diff --git a/include/boost/iterator/filter_iterator.hpp b/include/boost/iterator/filter_iterator.hpp index 2ec6d79..29d8176 100644 --- a/include/boost/iterator/filter_iterator.hpp +++ b/include/boost/iterator/filter_iterator.hpp @@ -9,119 +9,140 @@ #include +#include +#include #include #include #include -#include namespace boost { namespace iterators { - template - class filter_iterator; +template< typename Predicate, typename Iterator > +class filter_iterator; - namespace detail - { - template - struct filter_iterator_base +namespace detail { + +template< typename Predicate, typename Iterator > +using filter_iterator_base_t = iterator_adaptor< + filter_iterator< Predicate, Iterator >, + Iterator, + use_default, + typename std::conditional< + std::is_convertible< + iterator_traversal_t< Iterator >, + random_access_traversal_tag + >::value, + bidirectional_traversal_tag, + use_default + >::type +>; + +} // namespace detail + +template< typename Predicate, typename Iterator > +class filter_iterator : + public detail::filter_iterator_base_t< Predicate, Iterator > +{ + friend class iterator_core_access; + +private: + using super_t = detail::filter_iterator_base_t< Predicate, Iterator >; + + // Storage class to leverage EBO, when possible + struct storage : + private boost::empty_value< Predicate > { - typedef iterator_adaptor< - filter_iterator - , Iterator - , use_default - , typename std::conditional< - std::is_convertible< - typename iterator_traversal::type - , random_access_traversal_tag + using predicate_base = boost::empty_value< Predicate >; + + Iterator m_end; + + storage() = default; + + template< + typename Iter, + typename = typename std::enable_if< + !std::is_same< + typename std::remove_cv< typename std::remove_reference< Iter >::type >::type, + storage >::value - , bidirectional_traversal_tag - , use_default - >::type - > type; + > + > + explicit storage(Iter&& end) : + predicate_base(boost::empty_init_t{}), m_end(static_cast< Iterator&& >(end)) + { + } + + template< typename Pred, typename Iter > + storage(Pred&& pred, Iter&& end) : + predicate_base(boost::empty_init_t{}, static_cast< Predicate&& >(pred)), m_end(static_cast< Iterator&& >(end)) + { + } + + Predicate& predicate() noexcept { return predicate_base::get(); } + Predicate const& predicate() const noexcept { return predicate_base::get(); } }; - } - template - class filter_iterator - : public detail::filter_iterator_base::type - { - typedef typename detail::filter_iterator_base< - Predicate, Iterator - >::type super_t; +public: + filter_iterator() = default; - friend class iterator_core_access; + filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()) : + super_t(static_cast< Iterator&& >(x)), m_storage(static_cast< Predicate&& >(f), static_cast< Iterator&& >(end)) + { + satisfy_predicate(); + } - public: - filter_iterator() { } + template< bool Requires = std::is_class< Predicate >::value, typename = typename std::enable_if< Requires >::type > + filter_iterator(Iterator x, Iterator end = Iterator()) : + super_t(static_cast< Iterator&& >(x)), m_storage(static_cast< Iterator&& >(end)) + { + satisfy_predicate(); + } - filter_iterator(Predicate f, Iterator x, Iterator end_ = Iterator()) - : super_t(static_cast(x)), m_predicate(static_cast(f)), m_end(static_cast(end_)) - { - satisfy_predicate(); - } + template< typename OtherIterator, typename = enable_if_convertible_t< OtherIterator, Iterator > > + filter_iterator(filter_iterator< Predicate, OtherIterator > const& t) : + super_t(t.base()), m_storage(t.m_storage.predicate(), m_storage.m_end) + {} - filter_iterator(Iterator x, Iterator end_ = Iterator()) - : super_t(static_cast(x)), m_predicate(), m_end(static_cast(end_)) - { - // Don't allow use of this constructor if Predicate is a - // function pointer type, since it will be 0. - static_assert(std::is_class::value, "Predicate must be a class."); - satisfy_predicate(); - } + Predicate predicate() const { return m_storage.predicate(); } + Iterator end() const { return m_storage.m_end; } - template - filter_iterator( - filter_iterator const& t - , typename enable_if_convertible::type* = 0 - ) - : super_t(t.base()), m_predicate(t.predicate()), m_end(t.end()) {} +private: + void increment() + { + ++(this->base_reference()); + satisfy_predicate(); + } - Predicate predicate() const { return m_predicate; } + void decrement() + { + while (!m_storage.predicate()(*--(this->base_reference()))) {} + } - Iterator end() const { return m_end; } + void satisfy_predicate() + { + while (this->base() != m_storage.m_end && !m_storage.predicate()(*this->base())) + ++(this->base_reference()); + } - private: - void increment() - { - ++(this->base_reference()); - satisfy_predicate(); - } +private: + storage m_storage; +}; - void decrement() - { - while(!this->m_predicate(*--(this->base_reference()))){}; - } +template< typename Predicate, typename Iterator > +inline filter_iterator< Predicate, Iterator > make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()) +{ + return filter_iterator< Predicate, Iterator >(static_cast< Predicate&& >(f), static_cast< Iterator&& >(x), static_cast< Iterator&& >(end)); +} - void satisfy_predicate() - { - while (this->base() != this->m_end && !this->m_predicate(*this->base())) - ++(this->base_reference()); - } - - // Probably should be the initial base class so it can be - // optimized away via EBO if it is an empty class. - Predicate m_predicate; - Iterator m_end; - }; - - template - inline filter_iterator - make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()) - { - return filter_iterator(static_cast(f), static_cast(x), static_cast(end)); - } - - template - inline filter_iterator - make_filter_iterator( - typename std::enable_if< - std::is_class::value - , Iterator - >::type x - , Iterator end = Iterator()) - { - return filter_iterator(static_cast(x), static_cast(end)); - } +template< typename Predicate, typename Iterator > +inline typename std::enable_if< + std::is_class< Predicate >::value, + filter_iterator< Predicate, Iterator > +>::type make_filter_iterator(Iterator x, Iterator end = Iterator()) +{ + return filter_iterator< Predicate, Iterator >(static_cast< Iterator&& >(x), static_cast< Iterator&& >(end)); +} } // namespace iterators