Modernized filter_iterator.hpp.

Use EBO to minimize wasted storage space if the predicate is an empty class.

Disable default constructing non-class predicates using SFINAE instead
of a static_assert. This will help type traits like is_constructible,
when applied to the iterator type.
This commit is contained in:
Andrey Semashev
2025-02-05 04:22:35 +03:00
parent baf6d06cc2
commit dc57bcf319

View File

@@ -9,78 +9,105 @@
#include <type_traits> #include <type_traits>
#include <boost/core/use_default.hpp>
#include <boost/core/empty_value.hpp>
#include <boost/iterator/iterator_adaptor.hpp> #include <boost/iterator/iterator_adaptor.hpp>
#include <boost/iterator/iterator_categories.hpp> #include <boost/iterator/iterator_categories.hpp>
#include <boost/iterator/enable_if_convertible.hpp> #include <boost/iterator/enable_if_convertible.hpp>
#include <boost/core/use_default.hpp>
namespace boost { namespace boost {
namespace iterators { namespace iterators {
template <class Predicate, class Iterator> template< typename Predicate, typename Iterator >
class filter_iterator; class filter_iterator;
namespace detail namespace detail {
{
template <class Predicate, class Iterator> template< typename Predicate, typename Iterator >
struct filter_iterator_base using filter_iterator_base_t = iterator_adaptor<
{ filter_iterator< Predicate, Iterator >,
typedef iterator_adaptor< Iterator,
filter_iterator<Predicate, Iterator> use_default,
, Iterator typename std::conditional<
, use_default
, typename std::conditional<
std::is_convertible< std::is_convertible<
typename iterator_traversal<Iterator>::type iterator_traversal_t< Iterator >,
, random_access_traversal_tag random_access_traversal_tag
>::value >::value,
, bidirectional_traversal_tag bidirectional_traversal_tag,
, use_default use_default
>::type >::type
> type; >;
};
}
template <class Predicate, class Iterator> } // namespace detail
class filter_iterator
: public detail::filter_iterator_base<Predicate, Iterator>::type
{
typedef typename detail::filter_iterator_base<
Predicate, Iterator
>::type super_t;
template< typename Predicate, typename Iterator >
class filter_iterator :
public detail::filter_iterator_base_t< Predicate, Iterator >
{
friend class iterator_core_access; friend class iterator_core_access;
public: private:
filter_iterator() { } using super_t = detail::filter_iterator_base_t< Predicate, Iterator >;
filter_iterator(Predicate f, Iterator x, Iterator end_ = Iterator()) // Storage class to leverage EBO, when possible
: super_t(static_cast<Iterator&&>(x)), m_predicate(static_cast<Predicate&&>(f)), m_end(static_cast<Iterator&&>(end_)) struct storage :
private boost::empty_value< Predicate >
{
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
>
>
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(); }
};
public:
filter_iterator() = default;
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(); satisfy_predicate();
} }
filter_iterator(Iterator x, Iterator end_ = Iterator()) template< bool Requires = std::is_class< Predicate >::value, typename = typename std::enable_if< Requires >::type >
: super_t(static_cast<Iterator&&>(x)), m_predicate(), m_end(static_cast<Iterator&&>(end_)) filter_iterator(Iterator x, Iterator end = Iterator()) :
super_t(static_cast< Iterator&& >(x)), m_storage(static_cast< Iterator&& >(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<Predicate>::value, "Predicate must be a class.");
satisfy_predicate(); satisfy_predicate();
} }
template<class OtherIterator> template< typename OtherIterator, typename = enable_if_convertible_t< OtherIterator, Iterator > >
filter_iterator( filter_iterator(filter_iterator< Predicate, OtherIterator > const& t) :
filter_iterator<Predicate, OtherIterator> const& t super_t(t.base()), m_storage(t.m_storage.predicate(), m_storage.m_end)
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 {}
)
: super_t(t.base()), m_predicate(t.predicate()), m_end(t.end()) {}
Predicate predicate() const { return m_predicate; } Predicate predicate() const { return m_storage.predicate(); }
Iterator end() const { return m_storage.m_end; }
Iterator end() const { return m_end; } private:
private:
void increment() void increment()
{ {
++(this->base_reference()); ++(this->base_reference());
@@ -89,39 +116,33 @@ namespace iterators {
void decrement() void decrement()
{ {
while(!this->m_predicate(*--(this->base_reference()))){}; while (!m_storage.predicate()(*--(this->base_reference()))) {}
} }
void satisfy_predicate() void satisfy_predicate()
{ {
while (this->base() != this->m_end && !this->m_predicate(*this->base())) while (this->base() != m_storage.m_end && !m_storage.predicate()(*this->base()))
++(this->base_reference()); ++(this->base_reference());
} }
// Probably should be the initial base class so it can be private:
// optimized away via EBO if it is an empty class. storage m_storage;
Predicate m_predicate; };
Iterator m_end;
};
template <class Predicate, class Iterator> template< typename Predicate, typename Iterator >
inline filter_iterator<Predicate,Iterator> inline filter_iterator< Predicate, Iterator > make_filter_iterator(Predicate f, Iterator x, Iterator end = 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));
return filter_iterator<Predicate,Iterator>(static_cast<Predicate&&>(f), static_cast<Iterator&&>(x), static_cast<Iterator&&>(end)); }
}
template <class Predicate, class Iterator> template< typename Predicate, typename Iterator >
inline filter_iterator<Predicate,Iterator> inline typename std::enable_if<
make_filter_iterator( std::is_class< Predicate >::value,
typename std::enable_if< filter_iterator< Predicate, Iterator >
std::is_class<Predicate>::value >::type make_filter_iterator(Iterator x, Iterator end = Iterator())
, Iterator {
>::type x return filter_iterator< Predicate, Iterator >(static_cast< Iterator&& >(x), static_cast< Iterator&& >(end));
, Iterator end = Iterator()) }
{
return filter_iterator<Predicate,Iterator>(static_cast<Iterator&&>(x), static_cast<Iterator&&>(end));
}
} // namespace iterators } // namespace iterators