Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r74584 - in trunk: boost libs/foreach/test status
From: eric_at_[hidden]
Date: 2011-09-26 14:10:47


Author: eric_niebler
Date: 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
New Revision: 74584
URL: http://svn.boost.org/trac/boost/changeset/74584

Log:
support for noncopyable rvalue ranges using C++0x
Added:
   trunk/libs/foreach/test/noncopyable_rvalue_const.cpp (contents, props changed)
   trunk/libs/foreach/test/noncopyable_rvalue_const_r.cpp (contents, props changed)
   trunk/libs/foreach/test/noncopyable_rvalue_nonconst.cpp (contents, props changed)
   trunk/libs/foreach/test/noncopyable_rvalue_nonconst_r.cpp (contents, props changed)
Text files modified:
   trunk/boost/foreach.hpp | 205 +++++++++++++++++++++++++++++++++++++++
   trunk/libs/foreach/test/Jamfile.v2 | 6
   trunk/status/explicit-failures-markup.xml | 14 ++
   3 files changed, 219 insertions(+), 6 deletions(-)

Modified: trunk/boost/foreach.hpp
==============================================================================
--- trunk/boost/foreach.hpp (original)
+++ trunk/boost/foreach.hpp 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -30,8 +30,13 @@
 #include <boost/config.hpp>
 #include <boost/detail/workaround.hpp>
 
+// Some compilers support rvalue references and auto type deduction.
+// With these C++0x features, temporary collections can be bound to
+// rvalue references and their lifetime is extended. No copy/move is needed.
+#if !defined(BOOST_NO_DECLTYPE) && !defined(BOOST_NO_RVALUE_REFERENCES)
+# define BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
 // Some compilers let us detect even const-qualified rvalues at compile-time
-#if !defined(BOOST_NO_RVALUE_REFERENCES) \
+#elif !defined(BOOST_NO_RVALUE_REFERENCES) \
  || BOOST_WORKAROUND(BOOST_MSVC, >= 1310) && !defined(_PREFAST_) \
  || (BOOST_WORKAROUND(__GNUC__, == 4) && (__GNUC_MINOR__ <= 5) && !defined(BOOST_INTEL) && \
                                                                   !defined(BOOST_CLANG)) \
@@ -88,11 +93,16 @@
 #include <boost/utility/addressof.hpp>
 #include <boost/foreach_fwd.hpp>
 
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# include <boost/type_traits/decay.hpp>
+# include <boost/type_traits/remove_const.hpp>
+# include <boost/type_traits/remove_cv.hpp>
+#endif
+
 #ifdef BOOST_FOREACH_RUN_TIME_CONST_RVALUE_DETECTION
 # include <new>
 # include <boost/aligned_storage.hpp>
 # include <boost/utility/enable_if.hpp>
-# include <boost/type_traits/remove_const.hpp>
 #endif
 
 namespace boost
@@ -689,6 +699,29 @@
 }
 #endif
 
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+template<typename T>
+inline typename foreach_iterator<typename remove_const<T>::type, is_const<T> >::type
+begin(T &col)
+{
+ return boost::begin(col);
+}
+
+template<typename T>
+inline T *
+begin(T *&col)
+{
+ return col;
+}
+
+template<typename T>
+inline T *
+begin(T * const &col)
+{
+ return col;
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // end
 //
@@ -729,6 +762,33 @@
 }
 #endif
 
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+template<typename T>
+inline typename foreach_iterator<typename remove_const<T>::type, is_const<T> >::type
+end(T &col)
+{
+ return boost::end(col);
+}
+
+struct cstr_end_iterator
+{
+};
+
+template<typename T>
+inline cstr_end_iterator
+end(T *&col)
+{
+ return cstr_end_iterator();
+}
+
+template<typename T>
+inline cstr_end_iterator
+end(T * const &col)
+{
+ return cstr_end_iterator();
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // done
 //
@@ -747,6 +807,15 @@
 }
 #endif
 
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+template<typename Iterator>
+inline bool operator !=(Iterator cur, cstr_end_iterator)
+{
+ return *cur != 0;
+}
+#endif
+
+
 ///////////////////////////////////////////////////////////////////////////////
 // next
 //
@@ -811,6 +880,35 @@
 }
 #endif
 
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+template<typename T>
+inline typename foreach_reverse_iterator<typename remove_const<T>::type, is_const<T> >::type
+rbegin(T &col)
+{
+ return boost::rbegin(col);
+}
+
+template<typename T>
+inline reverse_iterator<T *>
+rbegin(T *&col)
+{
+ T *p = col;
+ while(0 != *p)
+ ++p;
+ return reverse_iterator<T *>(p);
+}
+
+template<typename T>
+inline reverse_iterator<T *>
+rbegin(T * const &col)
+{
+ T *p = col;
+ while(0 != *p)
+ ++p;
+ return reverse_iterator<T *>(p);
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // rend
 //
@@ -852,6 +950,29 @@
 }
 #endif
 
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+template<typename T>
+inline typename foreach_reverse_iterator<typename remove_const<T>::type, is_const<T> >::type
+rend(T &col)
+{
+ return boost::rend(col);
+}
+
+template<typename T>
+inline reverse_iterator<T *>
+rend(T *&col)
+{
+ return reverse_iterator<T *>(col);
+}
+
+template<typename T>
+inline reverse_iterator<T *>
+rend(T * const &col)
+{
+ return reverse_iterator<T *>(col);
+}
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 // rdone
 //
@@ -922,10 +1043,40 @@
             boost::foreach_detail_::to_ptr(COL) \
           , boost_foreach_argument_dependent_lookup_hack_value))
 
-#if defined(BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION)
+///////////////////////////////////////////////////////////////////////////////
+// R-values and const R-values are bound to rvalue references
+///////////////////////////////////////////////////////////////////////////////
+#if defined(BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING)
+# define BOOST_FOREACH_PREAMBLE() \
+ BOOST_FOREACH_SUPPRESS_WARNINGS()
+
+namespace boost { namespace foreach_detail_
+{
+ template<typename T>
+ typename remove_cv<typename decay<T>::type>::type decay_copy(T &&);
+
+ template<typename T>
+ T const add_const_if_rvalue(T &&);
+}}
+# define BOOST_FOREACH_AUTO_OBJECT(NAME, EXPR) \
+ if (bool BOOST_PP_CAT(NAME, _defined) = false) {} else \
+ for (decltype(boost::foreach_detail_::decay_copy(EXPR)) NAME = (EXPR); \
+ !BOOST_PP_CAT(NAME, _defined); BOOST_PP_CAT(NAME, _defined) = true)
+
+// If EXPR is an rvalue, bind it to a const rvalue reference.
+# define BOOST_FOREACH_AUTO_REF_REF(NAME, EXPR) \
+ if (bool BOOST_PP_CAT(NAME, _defined) = false) {} else \
+ for (decltype(boost::foreach_detail_::add_const_if_rvalue(EXPR)) &&NAME = (EXPR); \
+ !BOOST_PP_CAT(NAME, _defined); BOOST_PP_CAT(NAME, _defined) = true)
+
+#elif defined(BOOST_FOREACH_COMPILE_TIME_CONST_RVALUE_DETECTION)
 ///////////////////////////////////////////////////////////////////////////////
 // R-values and const R-values supported here with zero runtime overhead
 ///////////////////////////////////////////////////////////////////////////////
+# define BOOST_FOREACH_PREAMBLE() \
+ BOOST_FOREACH_SUPPRESS_WARNINGS()
+
+
 
 // No variable is needed to track the rvalue-ness of the collection expression
 # define BOOST_FOREACH_PREAMBLE() \
@@ -1092,7 +1243,28 @@
 // BOOST_FOREACH(i, int_list)
 // { ... }
 //
-#define BOOST_FOREACH(VAR, COL) \
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# define BOOST_FOREACH(VAR, COL) \
+ BOOST_FOREACH_PREAMBLE() \
+ BOOST_FOREACH_AUTO_REF_REF( \
+ BOOST_FOREACH_ID(_foreach_col) \
+ , COL) \
+ BOOST_FOREACH_AUTO_OBJECT( \
+ BOOST_FOREACH_ID(_foreach_cur) \
+ , boost::foreach_detail_::begin(BOOST_FOREACH_ID(_foreach_col))) \
+ BOOST_FOREACH_AUTO_OBJECT( \
+ BOOST_FOREACH_ID(_foreach_end) \
+ , boost::foreach_detail_::end(BOOST_FOREACH_ID(_foreach_col))) \
+ for (bool BOOST_FOREACH_ID(_foreach_continue) = true; \
+ BOOST_FOREACH_ID(_foreach_continue) \
+ && BOOST_FOREACH_ID(_foreach_cur) != BOOST_FOREACH_ID(_foreach_end); \
+ BOOST_FOREACH_ID(_foreach_continue) \
+ ? (void)++BOOST_FOREACH_ID(_foreach_cur) : (void)0) \
+ if ( (BOOST_FOREACH_ID(_foreach_continue) = false) ) {} else \
+ for (VAR = *BOOST_FOREACH_ID(_foreach_cur); \
+ !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true)
+#else
+# define BOOST_FOREACH(VAR, COL) \
     BOOST_FOREACH_PREAMBLE() \
     if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) = BOOST_FOREACH_CONTAIN(COL)) {} else \
     if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_BEGIN(COL)) {} else \
@@ -1102,6 +1274,7 @@
               BOOST_FOREACH_ID(_foreach_continue) ? BOOST_FOREACH_NEXT(COL) : (void)0) \
         if (boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue))) {} else \
         for (VAR = BOOST_FOREACH_DEREF(COL); !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true)
+#endif
 
 ///////////////////////////////////////////////////////////////////////////////
 // BOOST_REVERSE_FOREACH
@@ -1110,7 +1283,28 @@
 // all other respects, BOOST_REVERSE_FOREACH is like
 // BOOST_FOREACH.
 //
-#define BOOST_REVERSE_FOREACH(VAR, COL) \
+#ifdef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# define BOOST_REVERSE_FOREACH(VAR, COL) \
+ BOOST_FOREACH_PREAMBLE() \
+ BOOST_FOREACH_AUTO_REF_REF( \
+ BOOST_FOREACH_ID(_foreach_col) \
+ , COL) \
+ BOOST_FOREACH_AUTO_OBJECT( \
+ BOOST_FOREACH_ID(_foreach_cur) \
+ , boost::foreach_detail_::rbegin(BOOST_FOREACH_ID(_foreach_col))) \
+ BOOST_FOREACH_AUTO_OBJECT( \
+ BOOST_FOREACH_ID(_foreach_end) \
+ , boost::foreach_detail_::rend(BOOST_FOREACH_ID(_foreach_col))) \
+ for (bool BOOST_FOREACH_ID(_foreach_continue) = true; \
+ BOOST_FOREACH_ID(_foreach_continue) \
+ && BOOST_FOREACH_ID(_foreach_cur) != BOOST_FOREACH_ID(_foreach_end); \
+ BOOST_FOREACH_ID(_foreach_continue) \
+ ? (void)++BOOST_FOREACH_ID(_foreach_cur) : (void)0) \
+ if ( (BOOST_FOREACH_ID(_foreach_continue) = false) ) {} else \
+ for (VAR = *BOOST_FOREACH_ID(_foreach_cur); \
+ !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true)
+#else
+# define BOOST_REVERSE_FOREACH(VAR, COL) \
     BOOST_FOREACH_PREAMBLE() \
     if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_col) = BOOST_FOREACH_CONTAIN(COL)) {} else \
     if (boost::foreach_detail_::auto_any_t BOOST_FOREACH_ID(_foreach_cur) = BOOST_FOREACH_RBEGIN(COL)) {} else \
@@ -1120,5 +1314,6 @@
               BOOST_FOREACH_ID(_foreach_continue) ? BOOST_FOREACH_RNEXT(COL) : (void)0) \
         if (boost::foreach_detail_::set_false(BOOST_FOREACH_ID(_foreach_continue))) {} else \
         for (VAR = BOOST_FOREACH_RDEREF(COL); !BOOST_FOREACH_ID(_foreach_continue); BOOST_FOREACH_ID(_foreach_continue) = true)
+#endif
 
 #endif

Modified: trunk/libs/foreach/test/Jamfile.v2
==============================================================================
--- trunk/libs/foreach/test/Jamfile.v2 (original)
+++ trunk/libs/foreach/test/Jamfile.v2 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -5,7 +5,7 @@
 # bring in rules for testing
 import testing ;
 
-project : requirements <toolset>msvc:<asynch-exceptions>on ;
+project : requirements <toolset>msvc:<asynch-exceptions>on <toolset>gcc:<cxxflags>-Wconversion ;
 
 test-suite "foreach"
     : [ run stl_byval.cpp ]
@@ -32,5 +32,9 @@
       [ run rvalue_nonconst_r.cpp ]
       [ run dependent_type.cpp ]
       [ run misc.cpp ]
+ [ run noncopyable_rvalue_const.cpp ]
+ [ run noncopyable_rvalue_nonconst.cpp ]
+ [ run noncopyable_rvalue_const_r.cpp ]
+ [ run noncopyable_rvalue_nonconst_r.cpp ]
       [ compile noncopyable.cpp ]
     ;

Added: trunk/libs/foreach/test/noncopyable_rvalue_const.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/foreach/test/noncopyable_rvalue_const.cpp 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -0,0 +1,70 @@
+// (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 <boost/test/minimal.hpp>
+#include <boost/foreach.hpp>
+
+#ifndef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# error Expected failure : non-copyable rvalues disallowed
+#else
+
+class my_container
+{
+public:
+ my_container()
+ {
+ array_[0] = 1;
+ array_[1] = 2;
+ array_[2] = 3;
+ array_[3] = 4;
+ array_[4] = 5;
+ }
+
+ typedef int* iterator;
+ typedef int const* const_iterator;
+
+ iterator begin() { return array_; }
+ const_iterator begin() const { return array_; }
+
+ iterator end() { return array_ + 5; }
+ const_iterator end() const { return array_ + 5; }
+
+private:
+ int array_[5];
+
+ // non-copyable
+ my_container(my_container const &);
+ my_container &operator =(my_container const &);
+
+ // non-movable
+ my_container(my_container &&);
+ my_container &operator =(my_container &&);
+};
+
+typedef my_container const const_my_container;
+
+///////////////////////////////////////////////////////////////////////////////
+// test_main
+//
+int test_main( int, char*[] )
+{
+ int counter = 0;
+
+ BOOST_FOREACH(int i, const_my_container())
+ {
+ counter += i;
+ }
+
+ BOOST_CHECK(15 == counter);
+
+ return 0;
+}
+
+#endif

Added: trunk/libs/foreach/test/noncopyable_rvalue_const_r.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/foreach/test/noncopyable_rvalue_const_r.cpp 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -0,0 +1,70 @@
+// (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 <boost/test/minimal.hpp>
+#include <boost/foreach.hpp>
+
+#ifndef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# error Expected failure : non-copyable rvalues disallowed
+#else
+
+class my_container
+{
+public:
+ my_container()
+ {
+ array_[0] = 1;
+ array_[1] = 2;
+ array_[2] = 3;
+ array_[3] = 4;
+ array_[4] = 5;
+ }
+
+ typedef int* iterator;
+ typedef int const* const_iterator;
+
+ iterator begin() { return array_; }
+ const_iterator begin() const { return array_; }
+
+ iterator end() { return array_ + 5; }
+ const_iterator end() const { return array_ + 5; }
+
+private:
+ int array_[5];
+
+ // non-copyable
+ my_container(my_container const &);
+ my_container &operator =(my_container const &);
+
+ // non-movable
+ my_container(my_container &&);
+ my_container &operator =(my_container &&);
+};
+
+typedef my_container const const_my_container;
+
+///////////////////////////////////////////////////////////////////////////////
+// test_main
+//
+int test_main( int, char*[] )
+{
+ int counter = 0;
+
+ BOOST_REVERSE_FOREACH(int i, const_my_container())
+ {
+ counter += i;
+ }
+
+ BOOST_CHECK(15 == counter);
+
+ return 0;
+}
+
+#endif

Added: trunk/libs/foreach/test/noncopyable_rvalue_nonconst.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/foreach/test/noncopyable_rvalue_nonconst.cpp 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -0,0 +1,68 @@
+// (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 <boost/test/minimal.hpp>
+#include <boost/foreach.hpp>
+
+#ifndef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# error Expected failure : non-copyable rvalues disallowed
+#else
+
+class my_container
+{
+public:
+ my_container()
+ {
+ array_[0] = 1;
+ array_[1] = 2;
+ array_[2] = 3;
+ array_[3] = 4;
+ array_[4] = 5;
+ }
+
+ typedef int* iterator;
+ typedef int const* const_iterator;
+
+ iterator begin() { return array_; }
+ const_iterator begin() const { return array_; }
+
+ iterator end() { return array_ + 5; }
+ const_iterator end() const { return array_ + 5; }
+
+private:
+ int array_[5];
+
+ // non-copyable
+ my_container(my_container const &);
+ my_container &operator =(my_container const &);
+
+ // non-movable
+ my_container(my_container &&);
+ my_container &operator =(my_container &&);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// test_main
+//
+int test_main( int, char*[] )
+{
+ int counter = 0;
+
+ BOOST_REVERSE_FOREACH(int i, my_container())
+ {
+ counter += i;
+ }
+
+ BOOST_CHECK(15 == counter);
+
+ return 0;
+}
+
+#endif

Added: trunk/libs/foreach/test/noncopyable_rvalue_nonconst_r.cpp
==============================================================================
--- (empty file)
+++ trunk/libs/foreach/test/noncopyable_rvalue_nonconst_r.cpp 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -0,0 +1,68 @@
+// (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 <boost/test/minimal.hpp>
+#include <boost/foreach.hpp>
+
+#ifndef BOOST_FOREACH_USE_RVALUE_REFERENCE_BINDING
+# error Expected failure : non-copyable rvalues disallowed
+#else
+
+class my_container
+{
+public:
+ my_container()
+ {
+ array_[0] = 1;
+ array_[1] = 2;
+ array_[2] = 3;
+ array_[3] = 4;
+ array_[4] = 5;
+ }
+
+ typedef int* iterator;
+ typedef int const* const_iterator;
+
+ iterator begin() { return array_; }
+ const_iterator begin() const { return array_; }
+
+ iterator end() { return array_ + 5; }
+ const_iterator end() const { return array_ + 5; }
+
+private:
+ int array_[5];
+
+ // non-copyable
+ my_container(my_container const &);
+ my_container &operator =(my_container const &);
+
+ // non-movable
+ my_container(my_container &&);
+ my_container &operator =(my_container &&);
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// test_main
+//
+int test_main( int, char*[] )
+{
+ int counter = 0;
+
+ BOOST_REVERSE_FOREACH(int i, my_container())
+ {
+ counter += i;
+ }
+
+ BOOST_CHECK(15 == counter);
+
+ return 0;
+}
+
+#endif

Modified: trunk/status/explicit-failures-markup.xml
==============================================================================
--- trunk/status/explicit-failures-markup.xml (original)
+++ trunk/status/explicit-failures-markup.xml 2011-09-26 14:10:45 EDT (Mon, 26 Sep 2011)
@@ -1706,6 +1706,16 @@
                 ADL which these compilers do not support.
             </note>
         </mark-expected-failures>
+
+ <mark-expected-failures>
+ <test name="noncopyable_rvalue_const"/>
+ <test name="noncopyable_rvalue_const_r"/>
+ <test name="noncopyable_rvalue_nonconst"/>
+ <test name="noncopyable_rvalue_nonconst_r"/>
+ <toolset name="*"/>
+ <note refid="50" author="Eric Niebler"/>
+ </mark-expected-failures>
+
     </library>
 
     <!-- format -->
@@ -6695,5 +6705,9 @@
         This test fails because MinGW apparently does not always catch exceptions properly.
     </note>
 
+ <note id="50">
+ This test requires C++0x support.
+ </note>
+
 </explicit-failures-markup>
 


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk