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.
This commit is contained in:
Maxime Coste 2022-04-15 17:37:23 +10:00
parent 90db664635
commit 81b520847c
3 changed files with 129 additions and 39 deletions

View File

@ -2086,14 +2086,7 @@ const CommandDesc execute_keys_cmd = {
ScopedSetBool disable_keymaps(context.keymaps_disabled(), not parser.get_switch("with-maps")); ScopedSetBool disable_keymaps(context.keymaps_disabled(), not parser.get_switch("with-maps"));
ScopedSetBool disable_hoooks(context.hooks_disabled(), not parser.get_switch("with-hooks")); ScopedSetBool disable_hoooks(context.hooks_disabled(), not parser.get_switch("with-hooks"));
KeyList keys; for (auto& key : parser | transform(parse_keys) | flatten())
for (auto& param : parser)
{
KeyList param_keys = parse_keys(param);
keys.insert(keys.end(), param_keys.begin(), param_keys.end());
}
for (auto& key : keys)
context.input_handler().handle_key(key); context.input_handler().handle_key(key);
}); });
} }

View File

@ -7,24 +7,29 @@ namespace Kakoune
{ {
UnitTest test_ranges{[] { UnitTest test_ranges{[] {
auto check_equal = [](auto&& container, ConstArrayView<StringView> expected) { using Strs = ConstArrayView<StringView>;
auto check_equal = [](auto&& container, auto&& expected) {
kak_assert(std::equal(container.begin(), container.end(), expected.begin(), expected.end())); kak_assert(std::equal(container.begin(), container.end(), expected.begin(), expected.end()));
}; };
check_equal("a,b,c"_sv | split<StringView>(','), {"a", "b", "c"}); check_equal("a,b,c"_sv | split<StringView>(','), Strs{"a", "b", "c"});
check_equal(",b,c"_sv | split<StringView>(','), {"", "b", "c"}); check_equal(",b,c"_sv | split<StringView>(','), Strs{"", "b", "c"});
check_equal(",b,"_sv | split<StringView>(','), {"", "b", ""}); check_equal(",b,"_sv | split<StringView>(','), Strs{"", "b", ""});
check_equal(","_sv | split<StringView>(','), {"", ""}); check_equal(","_sv | split<StringView>(','), Strs{"", ""});
check_equal(""_sv | split<StringView>(','), {}); check_equal(""_sv | split<StringView>(','), Strs{});
check_equal("a,b,c,"_sv | split_after<StringView>(','), {"a,", "b,", "c,"}); check_equal("a,b,c,"_sv | split_after<StringView>(','), Strs{"a,", "b,", "c,"});
check_equal("a,b,c"_sv | split_after<StringView>(','), {"a,", "b,", "c"}); check_equal("a,b,c"_sv | split_after<StringView>(','), Strs{"a,", "b,", "c"});
check_equal(R"(a\,,\,b,\,)"_sv | split<StringView>(',', '\\') check_equal(R"(a\,,\,b,\,)"_sv | split<StringView>(',', '\\')
| transform(unescape<',', '\\'>), {"a,", ",b", ","}); | transform(unescape<',', '\\'>), Strs{"a,", ",b", ","});
check_equal(R"(\,\,)"_sv | split<StringView>(',', '\\') check_equal(R"(\,\,)"_sv | split<StringView>(',', '\\')
| transform(unescape<',', '\\'>), {",,"}); | transform(unescape<',', '\\'>), Strs{",,"});
check_equal(R"(\\,\\,)"_sv | split<StringView>(',', '\\') check_equal(R"(\\,\\,)"_sv | split<StringView>(',', '\\')
| 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<StringView>{"", ""} | flatten(), ""_sv);
check_equal(Vector<StringView>{} | flatten(), ""_sv);
}}; }};
} }

View File

@ -24,13 +24,33 @@ decltype(auto) operator| (Range&& range, ViewFactory<Func> factory)
} }
template<typename Range> template<typename Range>
struct decay_range_impl { using type = std::remove_cvref_t<Range>; }; struct DecayRangeImpl { using type = std::remove_cvref_t<Range>; };
template<typename Range> template<typename Range>
struct decay_range_impl<Range&> { using type = Range&; }; struct DecayRangeImpl<Range&> { using type = Range&; };
template<typename Range> template<typename Range>
using decay_range = typename decay_range_impl<Range>::type; using DecayRange = typename DecayRangeImpl<Range>::type;
template<typename Range>
struct RangeHolderImpl { using type = std::remove_cvref_t<Range>; };
template<typename Range>
struct RangeHolderImpl<Range&> {
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<typename Range>
using RangeHolder = typename RangeHolderImpl<Range>::type;
template<typename Range> template<typename Range>
struct ReverseView struct ReverseView
@ -47,11 +67,11 @@ struct ReverseView
Range m_range; Range m_range;
}; };
inline auto reverse() constexpr auto reverse()
{ {
return ViewFactory{[](auto&& range) { return ViewFactory{[](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return ReverseView<decay_range<Range>>{std::forward<Range>(range)}; return ReverseView<DecayRange<Range>>{std::forward<Range>(range)};
}}; }};
} }
@ -71,11 +91,11 @@ struct SkipView
size_t m_skip_count; size_t m_skip_count;
}; };
inline auto skip(size_t count) constexpr auto skip(size_t count)
{ {
return ViewFactory{[count](auto&& range) { return ViewFactory{[count](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return SkipView<decay_range<Range>>{std::forward<Range>(range), count}; return SkipView<DecayRange<Range>>{std::forward<Range>(range), count};
}}; }};
} }
@ -89,11 +109,11 @@ struct DropView
size_t m_drop_count; size_t m_drop_count;
}; };
inline auto drop(size_t count) constexpr auto drop(size_t count)
{ {
return ViewFactory{[count](auto&& range) { return ViewFactory{[count](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return DropView<decay_range<Range>>{std::forward<Range>(range), count}; return DropView<DecayRange<Range>>{std::forward<Range>(range), count};
}}; }};
} }
@ -147,11 +167,11 @@ struct FilterView
}; };
template<typename Filter> template<typename Filter>
inline auto filter(Filter f) constexpr auto filter(Filter f)
{ {
return ViewFactory{[f = std::move(f)](auto&& range) { return ViewFactory{[f = std::move(f)](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return FilterView<decay_range<Range>, Filter>{std::forward<Range>(range), std::move(f)}; return FilterView<DecayRange<Range>, Filter>{std::forward<Range>(range), std::move(f)};
}}; }};
} }
@ -193,11 +213,11 @@ struct EnumerateView
Range m_range; Range m_range;
}; };
inline auto enumerate() constexpr auto enumerate()
{ {
return ViewFactory{[](auto&& range) { return ViewFactory{[](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return EnumerateView<decay_range<Range>>{std::forward<Range>(range)}; return EnumerateView<DecayRange<Range>>{std::forward<Range>(range)};
}}; }};
} }
@ -252,11 +272,11 @@ struct TransformView
}; };
template<typename Transform> template<typename Transform>
inline auto transform(Transform t) constexpr auto transform(Transform t)
{ {
return ViewFactory{[t = std::move(t)](auto&& range) { return ViewFactory{[t = std::move(t)](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return TransformView<decay_range<Range>, Transform>{std::forward<Range>(range), std::move(t)}; return TransformView<DecayRange<Range>, Transform>{std::forward<Range>(range), std::move(t)};
}}; }};
} }
@ -267,7 +287,7 @@ template<typename T, typename U> requires std::is_same_v<std::remove_cvref_t<dec
struct is_pointer_like<T, U> : std::true_type {}; struct is_pointer_like<T, U> : std::true_type {};
template<typename M, typename T> template<typename M, typename T>
inline auto transform(M T::*member) constexpr auto transform(M T::*member)
{ {
return transform([member](auto&& arg) -> decltype(auto) { return transform([member](auto&& arg) -> decltype(auto) {
using Arg = decltype(arg); using Arg = decltype(arg);
@ -364,7 +384,7 @@ auto split(Element separator)
{ {
return ViewFactory{[s = std::move(separator)](auto&& range) { return ViewFactory{[s = std::move(separator)](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return SplitView<decay_range<Range>, false, false, Element, ValueType>{std::forward<Range>(range), std::move(s), {}}; return SplitView<DecayRange<Range>, false, false, Element, ValueType>{std::forward<Range>(range), std::move(s), {}};
}}; }};
} }
@ -373,7 +393,7 @@ auto split_after(Element separator)
{ {
return ViewFactory{[s = std::move(separator)](auto&& range) { return ViewFactory{[s = std::move(separator)](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return SplitView<decay_range<Range>, false, true, Element, ValueType>{std::forward<Range>(range), std::move(s), {}}; return SplitView<DecayRange<Range>, false, true, Element, ValueType>{std::forward<Range>(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) { return ViewFactory{[s = std::move(separator), e = std::move(escaper)](auto&& range) {
using Range = decltype(range); using Range = decltype(range);
return SplitView<decay_range<Range>, true, false, Element, ValueType>{std::forward<Range>(range), std::move(s), std::move(e)}; return SplitView<DecayRange<Range>, true, false, Element, ValueType>{std::forward<Range>(range), std::move(s), std::move(e)};
}};
}
template<typename Range>
struct FlattenedView
{
using OuterIt = IteratorOf<Range>;
using InnerRange = ValueOf<Range>;
using InnerIt = IteratorOf<InnerRange>;
struct Iterator
{
using value_type = typename std::iterator_traits<InnerIt>::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<InnerRange> 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<DecayRange<Range>>{std::forward<Range>(range)};
}}; }};
} }
@ -434,7 +526,7 @@ struct ConcatView
}; };
template<typename Range1, typename Range2> template<typename Range1, typename Range2>
ConcatView<decay_range<Range1>, decay_range<Range2>> concatenated(Range1&& range1, Range2&& range2) ConcatView<DecayRange<Range1>, DecayRange<Range2>> concatenated(Range1&& range1, Range2&& range2)
{ {
return {range1, range2}; return {range1, range2};
} }