From e207bd30d4007c9031bd639f8232adc8dc4dce25 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sun, 15 Apr 2018 13:20:13 +1000 Subject: [PATCH] Extract a for_n_best algorithm from completion function Provide the heap based n-best algorithm through a nice interface. --- src/commands.cc | 18 ++++++++---------- src/insert_completer.cc | 37 +++++++++++++++++-------------------- src/ranges.hh | 14 ++++++++++++++ 3 files changed, 39 insertions(+), 30 deletions(-) diff --git a/src/commands.cc b/src/commands.cc index 7f7b8708..49381975 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -993,17 +993,15 @@ void define_command(const ParametersParser& parser, Context& context, const Shel } constexpr size_t max_count = 100; - // Gather best max_count matches - auto greater = [](auto& lhs, auto& rhs) { return rhs < lhs; }; - auto first = matches.begin(), last = matches.end(); - std::make_heap(first, last, greater); CandidateList res; - while (res.size() < max_count and first != last) - { - if (res.empty() or res.back() != first->candidate()) - res.push_back(first->candidate().str()); - std::pop_heap(first, last--, greater); - } + // Gather best max_count matches + for_n_best(matches, max_count, [](auto& lhs, auto& rhs) { return rhs < lhs; }, + [&] (RankedMatch& m) { + if (not res.empty() and res.back() == m.candidate()) + return false; + res.push_back(m.candidate().str()); + return true; + }); return Completions{ 0_byte, pos_in_token, std::move(res) }; }; diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 1785648c..225ac5c9 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -177,30 +177,27 @@ InsertCompletion complete_word(const SelectionList& sels, constexpr size_t max_count = 100; // Gather best max_count matches - auto greater = [](auto& lhs, auto& rhs) { return rhs < lhs; }; - auto first = matches.begin(), last = matches.end(); - std::make_heap(first, last, greater); InsertCompletion::CandidateList candidates; candidates.reserve(std::min(matches.size(), max_count)); - while (candidates.size() < max_count and first != last) - { - if (candidates.empty() or candidates.back().completion != first->candidate()) - { - DisplayLine menu_entry; - if (other_buffers && first->buffer) - { - const auto pad_len = longest + 1 - first->candidate().char_length(); - menu_entry.push_back(first->candidate().str()); - menu_entry.push_back(String{' ', pad_len}); - menu_entry.push_back({ first->buffer->display_name(), faces["MenuInfo"] }); - } - else - menu_entry.push_back(first->candidate().str()); - candidates.push_back({first->candidate().str(), "", std::move(menu_entry)}); + for_n_best(matches, max_count, [](auto& lhs, auto& rhs) { return rhs < lhs; }, + [&](RankedMatchAndBuffer& m) { + if (not candidates.empty() and candidates.back().completion == m.candidate()) + return false; + DisplayLine menu_entry; + if (other_buffers && m.buffer) + { + const auto pad_len = longest + 1 - m.candidate().char_length(); + menu_entry.push_back(m.candidate().str()); + menu_entry.push_back(String{' ', pad_len}); + menu_entry.push_back({ m.buffer->display_name(), faces["MenuInfo"] }); } - std::pop_heap(first, last--, greater); - } + else + menu_entry.push_back(m.candidate().str()); + + candidates.push_back({m.candidate().str(), "", std::move(menu_entry)}); + return true; + }); return { std::move(candidates), word_begin, cursor_pos, buffer.timestamp() }; } diff --git a/src/ranges.hh b/src/ranges.hh index a8dc4487..1da0fe71 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -364,6 +364,20 @@ Init accumulate(Range&& c, Init&& init, BinOp&& op) return std::accumulate(begin(c), end(c), init, op); } +template +void for_n_best(Range&& c, size_t count, Compare&& compare, Func&& func) +{ + using std::begin; using std::end; + auto b = begin(c), e = end(c); + std::make_heap(b, e, compare); + while (count > 0 and b != e) + { + if (func(*b)) + --count; + std::pop_heap(b, e--, compare); + } +} + template auto gather() {