diff --git a/test/Jamfile b/test/Jamfile new file mode 100644 index 0000000..75d3d1f --- /dev/null +++ b/test/Jamfile @@ -0,0 +1,14 @@ +SEARCH on testing.jam = $(BOOST_BUILD_PATH) ; +include testing.jam ; +run unit_tests.cpp ; +run concept_tests.cpp ; +run iterator_adaptor_cc.cpp ; +run iterator_adaptor_test.cpp ; +compile iterator_archetype_cc.cpp ; +run transform_iterator_test.cpp ; +run indirect_iterator_test.cpp ; +run filter_iterator_test.cpp ; +run reverse_iterator_test.cpp ; +run counting_iterator_test.cpp ; +run is_convertible_fail.cpp ; # test changed to expected success, so that we catch compilation failures. +compile-fail interoperable_fail.cpp ; diff --git a/test/concept_tests.cpp b/test/concept_tests.cpp new file mode 100644 index 0000000..64d2c05 --- /dev/null +++ b/test/concept_tests.cpp @@ -0,0 +1,174 @@ +// (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. + +#include +#include +#include // remove +#include +#include "static_assert_same.hpp" // remove + +struct new_iterator + : public boost::iterator< boost::iterator_tag< + boost::writable_lvalue_iterator_tag + , boost::random_access_traversal_tag>, int> +{ + int& operator*() const { return *m_x; } + new_iterator& operator++() { return *this; } + new_iterator operator++(int) { return *this; } + new_iterator& operator--() { return *this; } + new_iterator operator--(int) { return *this; } + new_iterator& operator+=(std::ptrdiff_t) { return *this; } + new_iterator operator+(std::ptrdiff_t) { return *this; } + new_iterator& operator-=(std::ptrdiff_t) { return *this; } + std::ptrdiff_t operator-(const new_iterator&) const { return 0; } + new_iterator operator-(std::ptrdiff_t) const { return *this; } + bool operator==(const new_iterator&) const { return false; } + bool operator!=(const new_iterator&) const { return false; } + bool operator<(const new_iterator&) const { return false; } + int* m_x; +}; +new_iterator operator+(std::ptrdiff_t, new_iterator x) { return x; } + +struct old_iterator + : public boost::iterator +{ + int& operator*() const { return *m_x; } + old_iterator& operator++() { return *this; } + old_iterator operator++(int) { return *this; } + old_iterator& operator--() { return *this; } + old_iterator operator--(int) { return *this; } + old_iterator& operator+=(std::ptrdiff_t) { return *this; } + old_iterator operator+(std::ptrdiff_t) { return *this; } + old_iterator& operator-=(std::ptrdiff_t) { return *this; } + old_iterator operator-(std::ptrdiff_t) const { return *this; } + std::ptrdiff_t operator-(const old_iterator&) const { return 0; } + bool operator==(const old_iterator&) const { return false; } + bool operator!=(const old_iterator&) const { return false; } + bool operator<(const old_iterator&) const { return false; } + int* m_x; +}; +old_iterator operator+(std::ptrdiff_t, old_iterator x) { return x; } + +struct my_writable_lvalue_iterator_tag +{ + operator boost::writable_lvalue_iterator_tag() const; +}; + +struct my_single_pass_traversal_tag +{ + operator boost::single_pass_traversal_tag() const; +}; + +void test_tag_convertibility() +{ + // This set of tests is by no means complete. + + // Test that this is an input/output iterator +#if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407) + { + typedef boost::iterator_tag< + boost::writable_lvalue_iterator_tag + , boost::single_pass_traversal_tag + > tag; + + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + !boost::is_convertible::value + )); + } + + // Test that it's possible to build new sub-tags without + // derivation. Convertibility should be enough + { + typedef boost::iterator_tag< + my_writable_lvalue_iterator_tag + , my_single_pass_traversal_tag + > tag; + + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + !boost::is_convertible::value + )); + } + + // Test that a single-pass readable lvalue iterator is only an + // input iterator. Requires special case handling in + // categories.hpp + { + typedef boost::iterator_tag< + boost::readable_lvalue_iterator_tag + , boost::single_pass_traversal_tag + > tag; + BOOST_STATIC_ASSERT(( + boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + !boost::is_convertible::value + )); + BOOST_STATIC_ASSERT(( + !boost::is_convertible::value + )); + } +#endif +} + +int +main() +{ + test_tag_convertibility(); + + typedef boost::iterator_tag< boost::writable_lvalue_iterator_tag, boost::random_access_traversal_tag > tag; + + // BOOST_STATIC_ASSERT((boost::detail::is_random_access_iterator::value)); + int test = static_assert_same::value; + test = static_assert_same::value; + + // BOOST_STATIC_ASSERT((boost::detail::is_random_access_iterator::value)); + test = static_assert_same::value; + test = static_assert_same::value; + + typedef boost::traversal_category::type traversal_category; + + // BOOST_STATIC_ASSERT(boost::detail::has_traversal::value); + BOOST_STATIC_ASSERT(boost::detail::is_new_iterator_tag::value); + + + test = static_assert_same::value; + (void)test; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + boost::function_requires< + boost_concepts::WritableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessTraversalConcept >(); + + boost::function_requires< + boost_concepts::ReadableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessTraversalConcept >(); +#endif + + boost::function_requires< + boost_concepts::WritableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessTraversalConcept >(); + + boost::function_requires< + boost_concepts::WritableLvalueIteratorConcept >(); + boost::function_requires< + boost_concepts::RandomAccessTraversalConcept >(); + return 0; +} diff --git a/test/counting_iterator_test.cpp b/test/counting_iterator_test.cpp new file mode 100644 index 0000000..fbfe70b --- /dev/null +++ b/test/counting_iterator_test.cpp @@ -0,0 +1,295 @@ +// (C) Copyright David Abrahams 2001. 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. +// +// See http://www.boost.org for most recent version including documentation. +// +// Revision History +// 16 Feb 2001 Added a missing const. Made the tests run (somewhat) with +// plain MSVC again. (David Abrahams) +// 11 Feb 2001 #if 0'd out use of counting_iterator on non-numeric types in +// MSVC without STLport, so that the other tests may proceed +// (David Abrahams) +// 04 Feb 2001 Added use of iterator_tests.hpp (David Abrahams) +// 28 Jan 2001 Removed not_an_iterator detritus (David Abrahams) +// 24 Jan 2001 Initial revision (David Abrahams) + +#include + +#ifdef __BORLANDC__ // Borland mis-detects our custom iterators +# pragma warn -8091 // template argument ForwardIterator passed to '...' is a output iterator +# pragma warn -8071 // Conversion may lose significant digits (due to counting_iterator += n). +#endif + +#ifdef BOOST_MSVC +# pragma warning(disable:4786) // identifier truncated in debug info +#endif + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#ifndef __BORLANDC__ +# include +#endif +#include +#include +#include +#ifndef BOOST_NO_SLIST +# include +#endif + + +#ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS +template +struct signed_assert_nonnegative +{ + static void test(T x) { assert(x >= 0); } +}; + +template +struct unsigned_assert_nonnegative +{ + static void test(T x) {} +}; + +template +struct assert_nonnegative + : boost::mpl::if_c< + std::numeric_limits::is_signed + , signed_assert_nonnegative + , unsigned_assert_nonnegative + >::type +{ +}; +#endif + +// Special tests for RandomAccess CountingIterators. +template +void category_test( + CountingIterator start, + CountingIterator finish, + Value, + std::random_access_iterator_tag) +{ + typedef typename + boost::detail::iterator_traits::difference_type + difference_type; + difference_type distance = boost::detail::distance(start, finish); + + // Pick a random position internal to the range + difference_type offset = (unsigned)rand() % distance; + +#ifdef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS + assert(offset >= 0); +#else + assert_nonnegative::test(offset); +#endif + + CountingIterator internal = start; + std::advance(internal, offset); + + // Try some binary searches on the range to show that it's ordered + assert(std::binary_search(start, finish, *internal)); + + // #including tuple crashed borland, so I had to give up on tie(). + std::pair xy( + std::equal_range(start, finish, *internal)); + CountingIterator x = xy.first, y = xy.second; + + assert(boost::detail::distance(x, y) == 1); + + // Show that values outside the range can't be found + assert(!std::binary_search(start, boost::prior(finish), *finish)); + + // Do the generic random_access_iterator_test + typedef typename CountingIterator::value_type value_type; + std::vector v; + for (value_type z = *start; !(z == *finish); ++z) + v.push_back(z); + + // Note that this test requires a that the first argument is + // dereferenceable /and/ a valid iterator prior to the first argument + boost::random_access_iterator_test(start, v.size(), v.begin()); +} + +// Special tests for bidirectional CountingIterators +template +void category_test(CountingIterator start, Value v1, std::bidirectional_iterator_tag) +{ + Value v2 = v1; + ++v2; + + // Note that this test requires a that the first argument is + // dereferenceable /and/ a valid iterator prior to the first argument + boost::bidirectional_iterator_test(start, v1, v2); +} + +template +void category_test(CountingIterator start, CountingIterator finish, Value v1, std::forward_iterator_tag) +{ + Value v2 = v1; + ++v2; + if (finish != start && finish != boost::next(start)) + boost::forward_readable_iterator_test(start, finish, v1, v2); +} + +template +void test_aux(CountingIterator start, CountingIterator finish, Value v1) +{ + typedef typename CountingIterator::iterator_category category; + typedef typename CountingIterator::value_type value_type; + + // If it's a RandomAccessIterator we can do a few delicate tests + category_test(start, finish, v1, category()); + + // Okay, brute force... + for (CountingIterator p = start + ; p != finish && boost::next(p) != finish + ; ++p) + { + assert(boost::next(*p) == *boost::next(p)); + } + + // prove that a reference can be formed to these values + typedef typename CountingIterator::value_type value; + const value* q = &*start; + (void)q; // suppress unused variable warning +} + +template +void test(Incrementable start, Incrementable finish) +{ + test_aux(boost::make_counting_iterator(start), boost::make_counting_iterator(finish), start); +} + +template +void test_integer(Integer* = 0) // default arg works around MSVC bug +{ + Integer start = 0; + Integer finish = 120; + test(start, finish); +} + +template +void test_integer3(Integer* = 0, Category* = 0, Difference* = 0) // default arg works around MSVC bug +{ + Integer start = 0; + Integer finish = 120; + typedef boost::counting_iterator iterator; + test_aux(iterator(start), iterator(finish), start); +} + +template +void test_container(Container* = 0) // default arg works around MSVC bug +{ + Container c(1 + (unsigned)rand() % 1673); + + const typename Container::iterator start = c.begin(); + + // back off by 1 to leave room for dereferenceable value at the end + typename Container::iterator finish = start; + std::advance(finish, c.size() - 1); + + test(start, finish); + + typedef typename Container::const_iterator const_iterator; + test(const_iterator(start), const_iterator(finish)); +} + +class my_int1 { +public: + my_int1() { } + my_int1(int x) : m_int(x) { } + my_int1& operator++() { ++m_int; return *this; } + bool operator==(const my_int1& x) const { return m_int == x.m_int; } +private: + int m_int; +}; + +class my_int2 { +public: + typedef void value_type; + typedef void pointer; + typedef void reference; + typedef std::ptrdiff_t difference_type; + typedef std::bidirectional_iterator_tag iterator_category; + + my_int2() { } + my_int2(int x) : m_int(x) { } + my_int2& operator++() { ++m_int; return *this; } + my_int2& operator--() { --m_int; return *this; } + bool operator==(const my_int2& x) const { return m_int == x.m_int; } +private: + int m_int; +}; + +class my_int3 { +public: + typedef void value_type; + typedef void pointer; + typedef void reference; + typedef std::ptrdiff_t difference_type; + typedef std::random_access_iterator_tag iterator_category; + + my_int3() { } + my_int3(int x) : m_int(x) { } + my_int3& operator++() { ++m_int; return *this; } + my_int3& operator+=(std::ptrdiff_t n) { m_int += n; return *this; } + std::ptrdiff_t operator-(const my_int3& x) const { return m_int - x.m_int; } + my_int3& operator--() { --m_int; return *this; } + bool operator==(const my_int3& x) const { return m_int == x.m_int; } + bool operator!=(const my_int3& x) const { return m_int != x.m_int; } + bool operator<(const my_int3& x) const { return m_int < x.m_int; } +private: + int m_int; +}; + +int main() +{ + // Test the built-in integer types. + test_integer(); + test_integer(); + test_integer(); + test_integer(); + test_integer(); + test_integer(); + test_integer(); + test_integer(); + test_integer(); + test_integer(); +#if defined(BOOST_HAS_LONG_LONG) + test_integer(); + test_integer(); +#endif + + // Test user-defined type. + + test_integer3(); + test_integer(); + test_integer(); + + // Some tests on container iterators, to prove we handle a few different categories + test_container >(); + test_container >(); +# ifndef BOOST_NO_SLIST + test_container >(); +# endif + + // Also prove that we can handle raw pointers. + int array[2000]; + test(boost::make_counting_iterator(array), boost::make_counting_iterator(array+2000-1)); + + return 0; +} diff --git a/test/filter_iterator_test.cpp b/test/filter_iterator_test.cpp new file mode 100644 index 0000000..16cd894 --- /dev/null +++ b/test/filter_iterator_test.cpp @@ -0,0 +1,87 @@ +// 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 +#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 + +template struct undefined; + +// 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::bidirectional_readable_iterator_test( + filter_iter(one_or_four(), array, array+N) + , dummyT(1), dummyT(4)); + + BOOST_STATIC_ASSERT(( + !boost::detail::is_tag< + boost::random_access_traversal_tag + , 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::bidirectional_readable_iterator_test( + boost::make_filter_iterator(one_or_four(), array2.begin(), array2.end()), + dummyT(1), dummyT(4)); + + boost::bidirectional_readable_iterator_test( + boost::make_filter_iterator(one_or_four(), array2.begin(), array2.end()), + dummyT(1), dummyT(4)); + + boost::bidirectional_readable_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::bidirectional_readable_iterator_test( + filter_iter(array+0, array+N), + dummyT(1), dummyT(4)); + + boost::bidirectional_readable_iterator_test( + filter_iter(one_or_four(), array, array + N), + dummyT(1), dummyT(4)); + + std::cout << "test successful " << std::endl; + return 0; +} diff --git a/test/indirect_iterator_test.cpp b/test/indirect_iterator_test.cpp new file mode 100644 index 0000000..43fa4ae --- /dev/null +++ b/test/indirect_iterator_test.cpp @@ -0,0 +1,253 @@ +// (C) Copyright Jeremy Siek 1999. 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 +// 22 Nov 2002 Thomas Witt +// Added interoperability check. +// 08 Mar 2001 Jeremy Siek +// Moved test of indirect iterator into its own file. It to +// to be in iterator_adaptor_test.cpp. + +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include +#include + +#if !defined(__SGI_STL_PORT) \ + && (defined(BOOST_MSVC_STD_ITERATOR) \ + || BOOST_WORKAROUND(_CPPLIB_VER, <= 310) \ + || BOOST_WORKAROUND(__GNUC__, <= 2)) + +// std container random-access iterators don't support mutable/const +// interoperability (but may support const/mutable interop). +# define NO_MUTABLE_CONST_STD_DEQUE_ITERATOR_INTEROPERABILITY +# define NO_MUTABLE_CONST_STD_SET_ITERATOR_INTEROPERABILITY + +#endif + +#if defined(BOOST_MSVC_STD_ITERATOR) \ +|| defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) + +// No working iterator_traits implementation, so we must use deque +# define RA_CONTAINER std::deque +# include + +# ifdef NO_MUTABLE_CONST_STD_DEQUE_ITERATOR_INTEROPERABILITY +# define NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY +# endif + +#else + +# define RA_CONTAINER std::vector +# include + +#endif + +struct my_iterator_tag : public std::random_access_iterator_tag { }; + +using boost::dummyT; + +typedef RA_CONTAINER storage; +typedef RA_CONTAINER pointer_ra_container; +typedef std::set iterator_set; + +template +struct indirect_iterator_pair_generator +{ + typedef boost::indirect_iterator iterator; + + typedef boost::indirect_iterator< + typename Container::iterator + , typename iterator::value_type const + > const_iterator; +}; + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { namespace detail +{ + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; +}} +#endif + + +void more_indirect_iterator_tests() +{ +# if 0 + storage store(1000); + std::generate(store.begin(), store.end(), rand); + + pointer_ra_container ptr_ra_container; + iterator_set iter_set; + + for (storage::iterator p = store.begin(); p != store.end(); ++p) + { + ptr_ra_container.push_back(&*p); + iter_set.insert(p); + } + + typedef indirect_iterator_pair_generator indirect_ra_container; + + indirect_ra_container::iterator db(ptr_ra_container.begin()); + indirect_ra_container::iterator de(ptr_ra_container.end()); + assert(static_cast(de - db) == store.size()); + assert(db + store.size() == de); + indirect_ra_container::const_iterator dci = db; + + assert(dci == db); + +#ifndef NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY + assert(db == dci); +#endif + + assert(dci != de); + assert(dci < de); + assert(dci <= de); + +#ifndef NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY + assert(de >= dci); + assert(de > dci); +#endif + + dci = de; + assert(dci == de); + + boost::random_access_iterator_test(db + 1, store.size() - 1, boost::next(store.begin())); + + *db = 999; + assert(store.front() == 999); + + // Borland C++ is getting very confused about the typedefs here + typedef boost::indirect_iterator indirect_set_iterator; + typedef boost::indirect_iterator< + iterator_set::iterator + , iterator_set::iterator::value_type const + > const_indirect_set_iterator; + + indirect_set_iterator sb(iter_set.begin()); + indirect_set_iterator se(iter_set.end()); + const_indirect_set_iterator sci(iter_set.begin()); + assert(sci == sb); + +# ifndef NO_MUTABLE_CONST_STD_SET_ITERATOR_INTEROPERABILITY + assert(se != sci); +# endif + + assert(sci != se); + sci = se; + assert(sci == se); + + *boost::prior(se) = 888; + assert(store.back() == 888); + assert(std::equal(sb, se, store.begin())); + + boost::bidirectional_iterator_test(boost::next(sb), store[1], store[2]); + assert(std::equal(db, de, store.begin())); +#endif +} + +int +main() +{ + dummyT array[] = { dummyT(0), dummyT(1), dummyT(2), + dummyT(3), dummyT(4), dummyT(5) }; + const int N = sizeof(array)/sizeof(dummyT); + + typedef RA_CONTAINER > shared_t; + shared_t shared; + + // Concept checks + { + typedef boost::indirect_iterator iter_t; + + BOOST_STATIC_ASSERT( + boost::detail::has_element_type< + boost::shared_ptr + // std::iterator_traits::value_type + >::value + ); + + typedef boost::indirect_iterator< + shared_t::iterator + , boost::iterator_value::type const + > c_iter_t; + +# ifndef NO_MUTABLE_CONST_RA_ITERATOR_INTEROPERABILITY + boost::function_requires< boost_concepts::InteroperableConcept >(); +# endif + } + + // Test indirect_iterator_generator + { + for (int jj = 0; jj < N; ++jj) + shared.push_back(boost::shared_ptr(new dummyT(jj))); + + dummyT* ptr[N]; + for (int k = 0; k < N; ++k) + ptr[k] = array + k; + + typedef boost::indirect_iterator indirect_iterator; + + typedef boost::indirect_iterator + const_indirect_iterator; + + indirect_iterator i(ptr); + boost::random_access_iterator_test(i, N, array); + + boost::random_access_iterator_test( + boost::indirect_iterator(shared.begin()) + , N, array); + + boost::random_access_iterator_test(boost::make_indirect_iterator(ptr), N, array); + + // check operator-> + assert((*i).m_x == i->foo()); + + const_indirect_iterator j(ptr); + boost::random_access_iterator_test(j, N, array); + + + dummyT const*const* const_ptr = ptr; + boost::random_access_iterator_test(boost::make_indirect_iterator(const_ptr), N, array); + + boost::const_nonconst_iterator_test(i, ++j); + + more_indirect_iterator_tests(); + } + std::cout << "test successful " << std::endl; + return 0; +} diff --git a/test/interoperable_fail.cpp b/test/interoperable_fail.cpp new file mode 100644 index 0000000..d3d869d --- /dev/null +++ b/test/interoperable_fail.cpp @@ -0,0 +1,22 @@ +// Copyright Thomas Witt 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 +#include + +int main() +{ + { + typedef boost::reverse_iterator::iterator> rev_iter; + typedef boost::indirect_iterator::iterator> ind_iter; + + ind_iter() == rev_iter(); + } + + return boost::exit_success; +} diff --git a/test/is_convertible_fail.cpp b/test/is_convertible_fail.cpp new file mode 100644 index 0000000..7d3c9b1 --- /dev/null +++ b/test/is_convertible_fail.cpp @@ -0,0 +1,11 @@ +#include +#include + +int main() +{ + typedef boost::reverse_iterator rev_iter1; + typedef boost::reverse_iterator rev_iter2; + + return boost::is_convertible::value + ? boost::exit_failure : boost::exit_success; +} diff --git a/test/iterator_adaptor_cc.cpp b/test/iterator_adaptor_cc.cpp new file mode 100644 index 0000000..e08eabd --- /dev/null +++ b/test/iterator_adaptor_cc.cpp @@ -0,0 +1,40 @@ +#include +#include +#include +#include +#include + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { namespace detail +{ + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; +}} +#endif + +int main() +{ + { + typedef boost::reverse_iterator rev_iter; + typedef boost::reverse_iterator c_rev_iter; + + boost::function_requires< boost_concepts::WritableLvalueIteratorConcept >(); + boost::function_requires< boost_concepts::RandomAccessTraversalConcept >(); + boost::function_requires< boost::RandomAccessIteratorConcept >(); + boost::function_requires< boost_concepts::InteroperableConcept >(); + } + { + typedef boost::reverse_iterator::iterator> rev_iter; + typedef boost::reverse_iterator::const_iterator> c_rev_iter; + + boost::function_requires< boost_concepts::ReadableLvalueIteratorConcept >(); + boost::function_requires< boost_concepts::BidirectionalTraversalConcept >(); + boost::function_requires< boost::BidirectionalIteratorConcept >(); + boost::function_requires< boost_concepts::InteroperableConcept >(); + } + + return boost::exit_success; +} diff --git a/test/iterator_adaptor_test.cpp b/test/iterator_adaptor_test.cpp new file mode 100644 index 0000000..32edd85 --- /dev/null +++ b/test/iterator_adaptor_test.cpp @@ -0,0 +1,261 @@ +// (C) Copyright Thomas Witt 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. + +// See http://www.boost.org for most recent version including documentation. + +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include + +#include "static_assert_same.hpp" + +struct my_iterator_tag : public std::random_access_iterator_tag { }; + +using boost::dummyT; + + +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; +}; + +template +struct select1st_ + : public std::unary_function +{ + const typename Pair::first_type& operator()(const Pair& x) const { + return x.first; + } + typename Pair::first_type& operator()(Pair& x) const { + return x.first; + } +}; + +struct one_or_four { + bool operator()(dummyT x) const { + return x.foo() == 1 || x.foo() == 4; + } +}; + +typedef std::deque storage; +typedef std::deque pointer_deque; +typedef std::set iterator_set; + +template struct foo; + +void blah(int) { } + +struct my_gen +{ + typedef int result_type; + my_gen() : n(0) { } + int operator()() { return ++n; } + int n; +}; + +template +struct ptr_iterator + : boost::iterator_adaptor< + ptr_iterator + , V* + , V + , std::random_access_iterator_tag +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + , V& +#endif + > +{ +private: + typedef boost::iterator_adaptor< + ptr_iterator + , V* + , V + , std::random_access_iterator_tag +#if BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) + , V& +#endif + > super_t; + +public: + ptr_iterator() { } + ptr_iterator(V* d) : super_t(d) { } + + template + ptr_iterator( + const ptr_iterator& x + , typename boost::enable_if_convertible::type* = 0 + ) + : super_t(x.base()) + {} +}; + +template +struct fwd_iterator + : boost::iterator_adaptor< + fwd_iterator + , boost::forward_iterator_archetype + > +{ +private: + typedef boost::iterator_adaptor< + fwd_iterator + , boost::forward_iterator_archetype + > super_t; + +public: + fwd_iterator() { } + fwd_iterator(boost::forward_iterator_archetype d) : super_t(d) { } +}; + +template +struct in_iterator + : boost::iterator_adaptor< + in_iterator + , boost::input_iterator_archetype + > +{ +private: + typedef boost::iterator_adaptor< + in_iterator + , boost::input_iterator_archetype + > super_t; + +public: + in_iterator() { } + in_iterator(boost::input_iterator_archetype d) : super_t(d) { } +}; + +template +struct constant_iterator + : boost::iterator_adaptor< + constant_iterator + , Iter + , typename std::iterator_traits::value_type const + > +{ + typedef boost::iterator_adaptor< + constant_iterator + , Iter + , typename std::iterator_traits::value_type const + > base_t; + + constant_iterator() {} + constant_iterator(Iter it) + : base_t(it) {} +}; + +int +main() +{ + dummyT array[] = { dummyT(0), dummyT(1), dummyT(2), + dummyT(3), dummyT(4), dummyT(5) }; + const int N = sizeof(array)/sizeof(dummyT); + + // sanity check, if this doesn't pass the test is buggy + boost::random_access_iterator_test(array, N, array); + + // Test the iterator_adaptor + { + ptr_iterator i(array); + boost::random_access_iterator_test(i, N, array); + + ptr_iterator j(array); + boost::random_access_iterator_test(j, N, array); + boost::const_nonconst_iterator_test(i, ++j); + } + + int test; + // Test the iterator_traits + { + // Test computation of defaults + typedef ptr_iterator Iter1; + // don't use std::iterator_traits here to avoid VC++ problems + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; +#if !BOOST_WORKAROUND(__MWERKS__, <= 0x2407) + BOOST_STATIC_ASSERT((boost::is_convertible::value)); +#endif + } + + { + // Test computation of default when the Value is const + typedef ptr_iterator Iter1; + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; test = static_assert_same::value; + } + + { + // Test constant iterator idiom + typedef ptr_iterator BaseIter; + typedef constant_iterator Iter; + + test = static_assert_same::value; + test = static_assert_same::value; + test = static_assert_same::value; + + test = static_assert_same::value; + test = static_assert_same::value; + } + + // Test the iterator_adaptor + { + ptr_iterator i(array); + boost::random_access_iterator_test(i, N, array); + + ptr_iterator j(array); + boost::random_access_iterator_test(j, N, array); + boost::const_nonconst_iterator_test(i, ++j); + } + + // check operator-> with a forward iterator + { + boost::forward_iterator_archetype forward_iter; + + typedef fwd_iterator adaptor_type; + + adaptor_type i(forward_iter); + int zero = 0; + if (zero) // don't do this, just make sure it compiles + assert((*i).m_x == i->foo()); + } + + // check operator-> with an input iterator + { + boost::input_iterator_archetype input_iter; + typedef in_iterator adaptor_type; + adaptor_type i(input_iter); + int zero = 0; + if (zero) // don't do this, just make sure it compiles + assert((*i).m_x == i->foo()); + } + + std::cout << "test successful " << std::endl; + (void)test; + return 0; +} diff --git a/test/iterator_archetype_cc.cpp b/test/iterator_archetype_cc.cpp new file mode 100644 index 0000000..1edf5e5 --- /dev/null +++ b/test/iterator_archetype_cc.cpp @@ -0,0 +1,25 @@ +// +// Copyright Thomas Witt 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 + +int main() +{ + { + typedef boost::iterator_archetype iter; + + boost::function_requires< boost_concepts::WritableLvalueIteratorConcept >(); + boost::function_requires< boost_concepts::RandomAccessTraversalConcept >(); + } + return 0; // keep msvc happy +} + diff --git a/test/permutation_iterator_test.cpp b/test/permutation_iterator_test.cpp new file mode 100644 index 0000000..0b05ba2 --- /dev/null +++ b/test/permutation_iterator_test.cpp @@ -0,0 +1,101 @@ +// (C) Copyright Toon Knapen 2001. +// (C) Copyright Roland Richter 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 +#include + +#include + + +void permutation_test() +{ + // Example taken from documentation of old permutation_iterator. + typedef std::vector< int > element_range_type; + typedef std::list< int > index_type; + + const int element_range_size = 10; + const int index_size = 4; + + element_range_type elements( element_range_size ); + for( element_range_type::iterator el_it = elements.begin(); el_it != elements.end(); ++el_it ) + { *el_it = std::distance(elements.begin(), el_it); } + + index_type indices( index_size ); + for( index_type::iterator i_it = indices.begin(); i_it != indices.end(); ++i_it ) + { *i_it = element_range_size - index_size + std::distance(indices.begin(), i_it); } + std::reverse( indices.begin(), indices.end() ); + +#ifdef BOOST_MSVC + + typedef boost::permutation_iterator< element_range_type::iterator + , index_type::iterator + , boost::use_default + , boost::use_default + , element_range_type::reference > permutation_type; + + permutation_type begin( elements.begin(), indices.begin() ); + permutation_type it = begin; + permutation_type end( elements.begin(), indices.end() ); + +#else + + typedef boost::permutation_iterator< element_range_type::iterator, index_type::iterator > permutation_type; + permutation_type begin = boost::make_permutation_iterator( elements.begin(), indices.begin() ); + permutation_type it = begin; + permutation_type end = boost::make_permutation_iterator( elements.begin(), indices.end() ); + +#endif + + BOOST_CHECK( it == begin ); + BOOST_CHECK( it != end ); + + BOOST_CHECK( std::distance( begin, end ) == index_size ); + + for( index_type::iterator i_it = indices.begin(); it != end; ++i_it, ++it ) + { + BOOST_CHECK( *it == elements[ *i_it ] ); + } + + it = begin; + for( int i = 0; i < index_size ; i+=2, it+=2 ) + { + index_type::iterator i_it = indices.begin(); std::advance( i_it, i ); + BOOST_CHECK( *it == elements[ *i_it ] ); + } + + + it = begin + (index_size); + BOOST_CHECK( it != begin ); + for( index_type::iterator i_it = --indices.end(); it-- != begin; --i_it ) + { + BOOST_CHECK( *it == elements[ *i_it ] ); + } + + it = begin + (index_size - 1); + for( int i = 0; i < index_size; i+=2, it-=2 ) + { + index_type::iterator i_it = --indices.end(); std::advance( i_it, -i ); + BOOST_CHECK( *it == elements[ *i_it ] ); + } + +} + + +int test_main(int, char *[]) +{ + permutation_test(); + + bool error_on_purpose = false; + //BOOST_CHECK( error_on_purpose ); + + return 0; +} diff --git a/test/reverse_iterator_test.cpp b/test/reverse_iterator_test.cpp new file mode 100644 index 0000000..8b3e9b6 --- /dev/null +++ b/test/reverse_iterator_test.cpp @@ -0,0 +1,97 @@ +// Copyright Thomas Witt 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; + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost +{ + namespace detail + { + template<> struct iterator_traits + : ptr_iter_traits {}; + template<> struct iterator_traits + : ptr_iter_traits {}; + } +} +#endif + +// Test reverse iterator +int main() +{ + dummyT array[] = { dummyT(0), dummyT(1), dummyT(2), + dummyT(3), dummyT(4), dummyT(5) }; + const int N = sizeof(array)/sizeof(dummyT); + + // Test reverse_iterator_generator + { + dummyT reversed[N]; + std::copy(array, array + N, reversed); + std::reverse(reversed, reversed + N); + + typedef boost::reverse_iterator reverse_iterator; + + reverse_iterator i(reversed + N); + boost::random_access_iterator_test(i, N, array); + + boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array); + + typedef boost::reverse_iterator const_reverse_iterator; + + const_reverse_iterator j(reversed + N); + boost::random_access_iterator_test(j, N, array); + + const dummyT* const_reversed = reversed; + + boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array); + + boost::const_nonconst_iterator_test(i, ++j); + } + + // Test reverse_iterator_generator again, with traits fully deducible on all platforms + { + std::deque reversed_container; + std::reverse_copy(array, array + N, std::back_inserter(reversed_container)); + const std::deque::iterator reversed = reversed_container.begin(); + + + typedef boost::reverse_iterator< + std::deque::iterator> reverse_iterator; + typedef boost::reverse_iterator< + std::deque::const_iterator> const_reverse_iterator; + + // MSVC/STLport gives an INTERNAL COMPILER ERROR when any computation + // (e.g. "reversed + N") is used in the constructor below. + const std::deque::iterator finish = reversed_container.end(); + reverse_iterator i(finish); + + boost::random_access_iterator_test(i, N, array); + boost::random_access_iterator_test(boost::make_reverse_iterator(reversed + N), N, array); + + const_reverse_iterator j = reverse_iterator(finish); + boost::random_access_iterator_test(j, N, array); + + const std::deque::const_iterator const_reversed = reversed; + boost::random_access_iterator_test(boost::make_reverse_iterator(const_reversed + N), N, array); + + // Many compilers' builtin deque iterators don't interoperate well, though + // STLport fixes that problem. +#if defined(__SGI_STL_PORT) \ + || !BOOST_WORKAROUND(__GNUC__, <= 2) \ + && !BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x551)) \ + && !BOOST_WORKAROUND(BOOST_DINKUMWARE_STDLIB, <= 1) + + boost::const_nonconst_iterator_test(i, ++j); + +#endif + } + return 0; +} diff --git a/test/static_assert_same.hpp b/test/static_assert_same.hpp new file mode 100644 index 0000000..3bff6bf --- /dev/null +++ b/test/static_assert_same.hpp @@ -0,0 +1,31 @@ +// 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. +#ifndef STATIC_ASSERT_SAME_DWA2003530_HPP +# define STATIC_ASSERT_SAME_DWA2003530_HPP + +# include + +#ifndef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +template +struct static_assert_same; + +template +struct static_assert_same +{ + enum { value = 1 }; +}; +#else +# include +# include +# include + +template +struct static_assert_same + : boost::mpl::if_,boost::mpl::true_,void>::type +{}; +#endif + +#endif // STATIC_ASSERT_SAME_DWA2003530_HPP diff --git a/test/transform_iterator_test.cpp b/test/transform_iterator_test.cpp new file mode 100644 index 0000000..fe694b5 --- /dev/null +++ b/test/transform_iterator_test.cpp @@ -0,0 +1,248 @@ +// (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 +// 22 Nov 2002 Thomas Witt +// Added interoperability check. +// 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 +#include +#include +#include + + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { namespace detail +{ + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits*> + : ptr_iter_traits > {}; + + template<> struct iterator_traits + : ptr_iter_traits {}; + + template<> struct iterator_traits const*> + : ptr_iter_traits, std::pair const> {}; + +}} +#endif + +struct mult_functor { + // 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; +}; + +struct adaptable_mult_functor + : 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. + adaptable_mult_functor() { } + adaptable_mult_functor(int aa) : mult_functor(aa) { } +}; + + +struct select_first +{ + typedef int& result_type; + + int& operator()(std::pair& p) const + { + return p.first; + } +}; + +struct select_second +{ + typedef int& result_type; + + int& operator()(std::pair& p) const + { + return p.second; + } +}; + +struct const_select_first +{ + typedef int const& result_type; + + int const& operator()(std::pairconst& p) const + { + return p.first; + } +}; + +struct value_select_first +{ + typedef int result_type; + + int operator()(std::pairconst& p) const + { + return p.first; + } +}; + +int mult_2(int arg) +{ + return arg*2; +} + +int +main() +{ + const int N = 10; + + // Concept checks + { + typedef boost::transform_iterator iter_t; + typedef boost::transform_iterator c_iter_t; + + boost::function_requires< boost_concepts::InteroperableConcept >(); + } + + // 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, adaptable_mult_functor(2)); + boost::input_iterator_test(i, x[0], x[1]); + boost::input_iterator_test(iter_t(&y[0], adaptable_mult_functor(2)), x[0], x[1]); + + boost::random_access_readable_iterator_test(i, N, x); + } + + // Test transform_iterator non adaptable functor + { + 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); + } + + // Test transform_iterator default argument handling + { + { + typedef boost::transform_iterator iter_t; + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + { + typedef boost::transform_iterator iter_t; + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + + { + typedef boost::transform_iterator iter_t; + BOOST_STATIC_ASSERT((boost::is_same::value)); + BOOST_STATIC_ASSERT((boost::is_same::value)); + } + } + + // Test transform_iterator with function pointers + { + 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; + + boost::input_iterator_test(boost::make_transform_iterator(y, mult_2) + , x[0] + , x[1]); + + boost::input_iterator_test(boost::make_transform_iterator(&y[0], mult_2) + , x[0] + , x[1]); + + boost::random_access_readable_iterator_test(boost::make_transform_iterator(y, mult_2) + , N + , x); + + } + + // Test transform_iterator as projection iterator + { + typedef std::pair pair_t; + + int x[N]; + int y[N]; + pair_t values[N]; + + for(int i = 0; i < N; ++i) { + + x[i] = i; + y[i] = N - (i + 1); + + } + + std::copy(x, + x + N, + boost::make_transform_iterator((pair_t*)values, select_first())); + + std::copy(y, + y + N, + boost::make_transform_iterator((pair_t*)values, select_second())); + + boost::random_access_readable_iterator_test(boost::make_transform_iterator((pair_t*)values, value_select_first()), + N, + x); + + boost::random_access_readable_iterator_test(boost::make_transform_iterator((pair_t*)values, const_select_first()), + N, + x); + + boost::constant_lvalue_iterator_test(boost::make_transform_iterator((pair_t*)values, const_select_first()), x[0]); + + boost::mutable_lvalue_iterator_test(boost::make_transform_iterator((pair_t*)values, select_first()), x[0], 17); + + } + + std::cout << "test successful " << std::endl; + return 0; +} diff --git a/test/unit_tests.cpp b/test/unit_tests.cpp new file mode 100644 index 0000000..4887357 --- /dev/null +++ b/test/unit_tests.cpp @@ -0,0 +1,103 @@ +// 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 "static_assert_same.hpp" + +struct X { int a; }; + +#ifdef BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION +namespace boost { namespace detail { +template<> struct iterator_traits + : ptr_iter_traits {}; +}} +#endif + +struct Xiter : boost::iterator_adaptor +{ + Xiter(); + Xiter(X* p) : boost::iterator_adaptor(p) {} +}; + +void take_xptr(X*) {} +void operator_arrow_test() +{ + // check that the operator-> result is a pointer for lvalue iterators + X x; + take_xptr(Xiter(&x).operator->()); +} + +template +struct static_assert_min_cat + : static_assert_same< + typename boost::detail::minimum_category::type, Min + > +{}; + +void category_test() +{ + using namespace boost; + using namespace boost::detail; + + BOOST_STATIC_ASSERT(( + !is_tag< + input_output_iterator_tag + , std::input_iterator_tag>::value)); + + BOOST_STATIC_ASSERT(( + !is_tag< + input_output_iterator_tag + , std::output_iterator_tag>::value)); + + BOOST_STATIC_ASSERT(( + is_tag< + std::input_iterator_tag + , input_output_iterator_tag>::value)); + + BOOST_STATIC_ASSERT(( + is_tag< + std::output_iterator_tag + , input_output_iterator_tag>::value)); + + BOOST_STATIC_ASSERT(( + is_tag< + input_output_iterator_tag + , std::forward_iterator_tag>::value)); + + int test = static_assert_min_cat< + std::input_iterator_tag,input_output_iterator_tag, std::input_iterator_tag + >::value; + + test = static_assert_min_cat< + input_output_iterator_tag,std::input_iterator_tag, std::input_iterator_tag + >::value; + + test = static_assert_min_cat< + input_output_iterator_tag,std::forward_iterator_tag, input_output_iterator_tag + >::value; + + test = static_assert_min_cat< + std::input_iterator_tag,std::forward_iterator_tag, std::input_iterator_tag + >::value; + + test = static_assert_min_cat< + std::input_iterator_tag,std::random_access_iterator_tag, std::input_iterator_tag + >::value; + + test = static_assert_min_cat< + std::output_iterator_tag,std::random_access_iterator_tag, std::output_iterator_tag + >::value; + + (void)test; +} + +int main() +{ + category_test(); + operator_arrow_test(); + return 0; +} +