diff --git a/src/ranked_match.cc b/src/ranked_match.cc index 91bd57d3..11c58045 100644 --- a/src/ranked_match.cc +++ b/src/ranked_match.cc @@ -6,6 +6,30 @@ namespace Kakoune { +UsedLetters used_letters(StringView str) +{ + UsedLetters res = 0; + for (auto c : str) + { + if (c >= 'a' and c <= 'z') + res |= 1uL << (c - 'a'); + else if (c >= 'A' and c <= 'Z') + res |= 1uL << (c - 'A' + 26); + else if (c == '_') + res |= 1uL << 53; + else if (c == '-') + res |= 1uL << 54; + else + res |= 1uL << 63; + } + return res; +} + +bool matches(UsedLetters query, UsedLetters letters) +{ + return (query & letters) == query; +} + using Utf8It = utf8::iterator; static int count_word_boundaries_match(StringView candidate, StringView query) @@ -68,26 +92,36 @@ static bool subsequence_match_smart_case(StringView str, StringView subseq, int& return true; } -RankedMatch::RankedMatch(StringView candidate, StringView query) +template +RankedMatch::RankedMatch(StringView candidate, StringView query, TestFunc func) { if (candidate.empty() or query.length() > candidate.length()) return; if (query.empty()) + m_candidate = candidate; + else if (func() and subsequence_match_smart_case(candidate, query, m_match_index_sum)) { m_candidate = candidate; - return; + + m_first_char_match = smartcase_eq(query[0], candidate[0]); + m_word_boundary_match_count = count_word_boundaries_match(candidate, query); + m_only_word_boundary = m_word_boundary_match_count == query.length(); + m_prefix = std::equal(query.begin(), query.end(), candidate.begin(), smartcase_eq); } +} - if (not subsequence_match_smart_case(candidate, query, m_match_index_sum)) - return; +RankedMatch::RankedMatch(StringView candidate, UsedLetters candidate_letters, + StringView query, UsedLetters query_letters) + : RankedMatch{candidate, query, [&] { + return matches(to_lower(query_letters), to_lower(candidate_letters)) and + matches(query_letters & upper_mask, candidate_letters & upper_mask); + }} {} - m_candidate = candidate; - m_first_char_match = smartcase_eq(query[0], candidate[0]); - m_word_boundary_match_count = count_word_boundaries_match(candidate, query); - m_only_word_boundary = m_word_boundary_match_count == query.length(); - m_prefix = std::equal(query.begin(), query.end(), candidate.begin(), smartcase_eq); +RankedMatch::RankedMatch(StringView candidate, StringView query) + : RankedMatch{candidate, query, [] { return true; }} +{ } bool RankedMatch::operator<(const RankedMatch& other) const @@ -131,4 +165,9 @@ UnitTest test_ranked_match{[] { kak_assert(count_word_boundaries_match("countWordBoundariesMatch", "cWBM") == 4); }}; +UnitTest test_used_letters{[]() +{ + kak_assert(used_letters("abcd") == to_lower(used_letters("abcdABCD"))); +}}; + } diff --git a/src/ranked_match.hh b/src/ranked_match.hh index de03fd4c..0e0e49c4 100644 --- a/src/ranked_match.hh +++ b/src/ranked_match.hh @@ -6,9 +6,21 @@ namespace Kakoune { +using UsedLetters = uint64_t; +UsedLetters used_letters(StringView str); + +constexpr UsedLetters upper_mask = 0xFFFFFFC000000; + +inline UsedLetters to_lower(UsedLetters letters) +{ + return ((letters & upper_mask) >> 26) | (letters & (~upper_mask)); +} + struct RankedMatch { RankedMatch(StringView candidate, StringView query); + RankedMatch(StringView candidate, UsedLetters candidate_letters, + StringView query, UsedLetters query_letters); const StringView& candidate() const { return m_candidate; } bool operator<(const RankedMatch& other) const; @@ -17,6 +29,9 @@ struct RankedMatch explicit operator bool() const { return not m_candidate.empty(); } private: + template + RankedMatch(StringView candidate, StringView query, TestFunc test); + StringView m_candidate; bool m_first_char_match = false; bool m_prefix = false; diff --git a/src/word_db.cc b/src/word_db.cc index ed54910a..65685a39 100644 --- a/src/word_db.cc +++ b/src/word_db.cc @@ -8,35 +8,8 @@ namespace Kakoune { -UsedLetters used_letters(StringView str) -{ - UsedLetters res; - for (auto c : str) - { - if (c >= 'a' and c <= 'z') - res.set(c - 'a'); - else if (c >= 'A' and c <= 'Z') - res.set(c - 'A' + 26); - else if (c == '_') - res.set(53); - else if (c == '-') - res.set(54); - else - res.set(63); - } - return res; -} - -constexpr UsedLetters upper_mask = 0xFFFFFFC000000; - -UsedLetters to_lower(UsedLetters letters) -{ - return ((letters & upper_mask) >> 26) | (letters & (~upper_mask)); -} - using WordList = Vector; - static WordList get_words(StringView content) { WordList res; @@ -155,11 +128,6 @@ int WordDB::get_word_occurences(StringView word) const RankedMatchList WordDB::find_matching(StringView query) { - auto matches = [](UsedLetters query, UsedLetters letters) - { - return (query & letters) == query; - }; - update_db(); const UsedLetters letters = used_letters(query); RankedMatchList res; @@ -171,12 +139,7 @@ RankedMatchList WordDB::find_matching(StringView query) continue; } - UsedLetters word_letters = word.second.letters; - if (not matches(to_lower(letters), to_lower(word_letters)) or - not matches(letters & upper_mask, word_letters & upper_mask)) - continue; - - if (RankedMatch match{word.first, query}) + if (RankedMatch match{word.first, word.second.letters, query, letters}) res.push_back(match); } @@ -219,9 +182,4 @@ UnitTest test_word_db{[]() kak_assert(eq(res, WordList{ "allo" COMMA "mutch" COMMA "retchou" COMMA "tchou" })); }}; -UnitTest test_used_letters{[]() -{ - kak_assert(used_letters("abcd") == to_lower(used_letters("abcdABCD"))); -}}; - } diff --git a/src/word_db.hh b/src/word_db.hh index a4644b5b..3dcf455d 100644 --- a/src/word_db.hh +++ b/src/word_db.hh @@ -7,14 +7,9 @@ #include "vector.hh" #include "ranked_match.hh" -#include - namespace Kakoune { -using UsedLetters = std::bitset<64>; -UsedLetters used_letters(StringView str); - using RankedMatchList = Vector; // maintain a database of words available in a buffer