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,119 +9,140 @@
#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 >,
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< using predicate_base = boost::empty_value< Predicate >;
filter_iterator<Predicate, Iterator>
, Iterator Iterator m_end;
, use_default
, typename std::conditional< storage() = default;
std::is_convertible<
typename iterator_traversal<Iterator>::type template<
, random_access_traversal_tag typename Iter,
typename = typename std::enable_if<
!std::is_same<
typename std::remove_cv< typename std::remove_reference< Iter >::type >::type,
storage
>::value >::value
, bidirectional_traversal_tag >
, use_default >
>::type explicit storage(Iter&& end) :
> type; 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 Predicate, class Iterator> public:
class filter_iterator filter_iterator() = default;
: public detail::filter_iterator_base<Predicate, Iterator>::type
{
typedef typename detail::filter_iterator_base<
Predicate, Iterator
>::type super_t;
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: template< bool Requires = std::is_class< Predicate >::value, typename = typename std::enable_if< Requires >::type >
filter_iterator() { } 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()) template< typename OtherIterator, typename = enable_if_convertible_t< OtherIterator, Iterator > >
: super_t(static_cast<Iterator&&>(x)), m_predicate(static_cast<Predicate&&>(f)), m_end(static_cast<Iterator&&>(end_)) filter_iterator(filter_iterator< Predicate, OtherIterator > const& t) :
{ super_t(t.base()), m_storage(t.m_storage.predicate(), m_storage.m_end)
satisfy_predicate(); {}
}
filter_iterator(Iterator x, Iterator end_ = Iterator()) Predicate predicate() const { return m_storage.predicate(); }
: super_t(static_cast<Iterator&&>(x)), m_predicate(), m_end(static_cast<Iterator&&>(end_)) Iterator end() const { return m_storage.m_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();
}
template<class OtherIterator> private:
filter_iterator( void increment()
filter_iterator<Predicate, OtherIterator> const& t {
, typename enable_if_convertible<OtherIterator, Iterator>::type* = 0 ++(this->base_reference());
) satisfy_predicate();
: super_t(t.base()), m_predicate(t.predicate()), m_end(t.end()) {} }
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: private:
void increment() storage m_storage;
{ };
++(this->base_reference());
satisfy_predicate();
}
void decrement() template< typename Predicate, typename Iterator >
{ inline filter_iterator< Predicate, Iterator > make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator())
while(!this->m_predicate(*--(this->base_reference()))){}; {
} return filter_iterator< Predicate, Iterator >(static_cast< Predicate&& >(f), static_cast< Iterator&& >(x), static_cast< Iterator&& >(end));
}
void satisfy_predicate() template< typename Predicate, typename Iterator >
{ inline typename std::enable_if<
while (this->base() != this->m_end && !this->m_predicate(*this->base())) std::is_class< Predicate >::value,
++(this->base_reference()); filter_iterator< Predicate, Iterator >
} >::type make_filter_iterator(Iterator x, Iterator end = Iterator())
{
// Probably should be the initial base class so it can be return filter_iterator< Predicate, Iterator >(static_cast< Iterator&& >(x), static_cast< Iterator&& >(end));
// optimized away via EBO if it is an empty class. }
Predicate m_predicate;
Iterator m_end;
};
template <class Predicate, class 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));
}
template <class Predicate, class Iterator>
inline filter_iterator<Predicate,Iterator>
make_filter_iterator(
typename std::enable_if<
std::is_class<Predicate>::value
, Iterator
>::type x
, Iterator end = Iterator())
{
return filter_iterator<Predicate,Iterator>(static_cast<Iterator&&>(x), static_cast<Iterator&&>(end));
}
} // namespace iterators } // namespace iterators