From 81b520847cb62b8c4b9bc1776d879d8010d43cd6 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Fri, 15 Apr 2022 17:37:23 +1000 Subject: [PATCH] Introduce a flatten range adapter and use it in execute_keys_cmd This avoids allocating a KeyList vector in which to flatten all the different arguments and simplifies the client logic. --- src/commands.cc | 9 +--- src/ranges.cc | 27 ++++++---- src/ranges.hh | 132 ++++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 129 insertions(+), 39 deletions(-) diff --git a/src/commands.cc b/src/commands.cc index 2b419e76..3cfd8b73 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -2086,14 +2086,7 @@ const CommandDesc execute_keys_cmd = { ScopedSetBool disable_keymaps(context.keymaps_disabled(), not parser.get_switch("with-maps")); ScopedSetBool disable_hoooks(context.hooks_disabled(), not parser.get_switch("with-hooks")); - KeyList keys; - for (auto& param : parser) - { - KeyList param_keys = parse_keys(param); - keys.insert(keys.end(), param_keys.begin(), param_keys.end()); - } - - for (auto& key : keys) + for (auto& key : parser | transform(parse_keys) | flatten()) context.input_handler().handle_key(key); }); } diff --git a/src/ranges.cc b/src/ranges.cc index 11885ad1..4fe2a418 100644 --- a/src/ranges.cc +++ b/src/ranges.cc @@ -7,24 +7,29 @@ namespace Kakoune { UnitTest test_ranges{[] { - auto check_equal = [](auto&& container, ConstArrayView expected) { + using Strs = ConstArrayView; + auto check_equal = [](auto&& container, auto&& expected) { kak_assert(std::equal(container.begin(), container.end(), expected.begin(), expected.end())); }; - check_equal("a,b,c"_sv | split(','), {"a", "b", "c"}); - check_equal(",b,c"_sv | split(','), {"", "b", "c"}); - check_equal(",b,"_sv | split(','), {"", "b", ""}); - check_equal(","_sv | split(','), {"", ""}); - check_equal(""_sv | split(','), {}); + check_equal("a,b,c"_sv | split(','), Strs{"a", "b", "c"}); + check_equal(",b,c"_sv | split(','), Strs{"", "b", "c"}); + check_equal(",b,"_sv | split(','), Strs{"", "b", ""}); + check_equal(","_sv | split(','), Strs{"", ""}); + check_equal(""_sv | split(','), Strs{}); - check_equal("a,b,c,"_sv | split_after(','), {"a,", "b,", "c,"}); - check_equal("a,b,c"_sv | split_after(','), {"a,", "b,", "c"}); + check_equal("a,b,c,"_sv | split_after(','), Strs{"a,", "b,", "c,"}); + check_equal("a,b,c"_sv | split_after(','), Strs{"a,", "b,", "c"}); check_equal(R"(a\,,\,b,\,)"_sv | split(',', '\\') - | transform(unescape<',', '\\'>), {"a,", ",b", ","}); + | transform(unescape<',', '\\'>), Strs{"a,", ",b", ","}); check_equal(R"(\,\,)"_sv | split(',', '\\') - | transform(unescape<',', '\\'>), {",,"}); + | transform(unescape<',', '\\'>), Strs{",,"}); check_equal(R"(\\,\\,)"_sv | split(',', '\\') - | transform(unescape<',', '\\'>), {R"(\)", R"(\)", ""}); + | transform(unescape<',', '\\'>), Strs{R"(\)", R"(\)", ""}); + + check_equal(Array{{""_sv, "abc"_sv, ""_sv, "def"_sv, ""_sv}} | flatten(), "abcdef"_sv); + check_equal(Vector{"", ""} | flatten(), ""_sv); + check_equal(Vector{} | flatten(), ""_sv); }}; } diff --git a/src/ranges.hh b/src/ranges.hh index cf436880..a86b9e2b 100644 --- a/src/ranges.hh +++ b/src/ranges.hh @@ -24,13 +24,33 @@ decltype(auto) operator| (Range&& range, ViewFactory factory) } template -struct decay_range_impl { using type = std::remove_cvref_t; }; +struct DecayRangeImpl { using type = std::remove_cvref_t; }; template -struct decay_range_impl { using type = Range&; }; +struct DecayRangeImpl { using type = Range&; }; template -using decay_range = typename decay_range_impl::type; +using DecayRange = typename DecayRangeImpl::type; + +template +struct RangeHolderImpl { using type = std::remove_cvref_t; }; + +template +struct RangeHolderImpl { + struct type + { + Range* range{}; + + decltype(auto) begin() { return std::begin(*range); } + decltype(auto) end() { return std::end(*range); } + + type& operator=(Range& r) { range = &r; return *this; } + operator Range&() { return *range; } + }; +}; + +template +using RangeHolder = typename RangeHolderImpl::type; template struct ReverseView @@ -47,11 +67,11 @@ struct ReverseView Range m_range; }; -inline auto reverse() +constexpr auto reverse() { return ViewFactory{[](auto&& range) { using Range = decltype(range); - return ReverseView>{std::forward(range)}; + return ReverseView>{std::forward(range)}; }}; } @@ -71,11 +91,11 @@ struct SkipView size_t m_skip_count; }; -inline auto skip(size_t count) +constexpr auto skip(size_t count) { return ViewFactory{[count](auto&& range) { using Range = decltype(range); - return SkipView>{std::forward(range), count}; + return SkipView>{std::forward(range), count}; }}; } @@ -89,11 +109,11 @@ struct DropView size_t m_drop_count; }; -inline auto drop(size_t count) +constexpr auto drop(size_t count) { return ViewFactory{[count](auto&& range) { using Range = decltype(range); - return DropView>{std::forward(range), count}; + return DropView>{std::forward(range), count}; }}; } @@ -147,11 +167,11 @@ struct FilterView }; template -inline auto filter(Filter f) +constexpr auto filter(Filter f) { return ViewFactory{[f = std::move(f)](auto&& range) { using Range = decltype(range); - return FilterView, Filter>{std::forward(range), std::move(f)}; + return FilterView, Filter>{std::forward(range), std::move(f)}; }}; } @@ -193,11 +213,11 @@ struct EnumerateView Range m_range; }; -inline auto enumerate() +constexpr auto enumerate() { return ViewFactory{[](auto&& range) { using Range = decltype(range); - return EnumerateView>{std::forward(range)}; + return EnumerateView>{std::forward(range)}; }}; } @@ -252,11 +272,11 @@ struct TransformView }; template -inline auto transform(Transform t) +constexpr auto transform(Transform t) { return ViewFactory{[t = std::move(t)](auto&& range) { using Range = decltype(range); - return TransformView, Transform>{std::forward(range), std::move(t)}; + return TransformView, Transform>{std::forward(range), std::move(t)}; }}; } @@ -267,7 +287,7 @@ template requires std::is_same_v : std::true_type {}; template -inline auto transform(M T::*member) +constexpr auto transform(M T::*member) { return transform([member](auto&& arg) -> decltype(auto) { using Arg = decltype(arg); @@ -364,7 +384,7 @@ auto split(Element separator) { return ViewFactory{[s = std::move(separator)](auto&& range) { using Range = decltype(range); - return SplitView, false, false, Element, ValueType>{std::forward(range), std::move(s), {}}; + return SplitView, false, false, Element, ValueType>{std::forward(range), std::move(s), {}}; }}; } @@ -373,7 +393,7 @@ auto split_after(Element separator) { return ViewFactory{[s = std::move(separator)](auto&& range) { using Range = decltype(range); - return SplitView, false, true, Element, ValueType>{std::forward(range), std::move(s), {}}; + return SplitView, false, true, Element, ValueType>{std::forward(range), std::move(s), {}}; }}; } @@ -382,7 +402,79 @@ auto split(Element separator, Element escaper) { return ViewFactory{[s = std::move(separator), e = std::move(escaper)](auto&& range) { using Range = decltype(range); - return SplitView, true, false, Element, ValueType>{std::forward(range), std::move(s), std::move(e)}; + return SplitView, true, false, Element, ValueType>{std::forward(range), std::move(s), std::move(e)}; + }}; +} + +template +struct FlattenedView +{ + using OuterIt = IteratorOf; + using InnerRange = ValueOf; + using InnerIt = IteratorOf; + + struct Iterator + { + using value_type = typename std::iterator_traits::value_type; + using iterator_category = std::forward_iterator_tag; + using difference_type = std::size_t; + using reference = value_type&; + + Iterator() = default; + Iterator(OuterIt begin, OuterIt end) : m_outer_it{begin}, m_outer_end{end} + { + find_next_inner(); + } + + decltype(auto) operator*() { return *m_inner_it; } + + Iterator& operator++() + { + if (++m_inner_it == std::end(m_inner_range)) + { + ++m_outer_it; + find_next_inner(); + } + return *this; + } + Iterator operator++(int) { auto copy = *this; ++*this; return copy; } + + friend bool operator==(const Iterator& lhs, const Iterator& rhs) + { + return lhs.m_outer_it == rhs.m_outer_it and lhs.m_inner_it == rhs.m_inner_it; + } + + void find_next_inner() + { + m_inner_it = InnerIt{}; + for (; m_outer_it != m_outer_end; ++m_outer_it) + { + m_inner_range = *m_outer_it; + if (std::begin(m_inner_range) != std::end(m_inner_range)) + { + m_inner_it = std::begin(m_inner_range); + return; + } + } + } + + OuterIt m_outer_it{}; + OuterIt m_outer_end{}; + InnerIt m_inner_it{}; + RangeHolder m_inner_range; + }; + + Iterator begin() const { return {std::begin(m_range), std::end(m_range)}; } + Iterator end() const { return {std::end(m_range), std::end(m_range)}; } + + Range m_range; +}; + +constexpr auto flatten() +{ + return ViewFactory{[](auto&& range){ + using Range = decltype(range); + return FlattenedView>{std::forward(range)}; }}; } @@ -434,7 +526,7 @@ struct ConcatView }; template -ConcatView, decay_range> concatenated(Range1&& range1, Range2&& range2) +ConcatView, DecayRange> concatenated(Range1&& range1, Range2&& range2) { return {range1, range2}; }