diff --git a/src/buffer.cc b/src/buffer.cc index 57a243e94..71cae3de2 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -3,6 +3,7 @@ #include "assert.hh" #include "buffer_manager.hh" #include "client.hh" +#include "containers.hh" #include "context.hh" #include "file.hh" #include "interned_string.hh" diff --git a/src/commands.cc b/src/commands.cc index 80dd696e1..2364d83f5 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -7,6 +7,7 @@ #include "client_manager.hh" #include "command_manager.hh" #include "completion.hh" +#include "containers.hh" #include "context.hh" #include "debug.hh" #include "event_manager.hh" diff --git a/src/containers.hh b/src/containers.hh new file mode 100644 index 000000000..f4df5d457 --- /dev/null +++ b/src/containers.hh @@ -0,0 +1,172 @@ +#ifndef containers_hh_INCLUDED +#define containers_hh_INCLUDED + +#include +#include +#include + +namespace Kakoune +{ + +template +struct ReversedContainer +{ + using iterator = decltype(std::declval().rbegin()); + ReversedContainer(Container& container) : m_container(container) {} + + iterator begin() { return m_container.rbegin(); } + iterator end() { return m_container.rend(); } + +private: + Container& m_container; +}; + +template +ReversedContainer reversed(Container&& container) +{ + return ReversedContainer(container); +} + +template +struct FilteredIterator : std::iterator +{ + FilteredIterator(Filter filter, Iterator it, Iterator end) + : m_it(std::move(it)), m_end(std::move(end)), m_filter(std::move(filter)) + { + do_filter(); + } + + auto operator*() -> decltype(*std::declval()) { return *m_it; } + FilteredIterator& operator++() { ++m_it; do_filter(); return *this; } + FilteredIterator operator++(int) { auto copy = *this; ++(*this); return copy; } + + friend bool operator==(const FilteredIterator& lhs, const FilteredIterator& rhs) + { + return lhs.m_it == rhs.m_it; + } + + friend bool operator!=(const FilteredIterator& lhs, const FilteredIterator& rhs) + { + return not (lhs == rhs); + } + +private: + void do_filter() + { + while (m_it != m_end and not m_filter(*m_it)) + ++m_it; + } + + Iterator m_it; + Iterator m_end; + Filter m_filter; +}; + +template +struct FilteredContainer +{ + using iterator = FilteredIterator())), Filter>; + FilteredContainer(Container& container, Filter filter) + : m_container(container), m_filter(std::move(filter)) {} + + iterator begin() const { return iterator(m_filter, m_container.begin(), m_container.end()); } + iterator end() const { return iterator(m_filter, m_container.end(), m_container.end()); } + +private: + Container& m_container; + Filter m_filter; +}; + +template +FilteredContainer filtered(Container&& container, Filter filter) +{ + return FilteredContainer(container, std::move(filter)); +} + +template +struct TransformedIterator : std::iterator()(*std::declval()))>::type> +{ + TransformedIterator(Transform transform, Iterator it) + : m_it(std::move(it)), m_transform(std::move(transform)) {} + + auto operator*() -> decltype(std::declval()(*std::declval())) { return m_transform(*m_it); } + TransformedIterator& operator++() { ++m_it; return *this; } + TransformedIterator operator++(int) { auto copy = *this; ++m_it; return copy; } + + friend bool operator==(const TransformedIterator& lhs, const TransformedIterator& rhs) + { + return lhs.m_it == rhs.m_it; + } + + friend bool operator!=(const TransformedIterator& lhs, const TransformedIterator& rhs) + { + return not (lhs == rhs); + } + +private: + Iterator m_it; + Transform m_transform; +}; + + +template +struct TransformedContainer +{ + using iterator = TransformedIterator())), Transform>; + TransformedContainer(Container& container, Transform transform) + : m_container(container), m_transform(std::move(transform)) {} + + iterator begin() const { return iterator(m_transform, m_container.begin()); } + iterator end() const { return iterator(m_transform, m_container.end()); } + +private: + Container& m_container; + Transform m_transform; +}; + +template +TransformedContainer transformed(Container&& container, Transform transform) +{ + return TransformedContainer(container, std::move(transform)); +} + +// Todo: move that into the following functions once we can remove the decltype +// return type. +using std::begin; +using std::end; + +template +auto find(Container&& container, const T& value) -> decltype(begin(container)) +{ + return std::find(begin(container), end(container), value); +} + +template +auto find_if(Container&& container, T op) -> decltype(begin(container)) +{ + return std::find_if(begin(container), end(container), op); +} + +template +bool contains(Container&& container, const T& value) +{ + return find(container, value) != end(container); +} + +template +void unordered_erase(Container&& vec, U&& value) +{ + auto it = find(vec, std::forward(value)); + if (it != vec.end()) + { + using std::swap; + swap(vec.back(), *it); + vec.pop_back(); + } +} + +} + +#endif // containers_hh_INCLUDED diff --git a/src/event_manager.cc b/src/event_manager.cc index 26a57eab8..21cd63312 100644 --- a/src/event_manager.cc +++ b/src/event_manager.cc @@ -1,5 +1,7 @@ #include "event_manager.hh" +#include "containers.hh" + #include namespace Kakoune diff --git a/src/face_registry.cc b/src/face_registry.cc index 53e5867bd..d99937c6c 100644 --- a/src/face_registry.cc +++ b/src/face_registry.cc @@ -1,5 +1,6 @@ #include "face_registry.hh" +#include "containers.hh" #include "exception.hh" namespace Kakoune @@ -7,8 +8,8 @@ namespace Kakoune static Face parse_face(StringView facedesc) { - auto bg_it = std::find(facedesc.begin(), facedesc.end(), ','); - auto attr_it = std::find(facedesc.begin(), facedesc.end(), '+'); + auto bg_it = find(facedesc, ','); + auto attr_it = find(facedesc, '+'); if (bg_it != facedesc.end() and attr_it < bg_it) throw runtime_error("invalid face description, expected [,][+]"); Face res; diff --git a/src/highlighter_group.cc b/src/highlighter_group.cc index c796afbb3..200587081 100644 --- a/src/highlighter_group.cc +++ b/src/highlighter_group.cc @@ -1,5 +1,7 @@ #include "highlighter_group.hh" +#include "containers.hh" + namespace Kakoune { diff --git a/src/id_map.hh b/src/id_map.hh index 97d6f45e3..a15903c14 100644 --- a/src/id_map.hh +++ b/src/id_map.hh @@ -1,9 +1,9 @@ #ifndef id_map_hh_INCLUDED #define id_map_hh_INCLUDED +#include "containers.hh" #include "completion.hh" #include "string.hh" -#include "utils.hh" #include diff --git a/src/keys.cc b/src/keys.cc index a726a8c18..b10663eec 100644 --- a/src/keys.cc +++ b/src/keys.cc @@ -1,5 +1,8 @@ #include "keys.hh" +#include "containers.hh" +#include "exception.hh" +#include "string.hh" #include "utils.hh" #include "utf8_iterator.hh" diff --git a/src/line_modification.hh b/src/line_modification.hh index 3cd2d6695..6f825c193 100644 --- a/src/line_modification.hh +++ b/src/line_modification.hh @@ -4,6 +4,8 @@ #include "units.hh" #include "utils.hh" +#include + namespace Kakoune { diff --git a/src/main.cc b/src/main.cc index 885d73337..579eca358 100644 --- a/src/main.cc +++ b/src/main.cc @@ -5,6 +5,7 @@ #include "client_manager.hh" #include "command_manager.hh" #include "commands.hh" +#include "containers.hh" #include "context.hh" #include "debug.hh" #include "event_manager.hh" diff --git a/src/ncurses_ui.cc b/src/ncurses_ui.cc index b11f5a58e..0a7dbf38f 100644 --- a/src/ncurses_ui.cc +++ b/src/ncurses_ui.cc @@ -7,6 +7,7 @@ #include "utf8_iterator.hh" #include +#include #define NCURSES_OPAQUE 0 #define NCURSES_INTERNALS diff --git a/src/normal.cc b/src/normal.cc index e4b9c8d15..13f1fb7ce 100644 --- a/src/normal.cc +++ b/src/normal.cc @@ -5,6 +5,7 @@ #include "client_manager.hh" #include "command_manager.hh" #include "commands.hh" +#include "containers.hh" #include "context.hh" #include "debug.hh" #include "face_registry.hh" diff --git a/src/option_manager.hh b/src/option_manager.hh index 439a0c536..c8fb1d5fe 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -2,6 +2,7 @@ #define option_manager_hh_INCLUDED #include "completion.hh" +#include "containers.hh" #include "exception.hh" #include "flags.hh" #include "option_types.hh" diff --git a/src/register_manager.cc b/src/register_manager.cc index f3b6b06e3..f9d36ae34 100644 --- a/src/register_manager.cc +++ b/src/register_manager.cc @@ -2,7 +2,7 @@ #include "assert.hh" #include "id_map.hh" -#include "utils.hh" +#include "exception.hh" namespace Kakoune { diff --git a/src/string.cc b/src/string.cc index 152b90aa3..6a1fda557 100644 --- a/src/string.cc +++ b/src/string.cc @@ -1,7 +1,7 @@ #include "string.hh" #include "exception.hh" -#include "utils.hh" +#include "containers.hh" #include "utf8_iterator.hh" namespace Kakoune diff --git a/src/utils.hh b/src/utils.hh index c8e29f893..fbf39e100 100644 --- a/src/utils.hh +++ b/src/utils.hh @@ -2,11 +2,8 @@ #define utils_hh_INCLUDED #include "assert.hh" -#include "exception.hh" -#include #include -#include namespace Kakoune { @@ -59,70 +56,6 @@ private: template T* Singleton::ms_instance = nullptr; -// *** Containers helpers *** - -template -struct ReversedContainer -{ - ReversedContainer(Container& container) : container(container) {} - Container& container; - - decltype(container.rbegin()) begin() { return container.rbegin(); } - decltype(container.rend()) end() { return container.rend(); } -}; - -template -auto begin(ReversedContainer& c) -> decltype(c.begin()) -{ - return c.begin(); -} - -template -auto end(ReversedContainer& c) -> decltype(c.end()) -{ - return c.end(); -} - -template -ReversedContainer reversed(Container&& container) -{ - return ReversedContainer(container); -} - -// Todo: move that into the following functions once we can remove the decltype -// return type. -using std::begin; -using std::end; - -template -auto find(Container&& container, const T& value) -> decltype(begin(container)) -{ - return std::find(begin(container), end(container), value); -} - -template -auto find_if(Container&& container, T op) -> decltype(begin(container)) -{ - return std::find_if(begin(container), end(container), op); -} - -template -bool contains(Container&& container, const T& value) -{ - return find(container, value) != end(container); -} - -template -void unordered_erase(std::vector& vec, U&& value) -{ - auto it = find(vec, std::forward(value)); - if (it != vec.end()) - { - std::swap(vec.back(), *it); - vec.pop_back(); - } -} - template void skip_while(Iterator& it, const EndIterator& end, T condition) {