#pragma once #include /// Similar to boost::filtered_range but a little bit easier and allows to convert ordinary iterators to filtered template struct RangeFiltered { using RawIterator = typename C:: iterator; class Iterator; /// Will iterate over elements for which filter(*it) == true RangeFiltered(F && filter, C & container) : filter(std::move(filter)), container(container) {} Iterator begin() const { return {*this, std::begin(container)}; } Iterator end() const { return {*this, std::end(container)}; } /// Convert ordinary iterator to filtered one /// Real position will be in range [ordinary_iterator; end()], so it is suitable to use with lower[upper]_bound() inline Iterator convert(RawIterator ordinary_iterator) const { return {*this, ordinary_iterator}; } /// It is similar to boost::filtered_iterator, but has additional features: /// it doesn't store end() iterator /// it doesn't store predicate, so it allows to implement operator=() /// it guarantees that operator++() works properly in case of filter(*it) == false class Iterator { public: using Range = RangeFiltered; typedef Iterator self_type; typedef typename std::iterator_traits::value_type value_type; typedef typename std::iterator_traits::reference reference; typedef const value_type & const_reference; typedef typename std::iterator_traits::pointer pointer; typedef const value_type * const_pointer; typedef typename std::iterator_traits::difference_type difference_type; typedef std::bidirectional_iterator_tag iterator_category; Iterator(const Range & range_, RawIterator iter_) : range(&range_), iter(iter_) { for (; iter != std::end(range->container) && !range->filter(*iter); ++iter); } Iterator(const Iterator & rhs) = default; Iterator(Iterator && rhs) noexcept = default; Iterator operator++() { ++iter; for (; iter != std::end(range->container) && !range->filter(*iter); ++iter); return *this; } Iterator operator--() { --iter; for (; !range->filter(*iter); --iter); /// Don't check std::begin() bound return *this; } pointer operator->() { return iter.operator->(); } const_pointer operator->() const { return iter.operator->(); } reference operator*() { return *iter; } const_reference operator*() const { return *iter; } bool operator==(const self_type & rhs) const { return iter == rhs.iter; } bool operator!=(const self_type & rhs) const { return iter != rhs.iter; } self_type & operator=(const self_type & rhs) = default; self_type & operator=(self_type && rhs) noexcept = default; ~Iterator() = default; private: const Range * range = nullptr; RawIterator iter; }; protected: F filter; C & container; }; template inline RangeFiltered, std::decay_t> createRangeFiltered(F && filter, C && container) { return {std::forward(filter), std::forward(container)}; };