#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