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:
parent
90db664635
commit
81b520847c
|
@ -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);
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}};
|
||||
|
||||
}
|
||||
|
|
132
src/ranges.hh
132
src/ranges.hh
|
@ -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};
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user