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_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);
});
}

View File

@ -7,24 +7,29 @@ namespace Kakoune
{
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()));
};
check_equal("a,b,c"_sv | split<StringView>(','), {"a", "b", "c"});
check_equal(",b,c"_sv | split<StringView>(','), {"", "b", "c"});
check_equal(",b,"_sv | split<StringView>(','), {"", "b", ""});
check_equal(","_sv | split<StringView>(','), {"", ""});
check_equal(""_sv | split<StringView>(','), {});
check_equal("a,b,c"_sv | split<StringView>(','), Strs{"a", "b", "c"});
check_equal(",b,c"_sv | split<StringView>(','), Strs{"", "b", "c"});
check_equal(",b,"_sv | split<StringView>(','), Strs{"", "b", ""});
check_equal(","_sv | split<StringView>(','), Strs{"", ""});
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>(','), {"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>(','), Strs{"a,", "b,", "c"});
check_equal(R"(a\,,\,b,\,)"_sv | split<StringView>(',', '\\')
| transform(unescape<',', '\\'>), {"a,", ",b", ","});
| transform(unescape<',', '\\'>), Strs{"a,", ",b", ","});
check_equal(R"(\,\,)"_sv | split<StringView>(',', '\\')
| transform(unescape<',', '\\'>), {",,"});
| transform(unescape<',', '\\'>), Strs{",,"});
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>
struct decay_range_impl { using type = std::remove_cvref_t<Range>; };
struct DecayRangeImpl { using type = std::remove_cvref_t<Range>; };
template<typename Range>
struct decay_range_impl<Range&> { using type = Range&; };
struct DecayRangeImpl<Range&> { using type = 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>
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<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;
};
inline auto skip(size_t count)
constexpr auto skip(size_t count)
{
return ViewFactory{[count](auto&& 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;
};
inline auto drop(size_t count)
constexpr auto drop(size_t count)
{
return ViewFactory{[count](auto&& 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>
inline auto filter(Filter f)
constexpr auto filter(Filter f)
{
return ViewFactory{[f = std::move(f)](auto&& 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;
};
inline auto enumerate()
constexpr auto enumerate()
{
return ViewFactory{[](auto&& 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>
inline auto transform(Transform t)
constexpr auto transform(Transform t)
{
return ViewFactory{[t = std::move(t)](auto&& 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 {};
template<typename M, typename T>
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<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) {
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) {
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>
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};
}