diff --git a/doc/foreach.qbk b/doc/foreach.qbk index 3cf809e..cc64843 100755 --- a/doc/foreach.qbk +++ b/doc/foreach.qbk @@ -162,6 +162,14 @@ Iterate over an expression that returns a sequence by value (i.e. an rvalue): // Note: get_vector_float() will be called exactly once } +Iterate in reverse: + + std::list list_int( /*...*/ ); + BOOST_REVERSE_FOREACH( int i, list_int ) + { + // do something with i + } + Iterating over rvalues doesn't work on some older compilers. Check the [link foreach.portability Portability] section to see whether your compiler supports this. @@ -170,11 +178,12 @@ compiler supports this. People have complained about the name _foreach_. It's too long. `ALL CAPS` can get tiresome to look at. That may be true, but _foreach_ is merely following -the [@../../../more/lib_guide.htm Boost Naming Convention]. That +the [@http://www.boost.org/more/lib_guide.htm Boost Naming Convention]. That doesn't mean you're stuck with it, though. If you would like to use a different identifier (`foreach`, perhaps), you can simply do: - #define foreach BOOST_FOREACH + #define foreach BOOST_FOREACH + #define reverse_foreach BOOST_REVERSE_FOREACH Only do this if you are sure that the identifier you choose will not cause name conflicts in your code. diff --git a/include/boost/foreach.hpp b/include/boost/foreach.hpp index a11c153..49680de 100755 --- a/include/boost/foreach.hpp +++ b/include/boost/foreach.hpp @@ -69,7 +69,10 @@ #include #include #include +#include +#include #include +#include #include #include #include @@ -202,15 +205,6 @@ namespace foreach_detail_ /////////////////////////////////////////////////////////////////////////////// // Define some utilities for assessing the properties of expressions // -typedef char yes_type; -typedef char (&no_type)[2]; -yes_type is_true(boost::mpl::true_ *); -no_type is_true(boost::mpl::false_ *); - -// Extracts the desired property from the expression without evaluating it -#define BOOST_FOREACH_PROTECT(expr) \ - (static_cast *>(0)) - template inline boost::mpl::and_ *and_(Bool1 *, Bool2 *) { return 0; } @@ -353,8 +347,8 @@ struct foreach_iterator // // To treat the container as an array, use boost::as_array() in , // as in BOOST_FOREACH( char ch, boost::as_array("hello") ) ... - #if BOOST_MSVC > 1300 - BOOST_MPL_ASSERT_MSG( (!is_char_array::value), IS_THIS_AN_ARRAY_OR_A_NULL_TERMINATED_STRING, (T) ); + #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 + BOOST_MPL_ASSERT_MSG( (!is_char_array::value), IS_THIS_AN_ARRAY_OR_A_NULL_TERMINATED_STRING, (T&) ); #endif // If the type is a pointer to a null terminated string (as opposed @@ -368,6 +362,37 @@ struct foreach_iterator >::type type; }; + +template +struct foreach_reverse_iterator +{ + // **** READ THIS IF YOUR COMPILE BREAKS HERE **** + // + // There is an ambiguity about how to iterate over arrays of char and wchar_t. + // Should the last array element be treated as a null terminator to be skipped, or + // is it just like any other element in the array? To fix the problem, you must + // say which behavior you want. + // + // To treat the container as a null-terminated string, merely cast it to a + // char const *, as in BOOST_FOREACH( char ch, (char const *)"hello" ) ... + // + // To treat the container as an array, use boost::as_array() in , + // as in BOOST_FOREACH( char ch, boost::as_array("hello") ) ... + #if !defined(BOOST_MSVC) || BOOST_MSVC > 1300 + BOOST_MPL_ASSERT_MSG( (!is_char_array::value), IS_THIS_AN_ARRAY_OR_A_NULL_TERMINATED_STRING, (T&) ); + #endif + + // If the type is a pointer to a null terminated string (as opposed + // to an array type), there is no ambiguity. + typedef BOOST_DEDUCED_TYPENAME wrap_cstr::type container; + + typedef BOOST_DEDUCED_TYPENAME boost::mpl::eval_if< + C + , range_reverse_iterator + , range_reverse_iterator + >::type type; +}; + template struct foreach_reference : iterator_reference::type> @@ -441,17 +466,20 @@ struct rvalue_probe typedef BOOST_DEDUCED_TYPENAME boost::mpl::if_< boost::mpl::or_, boost::is_array >, private_type_, T >::type value_type; - operator value_type(); - operator T &() const; + operator value_type() { return *reinterpret_cast(this); } // never called + operator T &() const { return *reinterpret_cast(const_cast(this)); } // never called }; template -rvalue_probe const make_probe(T const &t); +rvalue_probe const make_probe(T const &t) +{ + return rvalue_probe(); +} # define BOOST_FOREACH_IS_RVALUE(COL) \ boost::foreach_detail_::and_( \ boost::foreach_detail_::not_(boost::foreach_detail_::is_array_(COL)) \ - , BOOST_FOREACH_PROTECT(boost::foreach_detail_::is_rvalue_( \ + , (true ? 0 : boost::foreach_detail_::is_rvalue_( \ (true ? boost::foreach_detail_::make_probe(COL) : (COL)), 0))) #elif defined(BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION) @@ -717,6 +745,114 @@ deref(auto_any_t cur, type2type *) return *auto_any_cast(cur); } +///////////////////////////////////////////////////////////////////////////// +// rbegin +// +template +inline auto_any::type> +rbegin(auto_any_t col, type2type *, boost::mpl::true_ *) // rvalue +{ + return boost::rbegin(auto_any_cast(col)); +} + +template +inline auto_any::type> +rbegin(auto_any_t col, type2type *, boost::mpl::false_ *) // lvalue +{ + typedef BOOST_DEDUCED_TYPENAME type2type::type type; + typedef BOOST_DEDUCED_TYPENAME foreach_reverse_iterator::type iterator; + return iterator(boost::rbegin(derefof(auto_any_cast(col)))); +} + +#ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION +template +auto_any::type> +rbegin(auto_any_t col, type2type *, bool *) +{ + return boost::rbegin(*auto_any_cast, boost::mpl::false_>(col).get()); +} +#endif + +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +template +inline auto_any > +rbegin(auto_any_t col, type2type *, boost::mpl::true_ *) // null-terminated C-style strings +{ + T *p = auto_any_cast(col); + while(0 != *p) + ++p; + return reverse_iterator(p); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// rend +// +template +inline auto_any::type> +rend(auto_any_t col, type2type *, boost::mpl::true_ *) // rvalue +{ + return boost::rend(auto_any_cast(col)); +} + +template +inline auto_any::type> +rend(auto_any_t col, type2type *, boost::mpl::false_ *) // lvalue +{ + typedef BOOST_DEDUCED_TYPENAME type2type::type type; + typedef BOOST_DEDUCED_TYPENAME foreach_reverse_iterator::type iterator; + return iterator(boost::rend(derefof(auto_any_cast(col)))); +} + +#ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION +template +auto_any::type> +rend(auto_any_t col, type2type *, bool *) +{ + return boost::rend(*auto_any_cast, boost::mpl::false_>(col).get()); +} +#endif + +#ifndef BOOST_NO_FUNCTION_TEMPLATE_ORDERING +template +inline auto_any > +rend(auto_any_t col, type2type *, boost::mpl::true_ *) // null-terminated C-style strings +{ + return reverse_iterator(auto_any_cast(col)); +} +#endif + +/////////////////////////////////////////////////////////////////////////////// +// rdone +// +template +inline bool rdone(auto_any_t cur, auto_any_t end, type2type *) +{ + typedef BOOST_DEDUCED_TYPENAME foreach_reverse_iterator::type iter_t; + return auto_any_cast(cur) == auto_any_cast(end); +} + +/////////////////////////////////////////////////////////////////////////////// +// rnext +// +template +inline void rnext(auto_any_t cur, type2type *) +{ + typedef BOOST_DEDUCED_TYPENAME foreach_reverse_iterator::type iter_t; + ++auto_any_cast(cur); +} + +/////////////////////////////////////////////////////////////////////////////// +// rderef +// +template +inline BOOST_DEDUCED_TYPENAME foreach_reference::type +rderef(auto_any_t cur, type2type *) +{ + typedef BOOST_DEDUCED_TYPENAME foreach_reverse_iterator::type iter_t; + return *auto_any_cast(cur); +} + } // namespace foreach_detail_ } // namespace boost @@ -853,6 +989,34 @@ deref(auto_any_t cur, type2type *) _foreach_cur \ , BOOST_FOREACH_TYPEOF(COL)) +#define BOOST_FOREACH_RBEGIN(COL) \ + boost::foreach_detail_::rbegin( \ + _foreach_col \ + , BOOST_FOREACH_TYPEOF(COL) \ + , BOOST_FOREACH_SHOULD_COPY(COL)) + +#define BOOST_FOREACH_REND(COL) \ + boost::foreach_detail_::rend( \ + _foreach_col \ + , BOOST_FOREACH_TYPEOF(COL) \ + , BOOST_FOREACH_SHOULD_COPY(COL)) + +#define BOOST_FOREACH_RDONE(COL) \ + boost::foreach_detail_::rdone( \ + _foreach_cur \ + , _foreach_end \ + , BOOST_FOREACH_TYPEOF(COL)) + +#define BOOST_FOREACH_RNEXT(COL) \ + boost::foreach_detail_::rnext( \ + _foreach_cur \ + , BOOST_FOREACH_TYPEOF(COL)) + +#define BOOST_FOREACH_RDEREF(COL) \ + boost::foreach_detail_::rderef( \ + _foreach_cur \ + , BOOST_FOREACH_TYPEOF(COL)) + /////////////////////////////////////////////////////////////////////////////// // BOOST_FOREACH // @@ -890,4 +1054,22 @@ deref(auto_any_t cur, type2type *) if (boost::foreach_detail_::set_false(_foreach_continue)) {} else \ for (VAR = BOOST_FOREACH_DEREF(COL); !_foreach_continue; _foreach_continue = true) +/////////////////////////////////////////////////////////////////////////////// +// BOOST_REVERSE_FOREACH +// +// For iterating over collections in reverse order. In +// all other respects, BOOST_REVERSE_FOREACH is like +// BOOST_FOREACH. +// +#define BOOST_REVERSE_FOREACH(VAR, COL) \ + BOOST_FOREACH_PREAMBLE() \ + if (boost::foreach_detail_::auto_any_t _foreach_col = BOOST_FOREACH_CONTAIN(COL)) {} else \ + if (boost::foreach_detail_::auto_any_t _foreach_cur = BOOST_FOREACH_RBEGIN(COL)) {} else \ + if (boost::foreach_detail_::auto_any_t _foreach_end = BOOST_FOREACH_REND(COL)) {} else \ + for (bool _foreach_continue = true; \ + _foreach_continue && !BOOST_FOREACH_RDONE(COL); \ + _foreach_continue ? BOOST_FOREACH_RNEXT(COL) : (void)0) \ + if (boost::foreach_detail_::set_false(_foreach_continue)) {} else \ + for (VAR = BOOST_FOREACH_RDEREF(COL); !_foreach_continue; _foreach_continue = true) + #endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 4ac2630..7e772b5 100755 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -8,16 +8,27 @@ import testing ; test-suite "foreach" : [ run stl_byval.cpp ] [ run stl_byref.cpp ] + [ run stl_byval_r.cpp ] + [ run stl_byref_r.cpp ] [ run array_byval.cpp ] [ run array_byref.cpp ] + [ run array_byval_r.cpp ] + [ run array_byref_r.cpp ] [ run cstr_byval.cpp ] [ run cstr_byref.cpp ] + [ run cstr_byval_r.cpp ] + [ run cstr_byref_r.cpp ] [ run pair_byval.cpp ] [ run pair_byref.cpp ] + [ run pair_byval_r.cpp ] + [ run pair_byref_r.cpp ] [ run user_defined.cpp ] [ run call_once.cpp ] [ run rvalue_const.cpp ] [ run rvalue_nonconst.cpp ] + [ run rvalue_const_r.cpp ] + [ run rvalue_nonconst_r.cpp ] [ run dependent_type.cpp ] + [ run misc.cpp ] [ compile noncopyable.cpp ] ; diff --git a/test/array_byref_r.cpp b/test/array_byref_r.cpp new file mode 100755 index 0000000..aed9f7e --- /dev/null +++ b/test/array_byref_r.cpp @@ -0,0 +1,48 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef int foreach_container_type[5]; +typedef int const foreach_const_container_type[5]; +typedef int foreach_value_type; +typedef int &foreach_reference_type; +typedef int const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +int my_array[5] = { 1,2,3,4,5 }; +int const (&my_const_array)[5] = my_array; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + // non-const containers by reference + BOOST_CHECK(sequence_equal_byref_n_r(my_array, "\5\4\3\2\1")); + + // const containers by reference + BOOST_CHECK(sequence_equal_byref_c_r(my_const_array, "\5\4\3\2\1")); + + // mutate the mutable collections + mutate_foreach_byref_r(my_array); + + // compare the mutated collections to the actual results + BOOST_CHECK(sequence_equal_byref_n_r(my_array, "\6\5\4\3\2")); + + return 0; +} diff --git a/test/array_byval_r.cpp b/test/array_byval_r.cpp new file mode 100755 index 0000000..c9e8948 --- /dev/null +++ b/test/array_byval_r.cpp @@ -0,0 +1,44 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef int foreach_container_type[5]; +typedef int const foreach_const_container_type[5]; +typedef int foreach_value_type; +typedef int &foreach_reference_type; +typedef int const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +int my_array[5] = { 1,2,3,4,5 }; +int const (&my_const_array)[5] = my_array; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + boost::mpl::false_ *p = BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(my_array); + + // non-const containers by value + BOOST_CHECK(sequence_equal_byval_n_r(my_array, "\5\4\3\2\1")); + + // const containers by value + BOOST_CHECK(sequence_equal_byval_c_r(my_const_array, "\5\4\3\2\1")); + + return 0; +} diff --git a/test/cstr_byref_r.cpp b/test/cstr_byref_r.cpp new file mode 100755 index 0000000..79b46cf --- /dev/null +++ b/test/cstr_byref_r.cpp @@ -0,0 +1,49 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef char *foreach_container_type; +typedef char const *foreach_const_container_type; +typedef char foreach_value_type; +typedef char &foreach_reference_type; +typedef char const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +char my_ntcs_buffer[] = "\1\2\3\4\5"; +char *my_ntcs = my_ntcs_buffer; +char const *my_const_ntcs = my_ntcs; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + // non-const containers by reference + BOOST_CHECK(sequence_equal_byref_n_r(my_ntcs, "\5\4\3\2\1")); + + // const containers by reference + BOOST_CHECK(sequence_equal_byref_c_r(my_const_ntcs, "\5\4\3\2\1")); + + // mutate the mutable collections + mutate_foreach_byref_r(my_ntcs); + + // compare the mutated collections to the actual results + BOOST_CHECK(sequence_equal_byref_n_r(my_ntcs, "\6\5\4\3\2")); + + return 0; +} diff --git a/test/cstr_byval_r.cpp b/test/cstr_byval_r.cpp new file mode 100755 index 0000000..64f36e7 --- /dev/null +++ b/test/cstr_byval_r.cpp @@ -0,0 +1,45 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef char *foreach_container_type; +typedef char const *foreach_const_container_type; +typedef char foreach_value_type; +typedef char &foreach_reference_type; +typedef char const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +char my_ntcs_buffer[] = "\1\2\3\4\5"; +char *my_ntcs = my_ntcs_buffer; +char const *my_const_ntcs = my_ntcs; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + boost::mpl::true_ *p = BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(my_ntcs); + + // non-const containers by value + BOOST_CHECK(sequence_equal_byval_n_r(my_ntcs, "\5\4\3\2\1")); + + // const containers by value + BOOST_CHECK(sequence_equal_byval_c_r(my_const_ntcs, "\5\4\3\2\1")); + + return 0; +} diff --git a/test/misc.cpp b/test/misc.cpp new file mode 100755 index 0000000..2a25aca --- /dev/null +++ b/test/misc.cpp @@ -0,0 +1,47 @@ +// misc.cpp +// +// (C) Copyright Eric Niebler 2008. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 4 March 2008 : Initial version. +*/ + +#include +#include +#include + +struct xxx : std::vector +{ + virtual ~xxx() = 0; +}; + +void test_abstract(xxx& rng) +{ + BOOST_FOREACH (int x, rng) + { + (void)x; + } +} + +struct yyy : std::vector +{ + void test() + { + BOOST_FOREACH(int x, *this) + { + (void)x; + } + } +}; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + return 0; +} diff --git a/test/pair_byref_r.cpp b/test/pair_byref_r.cpp new file mode 100755 index 0000000..562cbf4 --- /dev/null +++ b/test/pair_byref_r.cpp @@ -0,0 +1,50 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 13 December 2004 : Initial version. + 25 August 2005 : Initial version. +*/ + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef std::pair foreach_container_type; +typedef std::pair const foreach_const_container_type; +typedef int foreach_value_type; +typedef int &foreach_reference_type; +typedef int const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +int my_array[] = { 1,2,3,4,5 }; +std::pair my_pair(my_array,my_array+5); +std::pair const my_const_pair(my_array,my_array+5); + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + // non-const containers by reference + BOOST_CHECK(sequence_equal_byref_n_r(my_pair, "\5\4\3\2\1")); + + // const containers by reference + BOOST_CHECK(sequence_equal_byref_c_r(my_const_pair, "\5\4\3\2\1")); + + // mutate the mutable collections + mutate_foreach_byref_r(my_pair); + + // compare the mutated collections to the actual results + BOOST_CHECK(sequence_equal_byref_n_r(my_pair, "\6\5\4\3\2")); + + return 0; +} diff --git a/test/pair_byval_r.cpp b/test/pair_byval_r.cpp new file mode 100755 index 0000000..cca814d --- /dev/null +++ b/test/pair_byval_r.cpp @@ -0,0 +1,45 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef std::pair foreach_container_type; +typedef std::pair const foreach_const_container_type; +typedef int foreach_value_type; +typedef int &foreach_reference_type; +typedef int const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +int my_array[] = { 1,2,3,4,5 }; +std::pair my_pair(my_array,my_array+5); +std::pair const my_const_pair(my_array,my_array+5); + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + boost::mpl::true_ *p = BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(my_pair); + + // non-const containers by value + BOOST_CHECK(sequence_equal_byval_n_r(my_pair, "\5\4\3\2\1")); + + // const containers by value + BOOST_CHECK(sequence_equal_byval_c_r(my_const_pair, "\5\4\3\2\1")); + + return 0; +} diff --git a/test/rvalue_const_r.cpp b/test/rvalue_const_r.cpp new file mode 100755 index 0000000..fbc2762 --- /dev/null +++ b/test/rvalue_const_r.cpp @@ -0,0 +1,44 @@ +// (C) Copyright Eric Niebler 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include +#include + +#ifdef BOOST_FOREACH_NO_CONST_RVALUE_DETECTION +// ignore error during Microsoft Code Analysis +#if !defined(_PREFAST_) +# error Expected failure : const rvalues disallowed +#endif +#else + +std::vector const get_vector() +{ + return std::vector(4, 4); +} + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + int counter = 0; + + BOOST_REVERSE_FOREACH(int i, get_vector()) + { + counter += i; + } + + BOOST_CHECK(16 == counter); + + return 0; +} + +#endif diff --git a/test/rvalue_nonconst_r.cpp b/test/rvalue_nonconst_r.cpp new file mode 100755 index 0000000..991f8be --- /dev/null +++ b/test/rvalue_nonconst_r.cpp @@ -0,0 +1,41 @@ +// (C) Copyright Eric Niebler 2005. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include +#include + +#ifdef BOOST_FOREACH_NO_RVALUE_DETECTION +# error Expected failure : rvalues disallowed +#else + +std::vector get_vector() +{ + return std::vector(4, 4); +} + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + int counter = 0; + + BOOST_REVERSE_FOREACH(int i, get_vector()) + { + counter += i; + } + + BOOST_CHECK(16 == counter); + + return 0; +} + +#endif diff --git a/test/stl_byref_r.cpp b/test/stl_byref_r.cpp new file mode 100755 index 0000000..6febdfb --- /dev/null +++ b/test/stl_byref_r.cpp @@ -0,0 +1,62 @@ +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005: Initial version. +*/ + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef std::list foreach_container_type; +typedef std::list const foreach_const_container_type; +typedef int foreach_value_type; +typedef int &foreach_reference_type; +typedef int const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// initialize a std::list +std::list make_list() +{ + std::list l; + l.push_back(1); + l.push_back(2); + l.push_back(3); + l.push_back(4); + l.push_back(5); + return l; +} + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +std::list my_list = make_list(); +std::list const &my_const_list = my_list; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + // non-const containers by reference + BOOST_CHECK(sequence_equal_byref_n_r(my_list, "\5\4\3\2\1")); + + // const containers by reference + BOOST_CHECK(sequence_equal_byref_c_r(my_const_list, "\5\4\3\2\1")); + + // mutate the mutable collections + mutate_foreach_byref_r(my_list); + + // compare the mutated collections to the actual results + BOOST_CHECK(sequence_equal_byref_n_r(my_list, "\6\5\4\3\2")); + + return 0; +} diff --git a/test/stl_byval_r.cpp b/test/stl_byval_r.cpp new file mode 100755 index 0000000..5cc7e47 --- /dev/null +++ b/test/stl_byval_r.cpp @@ -0,0 +1,60 @@ +// stl_byval.cpp +/// +// (C) Copyright Eric Niebler 2004. +// Use, modification and distribution are subject to the +// Boost Software License, Version 1.0. (See accompanying file +// LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +/* + Revision history: + 25 August 2005 : Initial version. +*/ + +#include +#include +#include + +/////////////////////////////////////////////////////////////////////////////// +// define the container types, used by utility.hpp to generate the helper functions +typedef std::list foreach_container_type; +typedef std::list const foreach_const_container_type; +typedef int foreach_value_type; +typedef int &foreach_reference_type; +typedef int const &foreach_const_reference_type; + +#include "./utility.hpp" + +/////////////////////////////////////////////////////////////////////////////// +// initialize a std::list +std::list make_list() +{ + std::list l; + l.push_back(1); + l.push_back(2); + l.push_back(3); + l.push_back(4); + l.push_back(5); + return l; +} + +/////////////////////////////////////////////////////////////////////////////// +// define some containers +// +std::list my_list = make_list(); +std::list const &my_const_list = my_list; + +/////////////////////////////////////////////////////////////////////////////// +// test_main +// +int test_main( int, char*[] ) +{ + boost::mpl::false_ *p = BOOST_FOREACH_IS_LIGHTWEIGHT_PROXY(my_list); + + // non-const containers by value + BOOST_CHECK(sequence_equal_byval_n_r(my_list, "\5\4\3\2\1")); + + // const containers by value + BOOST_CHECK(sequence_equal_byval_c_r(my_const_list, "\5\4\3\2\1")); + + return 0; +} diff --git a/test/utility.hpp b/test/utility.hpp index ba6ab18..40e64f8 100755 --- a/test/utility.hpp +++ b/test/utility.hpp @@ -76,4 +76,68 @@ inline void mutate_foreach_byref( foreach_container_type & rng ) } } + +/////////////////////////////////////////////////////////////////////////////// +// sequence_equal_byval_n_r +inline bool sequence_equal_byval_n_r( foreach_container_type & rng, char const * result ) +{ + BOOST_REVERSE_FOREACH( foreach_value_type i, rng ) + { + if(0 == *result || i != *result) + return false; + ++result; + } + return 0 == *result; +} + +/////////////////////////////////////////////////////////////////////////////// +// sequence_equal_byval_c_r +inline bool sequence_equal_byval_c_r( foreach_const_container_type & rng, char const * result ) +{ + BOOST_REVERSE_FOREACH( foreach_value_type i, rng ) + { + if(0 == *result || i != *result) + return false; + ++result; + } + return 0 == *result; +} + +/////////////////////////////////////////////////////////////////////////////// +// sequence_equal_byref_n_r +inline bool sequence_equal_byref_n_r( foreach_container_type & rng, char const * result ) +{ + BOOST_REVERSE_FOREACH( foreach_reference_type i, rng ) + { + if(0 == *result || i != *result) + return false; + ++result; + } + return 0 == *result; +} + +/////////////////////////////////////////////////////////////////////////////// +// sequence_equal_byref_c_r +inline bool sequence_equal_byref_c_r( foreach_const_container_type & rng, char const * result ) +{ + BOOST_REVERSE_FOREACH( foreach_const_reference_type i, rng ) + { + if(0 == *result || i != *result) + return false; + ++result; + } + return 0 == *result; +} + +/////////////////////////////////////////////////////////////////////////////// +// mutate_foreach_byref +// +inline void mutate_foreach_byref_r( foreach_container_type & rng ) +{ + BOOST_REVERSE_FOREACH( foreach_reference_type i, rng ) + { + ++i; + } +} + #endif