diff --git a/include/boost/iterator/iterator_adaptors.hpp b/include/boost/iterator/iterator_adaptors.hpp index deefa02..32f7cb1 100644 --- a/include/boost/iterator/iterator_adaptors.hpp +++ b/include/boost/iterator/iterator_adaptors.hpp @@ -18,7 +18,7 @@ template struct downcastable : Base { typedef typename Base::final final_t; - public: +public: final_t& downcast() { return static_cast(*this); } const final_t& downcast() const { return static_cast(*this); } }; @@ -207,6 +207,47 @@ struct reverse_iterator Base m_base; }; +template +struct transform_iterator + : iterator_adaptor< + transform_iterator, + typename AdaptableUnaryFunction::result_type, + typename AdaptableUnaryFunction::result_type, + typename AdaptableUnaryFunction::result_type*, + iterator_tag::type>, + typename detail::iterator_traits::difference_type + > +{ + typedef typename AdaptableUnaryFunction::result_type value_type; +private: + typedef iterator_adaptor< + transform_iterator, value_type, value_type, value_type*, + iterator_tag::type>, + typename detail::iterator_traits::difference_type + > super; + +public: + transform_iterator() { } + + transform_iterator(const Base& x, AdaptableUnaryFunction f) + : m_base(x), m_f(f) { } + + value_type dereference() const { return m_f(*m_base); } + + template + transform_iterator(const transform_iterator& y) + : m_base(y.m_base), m_f(y.m_f) { } + + Base& base() { return m_base; } + Base const& base() const { return m_base; } + +private: + Base m_base; + AdaptableUnaryFunction m_f; +}; + } // namespace boost diff --git a/include/boost/iterator/iterator_categories.hpp b/include/boost/iterator/iterator_categories.hpp index 62b1c31..dbfc0f9 100644 --- a/include/boost/iterator/iterator_categories.hpp +++ b/include/boost/iterator/iterator_categories.hpp @@ -4,6 +4,9 @@ // "as is" without express or implied warranty, and with no claim as // to its suitability for any purpose. +// TODO: +// Add separate category tag for operator[]. + #ifndef BOOST_ITERATOR_CATEGORIES_HPP #define BOOST_ITERATOR_CATEGORIES_HPP @@ -21,19 +24,22 @@ namespace boost { // Return Type Categories struct readable_iterator_tag { }; struct writable_iterator_tag { }; - struct swappable_iterator_tag { }; - struct mutable_lvalue_iterator_tag : - virtual public writable_iterator_tag, - virtual public readable_iterator_tag { }; + struct swappable_iterator_tag : + virtual public readable_iterator_tag, // Not sure about this change -JGS + virtual public writable_iterator_tag { }; struct constant_lvalue_iterator_tag : virtual public readable_iterator_tag { }; + struct mutable_lvalue_iterator_tag : + virtual public swappable_iterator_tag, + virtual public constant_lvalue_iterator_tag { }; // Traversal Categories struct input_traversal_tag { }; struct output_traversal_tag { }; - struct forward_traversal_tag { }; - struct bidirectional_traversal_tag : public forward_traversal_tag { }; - struct random_access_traversal_tag : public bidirectional_traversal_tag { }; + struct forward_traversal_tag : virtual public input_traversal_tag, + virtual public output_traversal_tag { }; + struct bidirectional_traversal_tag : virtual public forward_traversal_tag { }; + struct random_access_traversal_tag : virtual public bidirectional_traversal_tag { }; struct error_iterator_tag { }; diff --git a/include/boost/iterator/new_iterator_tests.hpp b/include/boost/iterator/new_iterator_tests.hpp new file mode 100644 index 0000000..0a60f10 --- /dev/null +++ b/include/boost/iterator/new_iterator_tests.hpp @@ -0,0 +1,427 @@ +#ifndef BOOST_NEW_ITERATOR_TESTS_HPP +# define BOOST_NEW_ITERATOR_TESTS_HPP + +// This is meant to be the beginnings of a comprehensive, generic +// test suite for STL concepts such as iterators and containers. +// +// Revision History: +// 28 Oct 2002 Started update for new iterator categories +// (Jeremy Siek) +// 28 Apr 2002 Fixed input iterator requirements. +// For a == b a++ == b++ is no longer required. +// See 24.1.1/3 for details. +// (Thomas Witt) +// 08 Feb 2001 Fixed bidirectional iterator test so that +// --i is no longer a precondition. +// (Jeremy Siek) +// 04 Feb 2001 Added lvalue test, corrected preconditions +// (David Abrahams) + +# include +# include +# include +# include +# include // for detail::dummy_constructor +#include +#include + +namespace boost { + +void is_readable(readable_iterator_tag) { } +void is_writable(writable_iterator_tag) { } +void is_swappable(swappable_iterator_tag) { } +void is_constant_lvalue(constant_lvalue_iterator_tag) { } +void is_mutable_lvalue(mutable_lvalue_iterator_tag) { } + +// Preconditions: *i == v +template +void readable_iterator_test(const Iterator i1, T v) +{ + Iterator i2(i1); // Copy Constructible + typedef typename detail::iterator_traits::reference ref_t; + ref_t r1 = *i1; + ref_t r2 = *i2; + T v1 = r1; + T v2 = r2; + assert(v1 == v); + assert(v2 == v); + is_readable(typename return_category::type()); +} + +template +void writable_iterator_test(Iterator i, T v) +{ + Iterator i2(i); // Copy Constructible + *i2 = v; + is_writable(typename return_category::type()); +} + +template +void swappable_iterator_test(Iterator i, Iterator j) +{ + Iterator i2(i), j2(j); + typename detail::iterator_traits::value_type bi = *i; bj = *j; + iter_swap(i2, j2); + typename detail::iterator_traits::value_type ai = *i; aj = *j; + assert(bi == aj && bj == ai); + is_swappable(typename return_category::type()); +} + +template +void constant_lvalue_iterator_test(Iterator i, T v1) +{ + Iterator i2(i); + typedef typename detail::iterator_traits::value_type value_type; + typedef typename detail::iterator_traits::reference reference; + BOOST_STATIC_ASSERT((is_same::value)); + const T& v2 = *i2; + assert(v1 == v2); + is_constant_lvalue(typename return_category::type()); +} + +template +void mutable_lvalue_iterator_test(Iterator i, T v1, T v2) +{ + Iterator i2(i); + typedef typename detail::iterator_traits::value_type value_type; + typedef typename detail::iterator_traits::reference reference; + BOOST_STATIC_ASSERT((is_same::value)); + T& v3 = *i2; + assert(v1 == v3); + *i = v2; + T& v4 = *i2; + assert(v2 == v4); + is_mutable_lvalue(typename return_category::type()); +} + +template +void forward_readable_iterator_test(Iterator i, Iterator j, T val1, T val2) +{ + Iterator i2; + Iterator i3(i); + i2 = i; + assert(i2 == i3); + assert(i != j); + assert(i2 != j); + readable_iterator_test(i, val1); + readable_iterator_test(i2, val1); + readable_iterator_test(i3, val1); + + assert(i == i2++); + assert(i != ++i3); + + readable_iterator_test(i2, val2); + readable_iterator_test(i3, val2); + + readable_iterator_test(i, val1); +} + +template +void forward_swappable_iterator_test(Iterator i, Iterator j, T val1, T val2) +{ + forward_readable_iterator_test(i, j, val1, val2); + Iterator i2 = i; + ++i2; + swappable_iterator_test(i, i2); +} + +// bidirectional +// Preconditions: *i == v1, *++i == v2 +template +void bidirectional_readable_iterator_test(Iterator i, T v1, T v2) +{ + Iterator j(i); + ++j; + forward_readable_iterator_test(i, j, v1, v2); + ++i; + + Iterator i1 = i, i2 = i; + + assert(i == i1--); + assert(i != --i2); + + readable_iterator_test(i, v2); + readable_iterator_test(i1, v1); + readable_iterator_test(i2, v1); + + --i; + assert(i == i1); + assert(i == i2); + ++i1; + ++i2; + + readable_iterator_test(i, v1); + readable_iterator_test(i1, v2); + readable_iterator_test(i2, v2); +} + + +// random access +// Preconditions: [i,i+N) is a valid range +template +void random_access_readable_iterator_test(Iterator i, int N, TrueVals vals) +{ + bidirectional_readable_iterator_test(i, vals[0], vals[1]); + const Iterator j = i; + int c; + + for (c = 0; c < N-1; ++c) { + assert(i == j + c); + assert(*i == vals[c]); + assert(*i == j[c]); + assert(*i == *(j + c)); + assert(*i == *(c + j)); + ++i; + assert(i > j); + assert(i >= j); + assert(j <= i); + assert(j < i); + } + + Iterator k = j + N - 1; + for (c = 0; c < N-1; ++c) { + assert(i == k - c); + assert(*i == vals[N - 1 - c]); + assert(*i == j[N - 1 - c]); + Iterator q = k - c; + assert(*i == *q); + assert(i > j); + assert(i >= j); + assert(j <= i); + assert(j < i); + --i; + } +} + + +#if 0 + +// Tests whether type Iterator satisfies the requirements for a +// TrivialIterator. +// Preconditions: i != j, *i == val +template +void trivial_iterator_test(const Iterator i, const Iterator j, T val) +{ + Iterator k; + assert(i == i); + assert(j == j); + assert(i != j); +#ifdef BOOST_NO_STD_ITERATOR_TRAITS + T v = *i; +#else + typename std::iterator_traits::value_type v = *i; +#endif + assert(v == val); +#if 0 + // hmm, this will give a warning for transform_iterator... perhaps + // this should be separated out into a stand-alone test since there + // are several situations where it can't be used, like for + // integer_range::iterator. + assert(v == i->foo()); +#endif + k = i; + assert(k == k); + assert(k == i); + assert(k != j); + assert(*k == val); +} + + +// Preconditions: i != j +template +void mutable_trivial_iterator_test(const Iterator i, const Iterator j, T val) +{ + *i = val; + trivial_iterator_test(i, j, val); +} + + + + + +template +void dereference_test(Iterator i, T v1, read_write_iterator_tag) +{ + *i = v1; +} + + +// Preconditions: *i == v1, *++i == v2 +template +void input_iterator_test(Iterator i, T v1, T v2) +{ + Iterator i1(i); + + assert(i == i1); + assert(!(i != i1)); + + // I can see no generic way to create an input iterator + // that is in the domain of== of i and != i. + // The following works for istream_iterator but is not + // guaranteed to work for arbitrary input iterators. + // + // Iterator i2; + // + // assert(i != i2); + // assert(!(i == i2)); + + assert(*i1 == v1); + assert(*i == v1); + + // we cannot test for equivalence of (void)++i & (void)i++ + // as i is only guaranteed to be single pass. + assert(*i++ == v1); + + i1 = i; + + assert(i == i1); + assert(!(i != i1)); + + assert(*i1 == v2); + assert(*i == v2); + + // i is dereferencable, so it must be incrementable. + ++i; + + // how to test for operator-> ? +} + +// how to test output iterator? + + +template struct lvalue_test +{ + template static void check(Iterator) + { +# ifndef BOOST_NO_STD_ITERATOR_TRAITS + typedef typename std::iterator_traits::reference reference; + typedef typename std::iterator_traits::value_type value_type; +# else + typedef typename Iterator::reference reference; + typedef typename Iterator::value_type value_type; +# endif + BOOST_STATIC_ASSERT(boost::is_reference::value); + BOOST_STATIC_ASSERT((boost::is_same::value + || boost::is_same::value + )); + } +}; + +# ifdef BOOST_NO_STD_ITERATOR_TRAITS +template <> struct lvalue_test { + template static void check(T) {} +}; +#endif + +template +void forward_iterator_test(Iterator i, T v1, T v2) +{ + input_iterator_test(i, v1, v2); + + Iterator i1 = i, i2 = i; + + assert(i == i1++); + assert(i != ++i2); + + trivial_iterator_test(i, i1, v1); + trivial_iterator_test(i, i2, v1); + + ++i; + assert(i == i1); + assert(i == i2); + ++i1; + ++i2; + + trivial_iterator_test(i, i1, v2); + trivial_iterator_test(i, i2, v2); + + // borland doesn't allow non-type template parameters +# if !defined(__BORLANDC__) || (__BORLANDC__ > 0x551) + lvalue_test<(boost::is_pointer::value)>::check(i); +#endif +} + +// Preconditions: *i == v1, *++i == v2 +template +void bidirectional_iterator_test(Iterator i, T v1, T v2) +{ + forward_iterator_test(i, v1, v2); + ++i; + + Iterator i1 = i, i2 = i; + + assert(i == i1--); + assert(i != --i2); + + trivial_iterator_test(i, i1, v2); + trivial_iterator_test(i, i2, v2); + + --i; + assert(i == i1); + assert(i == i2); + ++i1; + ++i2; + + trivial_iterator_test(i, i1, v1); + trivial_iterator_test(i, i2, v1); +} + +// mutable_bidirectional_iterator_test + +// Preconditions: [i,i+N) is a valid range +template +void random_access_iterator_test(Iterator i, int N, TrueVals vals) +{ + bidirectional_iterator_test(i, vals[0], vals[1]); + const Iterator j = i; + int c; + + for (c = 0; c < N-1; ++c) { + assert(i == j + c); + assert(*i == vals[c]); + assert(*i == j[c]); + assert(*i == *(j + c)); + assert(*i == *(c + j)); + ++i; + assert(i > j); + assert(i >= j); + assert(j <= i); + assert(j < i); + } + + Iterator k = j + N - 1; + for (c = 0; c < N-1; ++c) { + assert(i == k - c); + assert(*i == vals[N - 1 - c]); + assert(*i == j[N - 1 - c]); + Iterator q = k - c; + assert(*i == *q); + assert(i > j); + assert(i >= j); + assert(j <= i); + assert(j < i); + --i; + } +} + +// Precondition: i != j +template +void const_nonconst_iterator_test(Iterator i, ConstIterator j) +{ + assert(i != j); + assert(j != i); + + ConstIterator k(i); + assert(k == i); + assert(i == k); + + k = i; + assert(k == i); + assert(i == k); +} + +#endif + +} // namespace boost + +#endif // BOOST_NEW_ITERATOR_TESTS_HPP diff --git a/test/transform_iterator_test.cpp b/test/transform_iterator_test.cpp new file mode 100644 index 0000000..585c236 --- /dev/null +++ b/test/transform_iterator_test.cpp @@ -0,0 +1,58 @@ +// (C) Copyright Jeremy Siek 2002. 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. + +// Revision History +// 28 Oct 2002 Jeremy Siek +// Updated for new iterator adaptors. +// 08 Mar 2001 Jeremy Siek +// Moved test of transform iterator into its own file. It to +// to be in iterator_adaptor_test.cpp. + +#include +#include +#include +#include +#include +#include + +struct mult_functor { + typedef int result_type; + typedef int argument_type; + // Functors used with transform_iterator must be + // DefaultConstructible, as the transform_iterator must be + // DefaultConstructible to satisfy the requirements for + // TrivialIterator. + mult_functor() { } + mult_functor(int aa) : a(aa) { } + int operator()(int b) const { return a * b; } + int a; +}; + +int +main() +{ + const int N = 10; + + // Test transform_iterator + { + int x[N], y[N]; + for (int k = 0; k < N; ++k) + x[k] = k; + std::copy(x, x + N, y); + + for (int k2 = 0; k2 < N; ++k2) + x[k2] = x[k2] * 2; + + typedef boost::transform_iterator iter_t; + iter_t i(y, mult_functor(2)); + boost::input_iterator_test(i, x[0], x[1]); + boost::input_iterator_test(iter_t(&y[0], mult_functor(2)), x[0], x[1]); + + boost::random_access_readable_iterator_test(i, N, x); + } + std::cout << "test successful " << std::endl; + return 0; +}