From 6141b83c5e3ad77431dd64b26a28da9c760754f2 Mon Sep 17 00:00:00 2001 From: Dave Abrahams Date: Sun, 12 Jan 2003 06:14:18 +0000 Subject: [PATCH] filter_iterator [SVN r850] --- include/boost/iterator/iterator_adaptors.hpp | 100 ++++++++++++++++++- test/Jamfile | 1 + test/filter_iterator_test.cpp | 81 +++++++++++++++ 3 files changed, 178 insertions(+), 4 deletions(-) create mode 100644 test/filter_iterator_test.cpp diff --git a/include/boost/iterator/iterator_adaptors.hpp b/include/boost/iterator/iterator_adaptors.hpp index e549a05..7e14645 100644 --- a/include/boost/iterator/iterator_adaptors.hpp +++ b/include/boost/iterator/iterator_adaptors.hpp @@ -693,6 +693,12 @@ namespace boost { } }; + template + reverse_iterator make_reverse_iterator(BidirectionalIterator x) + { + return reverse_iterator(x); + } + // // TODO fix category // @@ -734,6 +740,8 @@ namespace boost { private: typename super_t::value_type dereference() const { return m_f(super_t::dereference()); } + // Probably should be the initial base class so it can be + // optimized away via EBO if it is an empty class. AdaptableUnaryFunction m_f; }; @@ -744,7 +752,7 @@ namespace boost { // // Detection for whether a type has a nested `element_type' // typedef. Used to detect smart pointers. For compilers not - // supporting mpl's has_xxx, we supply specialzations. However, we + // supporting mpl's has_xxx, we supply specializations. However, we // really ought to have a specializable is_pointer template which // can be used instead with something like // boost/python/pointee.hpp to find the value_type. @@ -849,9 +857,9 @@ namespace boost { , typename enable_if_convertible::type* = 0 # endif ) - - : super_t(y.base()) {} - + : super_t(y.base()) + {} + private: typename super_t::reference dereference() const { return **this->base(); } @@ -871,6 +879,90 @@ namespace boost { return indirect_iterator(x); } + template + struct filter_iterator_traits + : detail::iterator_traits + { + typedef iterator_tag< + typename return_category::type + , forward_traversal_tag + > iterator_category; + }; + + template + class filter_iterator + : public iterator_adaptor< + filter_iterator, Iterator, + typename filter_iterator_traits::value_type, + typename filter_iterator_traits::reference, + typename filter_iterator_traits::pointer, + typename filter_iterator_traits::iterator_category, + typename filter_iterator_traits::difference_type + > + { + typedef iterator_adaptor< + filter_iterator, Iterator, + typename filter_iterator_traits::value_type, + typename filter_iterator_traits::reference, + typename filter_iterator_traits::pointer, + typename filter_iterator_traits::iterator_category, + typename filter_iterator_traits::difference_type > super_t; + + friend class iterator_core_access; + + public: + filter_iterator() { } + + filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()) + : super_t(x), m_predicate(f), m_end(end) + { + satisfy_predicate(); + } + + filter_iterator(Iterator x, Iterator end = Iterator()) + : super_t(x), m_predicate(), m_end(end) + { + satisfy_predicate(); + } + + template + filter_iterator( + filter_iterator const& t + # ifndef BOOST_NO_ENABLE_IF_CONSTRUCTORS + , typename enable_if_convertible::type* = 0 + # endif + ) + : super_t(t.base()), m_predicate(t.predicate()), m_end(t.end()) {} + + Predicate predicate() const { return m_predicate; } + + Iterator end() const { return m_end; } + + private: + void increment() + { + super_t::increment(); + satisfy_predicate(); + } + + void satisfy_predicate() + { + while (this->base() != this->m_end && !this->m_predicate(*this->base())) + super_t::increment(); + } + + // 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 + filter_iterator + make_filter_iterator(Predicate f, Iterator x, Iterator end = Iterator()) + { + return filter_iterator(f,x,end); + } } // namespace boost // diff --git a/test/Jamfile b/test/Jamfile index 120db87..6c0b480 100644 --- a/test/Jamfile +++ b/test/Jamfile @@ -4,5 +4,6 @@ run concept_tests.cpp ; run iterator_adaptor_cc.cpp ; run transform_iterator_test.cpp ; run indirect_iterator_test.cpp ; +run filter_iterator_test.cpp ; compile-fail interoperable_fail.cpp ; compile-fail is_convertible_fail.cpp ; \ No newline at end of file diff --git a/test/filter_iterator_test.cpp b/test/filter_iterator_test.cpp new file mode 100644 index 0000000..8eb0082 --- /dev/null +++ b/test/filter_iterator_test.cpp @@ -0,0 +1,81 @@ +// Copyright David Abrahams 2003. Permission to copy, use, +// modify, sell and distribute this software is granted provided this +// copyright notice appears in all copies. This software is provided +// "as is" without express or implied warranty, and with no claim as +// to its suitability for any purpose. + +#include +#include + +#include +#include + +using boost::dummyT; + +struct one_or_four { + bool operator()(dummyT x) const { + return x.foo() == 1 || x.foo() == 4; + } +}; + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { namespace detail +{ + template<> struct iterator_traits + : ptr_iter_traits {}; +}} +#endif + + +// Test filter iterator +int main() +{ + dummyT array[] = { dummyT(0), dummyT(1), dummyT(2), + dummyT(3), dummyT(4), dummyT(5) }; + const int N = sizeof(array)/sizeof(dummyT); + + typedef boost::filter_iterator filter_iter; + + boost::forward_iterator_test( + filter_iter(one_or_four(), array, array+N) + , dummyT(1), dummyT(4)); + +# if 0 + BOOST_STATIC_ASSERT( + (!boost::detail::is_bidirectional_traversal_iterator< + boost::traversal_category::type + >::value) ); +# endif + + // On compilers not supporting partial specialization, we can do more type + // deduction with deque iterators than with pointers... unless the library + // is broken ;-( + std::deque array2; + std::copy(array+0, array+N, std::back_inserter(array2)); + boost::forward_iterator_test( + boost::make_filter_iterator(one_or_four(), array2.begin(), array2.end()), + dummyT(1), dummyT(4)); + + boost::forward_iterator_test( + boost::make_filter_iterator(one_or_four(), array2.begin(), array2.end()), + dummyT(1), dummyT(4)); + + boost::forward_iterator_test( + boost::make_filter_iterator( + one_or_four() + , boost::make_reverse_iterator(array2.end()) + , boost::make_reverse_iterator(array2.begin()) + ), + dummyT(4), dummyT(1)); + + boost::forward_iterator_test( + filter_iter(array+0, array+N), + dummyT(1), dummyT(4)); + + boost::forward_iterator_test( + filter_iter(one_or_four(), array, array + N), + dummyT(1), dummyT(4)); + + std::cout << "test successful " << std::endl; + return 0; +}