|
Boost-Commit : |
Subject: [Boost-commit] svn:boost r61557 - in sandbox/move/libs: container container/doc container/doc/html container/proj container/test move move/doc move/doc/html move/example move/proj/vc7ide move/test
From: igaztanaga_at_[hidden]
Date: 2010-04-25 08:34:46
Author: igaztanaga
Date: 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
New Revision: 61557
URL: http://svn.boost.org/trac/boost/changeset/61557
Log:
Boost.Move review version
Added:
sandbox/move/libs/move/example/copymovable.hpp (contents, props changed)
sandbox/move/libs/move/example/doc_how_works.cpp (contents, props changed)
sandbox/move/libs/move/proj/vc7ide/copy_elision_test.vcproj (contents, props changed)
sandbox/move/libs/move/proj/vc7ide/doc_how_works.vcproj (contents, props changed)
sandbox/move/libs/move/test/copy_elision_test.cpp (contents, props changed)
Removed:
sandbox/move/libs/container/doc/html/
sandbox/move/libs/move/doc/html/
sandbox/move/libs/move/index.html
sandbox/move/libs/move/proj/vc7ide/todo.txt
Text files modified:
sandbox/move/libs/container/doc/Jamfile.v2 | 3
sandbox/move/libs/container/doc/container.qbk | 10
sandbox/move/libs/container/index.html | 4
sandbox/move/libs/container/proj/to-do.txt | 3
sandbox/move/libs/container/test/deque_test.cpp | 23 ++
sandbox/move/libs/container/test/flat_tree_test.cpp | 151 +++++++++++------
sandbox/move/libs/container/test/list_test.cpp | 16 +
sandbox/move/libs/container/test/list_test.hpp | 76 ++++++++
sandbox/move/libs/container/test/movable_int.hpp | 52 ++++++
sandbox/move/libs/container/test/set_test.hpp | 4
sandbox/move/libs/container/test/slist_test.cpp | 13 +
sandbox/move/libs/container/test/stable_vector_test.cpp | 12 +
sandbox/move/libs/container/test/tree_test.cpp | 55 +++++
sandbox/move/libs/container/test/vector_test.cpp | 66 +++++++
sandbox/move/libs/container/test/vector_test.hpp | 32 ++
sandbox/move/libs/move/doc/move.qbk | 326 +++++++++++++++++++++++++++++++++++++++
sandbox/move/libs/move/example/doc_clone_ptr.cpp | 14
sandbox/move/libs/move/example/doc_construct_forward.cpp | 94 +++++-----
sandbox/move/libs/move/example/movable.hpp | 10 +
sandbox/move/libs/move/proj/vc7ide/Move.sln | 25 ++
sandbox/move/libs/move/test/construct_forward.cpp | 73 ++++++++
sandbox/move/libs/move/test/copy_move_optimization.cpp | 24 ++
sandbox/move/libs/move/test/move.cpp | 7
sandbox/move/libs/move/test/move_iterator.cpp | 52 ++++++
24 files changed, 968 insertions(+), 177 deletions(-)
Modified: sandbox/move/libs/container/doc/Jamfile.v2
==============================================================================
--- sandbox/move/libs/container/doc/Jamfile.v2 (original)
+++ sandbox/move/libs/container/doc/Jamfile.v2 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -20,7 +20,8 @@
<doxygen:param>ENABLE_PREPROCESSING=YES
<doxygen:param>EXPAND_ONLY_PREDEF=YES
<doxygen:param>MACRO_EXPANSION=YES
- <doxygen:param>"PREDEFINED=\"BOOST_CONTAINER_DOXYGEN_INVOKED\" \\
+ <doxygen:param>"PREDEFINED=\"insert_const_ref_type= const T&\" \\
+ \"BOOST_CONTAINER_DOXYGEN_INVOKED\" \\
\"BOOST_ENABLE_MOVE_EMULATION(a)= \" \\
\"BOOST_RV_REF(T)=T &&\" \\
\"BOOST_COPY_ASSIGN_REF(T)=const T &\" \\
Modified: sandbox/move/libs/container/doc/container.qbk
==============================================================================
--- sandbox/move/libs/container/doc/container.qbk (original)
+++ sandbox/move/libs/container/doc/container.qbk 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -1,14 +1,14 @@
[/
- / Copyright (c) 2009-2009 Ion Gaztanaga
+ / Copyright (c) 2009-2010 Ion Gaztanaga
/
/ Distributed under 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)
/]
[library Boost.Container
- [quickbook 1.3]
- [authors [Gaztañaga, Ion]]
- [copyright 2009-2009 Ion Gaztañaga]
+ [quickbook 1.4]
+ [authors [Gaztanaga, Ion]]
+ [copyright 2009-2010 Ion Gaztanaga]
[id container]
[dirname container]
[purpose Containers library]
@@ -115,7 +115,7 @@
[section:other_features Other features]
* Default constructors don't allocate memory which improves performance and
- usually implies a no-throw guarantee (if predicate's default constructor doesn't throw).
+ usually implies a no-throw guarantee (if predicate's or allocator's default constructor doesn't throw).
* Small string optimization for [classref boost::container::basic_string basic_string],
with an internal buffer of 11/23 bytes (32/64 bit systems)
Modified: sandbox/move/libs/container/index.html
==============================================================================
--- sandbox/move/libs/container/index.html (original)
+++ sandbox/move/libs/container/index.html 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -5,10 +5,10 @@
-->
<html>
<head>
-<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
+<meta http-equiv="refresh" content="0; URL=../../doc/html/container.html">
</head>
<body>
Automatic redirection failed, please go to
-doc/html/index.html
+../../doc/html/container.html
</body>
</html>
Modified: sandbox/move/libs/container/proj/to-do.txt
==============================================================================
--- sandbox/move/libs/container/proj/to-do.txt (original)
+++ sandbox/move/libs/container/proj/to-do.txt 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -1 +1,2 @@
-
+->Change "insert" and "push_back"/"push_front" to catch non-const rvalues
+->Add an example with stateful allocators
Modified: sandbox/move/libs/container/test/deque_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/deque_test.cpp (original)
+++ sandbox/move/libs/container/test/deque_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -26,6 +26,7 @@
#include <boost/container/detail/type_traits.hpp>
#include <string>
#include "emplace_test.hpp"
+#include "vector_test.hpp"
using namespace boost::container;
@@ -37,14 +38,14 @@
//Function to check if both sets are equal
template<class V1, class V2>
-bool copyable_only(V1 *, V2 *, containers_detail::false_type)
+bool deque_copyable_only(V1 *, V2 *, containers_detail::false_type)
{
return true;
}
//Function to check if both sets are equal
template<class V1, class V2>
-bool copyable_only(V1 *cntdeque, V2 *stddeque, containers_detail::true_type)
+bool deque_copyable_only(V1 *cntdeque, V2 *stddeque, containers_detail::true_type)
{
typedef typename V1::value_type IntType;
std::size_t size = cntdeque->size();
@@ -210,7 +211,7 @@
if(!test::CheckEqualContainers(cntdeque, stddeque)) return false;
}
- if(!copyable_only(cntdeque, stddeque
+ if(!deque_copyable_only(cntdeque, stddeque
,containers_detail::bool_<!boost::is_movable<IntType>::value>())){
return false;
}
@@ -266,8 +267,20 @@
if(!do_test<test::movable_int>())
return 1;
-// if(!do_test<int, test::allocator_v1>())
-// return 1;
+ {
+ typedef deque<int> MyDeque;
+ typedef deque<test::movable_int> MyMoveDeque;
+ typedef deque<test::movable_and_copyable_int> MyCopyMoveDeque;
+ typedef deque<test::copyable_int> MyCopyDeque;
+ if(test::vector_test<MyDeque>())
+ return 1;
+ if(test::vector_test<MyMoveDeque>())
+ return 1;
+ if(test::vector_test<MyCopyMoveDeque>())
+ return 1;
+ if(test::vector_test<MyCopyDeque>())
+ return 1;
+ }
const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE);
Modified: sandbox/move/libs/container/test/flat_tree_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/flat_tree_test.cpp (original)
+++ sandbox/move/libs/container/test/flat_tree_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -19,53 +19,25 @@
#include "map_test.hpp"
#include "emplace_test.hpp"
-/////////////////////////////////////////////////////////////////
-//
-// This example repeats the same operations with std::set and
-// shmem_set using the node allocator
-// and compares the values of both containers
-//
-/////////////////////////////////////////////////////////////////
-
using namespace boost::container;
-/*
-//Explicit instantiation to detect compilation errors
-template class boost::container::flat_set
- <test::movable_and_copyable_int
- ,std::less<test::movable_and_copyable_int>
- ,test::dummy_test_allocator<test::movable_and_copyable_int> >;
-
-template class boost::container::flat_map
- <test::movable_and_copyable_int
- ,test::movable_and_copyable_int
- ,std::less<test::movable_and_copyable_int>
- ,test::dummy_test_allocator<std::pair<test::movable_and_copyable_int
- ,test::movable_and_copyable_int> > >;
-
-template class boost::container::flat_multiset
- <test::movable_and_copyable_int
- ,std::less<test::movable_and_copyable_int>
- ,test::dummy_test_allocator<test::movable_and_copyable_int> >;
-
-template class boost::container::flat_multimap
- <test::movable_and_copyable_int
- ,test::movable_and_copyable_int
- ,std::less<test::movable_and_copyable_int>
- ,test::dummy_test_allocator<std::pair<test::movable_and_copyable_int
- ,test::movable_and_copyable_int> > >;
-*/
+
//Alias allocator type
-typedef std::allocator<int> shmem_allocator_t;
+typedef std::allocator<int> allocator_t;
typedef std::allocator<test::movable_int>
- shmem_movable_allocator_t;
+ movable_allocator_t;
typedef std::allocator<std::pair<int, int> >
- shmem_pair_allocator_t;
+ pair_allocator_t;
typedef std::allocator<std::pair<test::movable_int, test::movable_int> >
- shmem_movable_pair_allocator_t;
+ movable_pair_allocator_t;
typedef std::allocator<test::movable_and_copyable_int >
- shmem_move_copy_allocator_t;
+ move_copy_allocator_t;
typedef std::allocator<std::pair<test::movable_and_copyable_int, test::movable_and_copyable_int> >
- shmem_move_copy_pair_allocator_t;
+ move_copy_pair_allocator_t;
+typedef std::allocator<test::copyable_int >
+ copy_allocator_t;
+typedef std::allocator<std::pair<test::copyable_int, test::copyable_int> >
+ copy_pair_allocator_t;
+
//Alias set types
typedef std::set<int> MyStdSet;
@@ -73,32 +45,45 @@
typedef std::map<int, int> MyStdMap;
typedef std::multimap<int, int> MyStdMultiMap;
-typedef flat_set<int, std::less<int>, shmem_allocator_t> MyShmSet;
-typedef flat_multiset<int, std::less<int>, shmem_allocator_t> MyShmMultiSet;
-typedef flat_map<int, int, std::less<int>, shmem_pair_allocator_t> MyShmMap;
-typedef flat_multimap<int, int, std::less<int>, shmem_pair_allocator_t> MyShmMultiMap;
+typedef flat_set<int, std::less<int>, allocator_t> MyShmSet;
+typedef flat_multiset<int, std::less<int>, allocator_t> MyShmMultiSet;
+typedef flat_map<int, int, std::less<int>, pair_allocator_t> MyShmMap;
+typedef flat_multimap<int, int, std::less<int>, pair_allocator_t> MyShmMultiMap;
typedef flat_set<test::movable_int, std::less<test::movable_int>
- ,shmem_movable_allocator_t> MyMovableShmSet;
+ ,movable_allocator_t> MyMovableShmSet;
typedef flat_multiset<test::movable_int,std::less<test::movable_int>
- ,shmem_movable_allocator_t> MyMovableShmMultiSet;
+ ,movable_allocator_t> MyMovableShmMultiSet;
typedef flat_map<test::movable_int, test::movable_int
,std::less<test::movable_int>
- ,shmem_movable_pair_allocator_t> MyMovableShmMap;
+ ,movable_pair_allocator_t> MyMovableShmMap;
typedef flat_multimap<test::movable_int, test::movable_int
,std::less<test::movable_int>
- ,shmem_movable_pair_allocator_t> MyMovableShmMultiMap;
+ ,movable_pair_allocator_t> MyMovableShmMultiMap;
typedef flat_set<test::movable_and_copyable_int, std::less<test::movable_and_copyable_int>
- ,shmem_move_copy_allocator_t> MyMoveCopyShmSet;
+ ,move_copy_allocator_t> MyMoveCopyShmSet;
typedef flat_multiset<test::movable_and_copyable_int,std::less<test::movable_and_copyable_int>
- ,shmem_move_copy_allocator_t> MyMoveCopyShmMultiSet;
+ ,move_copy_allocator_t> MyMoveCopyShmMultiSet;
typedef flat_map<test::movable_and_copyable_int, test::movable_and_copyable_int
,std::less<test::movable_and_copyable_int>
- ,shmem_move_copy_pair_allocator_t> MyMoveCopyShmMap;
+ ,move_copy_pair_allocator_t> MyMoveCopyShmMap;
typedef flat_multimap<test::movable_and_copyable_int, test::movable_and_copyable_int
,std::less<test::movable_and_copyable_int>
- ,shmem_move_copy_pair_allocator_t> MyMoveCopyShmMultiMap;
+ ,move_copy_pair_allocator_t> MyMoveCopyShmMultiMap;
+
+typedef flat_set<test::copyable_int, std::less<test::copyable_int>
+ ,copy_allocator_t> MyCopyShmSet;
+typedef flat_multiset<test::copyable_int,std::less<test::copyable_int>
+ ,copy_allocator_t> MyCopyShmMultiSet;
+typedef flat_map<test::copyable_int, test::copyable_int
+ ,std::less<test::copyable_int>
+ ,copy_pair_allocator_t> MyCopyShmMap;
+typedef flat_multimap<test::copyable_int, test::copyable_int
+ ,std::less<test::copyable_int>
+ ,copy_pair_allocator_t> MyCopyShmMultiMap;
+
+
//Test recursive structures
class recursive_flat_set
@@ -120,6 +105,8 @@
{ return a.id_ < b.id_; }
};
+
+
class recursive_flat_map
{
public:
@@ -157,7 +144,7 @@
}
int id_;
flat_multiset<recursive_flat_multiset> flat_set_;
- friend bool operator< (const recursive_flat_multiset &a, const recursive_flat_set &b)
+ friend bool operator< (const recursive_flat_multiset &a, const recursive_flat_multiset &b)
{ return a.id_ < b.id_; }
};
@@ -240,6 +227,33 @@
return 1;
}
+ if (0 != set_test_copyable<
+ MyMoveCopyShmSet
+ ,MyStdSet
+ ,MyMoveCopyShmMultiSet
+ ,MyStdMultiSet>()){
+ std::cout << "Error in set_test<MyShmSet>" << std::endl;
+ return 1;
+ }
+
+ if (0 != set_test<
+ MyCopyShmSet
+ ,MyStdSet
+ ,MyCopyShmMultiSet
+ ,MyStdMultiSet>()){
+ std::cout << "Error in set_test<MyCopyShmSet>" << std::endl;
+ return 1;
+ }
+
+ if (0 != set_test_copyable<
+ MyCopyShmSet
+ ,MyStdSet
+ ,MyCopyShmMultiSet
+ ,MyStdMultiSet>()){
+ std::cout << "Error in set_test<MyShmSet>" << std::endl;
+ return 1;
+ }
+
if (0 != map_test<
MyShmMap
,MyStdMap
@@ -275,11 +289,38 @@
return 1;
}
+ if (0 != map_test_copyable<
+ MyMoveCopyShmMap
+ ,MyStdMap
+ ,MyMoveCopyShmMultiMap
+ ,MyStdMultiMap>()){
+ std::cout << "Error in set_test<MyShmMap>" << std::endl;
+ return 1;
+ }
+
+ if (0 != map_test<
+ MyCopyShmMap
+ ,MyStdMap
+ ,MyCopyShmMultiMap
+ ,MyStdMultiMap>()){
+ std::cout << "Error in set_test<MyCopyShmMap>" << std::endl;
+ return 1;
+ }
+
+ if (0 != map_test_copyable<
+ MyCopyShmMap
+ ,MyStdMap
+ ,MyCopyShmMultiMap
+ ,MyStdMultiMap>()){
+ std::cout << "Error in set_test<MyShmMap>" << std::endl;
+ return 1;
+ }
+
const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC);
const test::EmplaceOptions MapOptions = (test::EmplaceOptions)(test::EMPLACE_HINT_PAIR | test::EMPLACE_ASSOC_PAIR);
- if(!boost::container::test::test_emplace<flat_map<test::EmplaceInt, test::EmplaceInt>, MapOptions>())
- return 1;
+// if(!boost::container::test::test_emplace<flat_map<test::EmplaceInt, test::EmplaceInt>, MapOptions>())
+// return 1;
if(!boost::container::test::test_emplace<flat_multimap<test::EmplaceInt, test::EmplaceInt>, MapOptions>())
return 1;
if(!boost::container::test::test_emplace<flat_set<test::EmplaceInt>, SetOptions>())
Modified: sandbox/move/libs/container/test/list_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/list_test.cpp (original)
+++ sandbox/move/libs/container/test/list_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -22,20 +22,26 @@
test::dummy_test_allocator<test::movable_and_copyable_int> >;
typedef list<int> MyList;
-typedef list<volatile int> MyVolatileList;
typedef list<test::movable_int> MyMoveList;
typedef list<test::movable_and_copyable_int> MyCopyMoveList;
+typedef list<test::copyable_int> MyCopyList;
class recursive_list
{
public:
int id_;
list<recursive_list> list_;
+ recursive_list &operator=(const recursive_list &o)
+ { list_ = o.list_; return *this; }
};
void recursive_list_test()//Test for recursive types
{
- list<recursive_list> recursive_list_list;
+ list<recursive_list> recursive, copy;
+ //Test to test both move emulations
+ if(!copy.size()){
+ copy = recursive;
+ }
}
int main ()
@@ -52,15 +58,15 @@
if(test::list_test<MyList, true>())
return 1;
- if(test::list_test<MyVolatileList, true>())
- return 1;
-
if(test::list_test<MyMoveList, true>())
return 1;
if(test::list_test<MyCopyMoveList, true>())
return 1;
+ if(test::list_test<MyCopyList, true>())
+ return 1;
+
const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_FRONT | test::EMPLACE_BEFORE);
if(!boost::container::test::test_emplace<list<test::EmplaceInt>, Options>())
Modified: sandbox/move/libs/container/test/list_test.hpp
==============================================================================
--- sandbox/move/libs/container/test/list_test.hpp (original)
+++ sandbox/move/libs/container/test/list_test.hpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -25,8 +25,55 @@
namespace container {
namespace test{
+template<class V1, class V2>
+bool list_copyable_only(V1 *, V2 *, boost::container::containers_detail::false_type)
+{
+ return true;
+}
+
+//Function to check if both sets are equal
+template<class V1, class V2>
+bool list_copyable_only(V1 *shmlist, V2 *stdlist, boost::container::containers_detail::true_type)
+{
+ typedef typename V1::value_type IntType;
+ shmlist->insert(shmlist->end(), 50, IntType(1));
+ stdlist->insert(stdlist->end(), 50, 1);
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return false;
+
+ {
+ IntType move_me(1);
+ shmlist->insert(shmlist->begin(), 50, boost::move(move_me));
+ stdlist->insert(stdlist->begin(), 50, 1);
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return false;
+ }
+ {
+ IntType move_me(2);
+ shmlist->assign(shmlist->size()/2, boost::move(move_me));
+ stdlist->assign(stdlist->size()/2, 2);
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return false;
+ }
+ {
+ IntType move_me(3);
+ shmlist->assign(shmlist->size()*3-1, boost::move(move_me));
+ stdlist->assign(stdlist->size()*3-1, 3);
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return false;
+ }
+
+ {
+ IntType copy_me(3);
+ const IntType ccopy_me(3);
+ shmlist->push_front(copy_me);
+ stdlist->push_front(int(3));
+ shmlist->push_front(ccopy_me);
+ stdlist->push_front(int(3));
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return false;
+ }
+
+ return true;
+}
+
template<bool DoublyLinked>
-struct push_data_function
+struct list_push_data_function
{
template<class MyShmList, class MyStdList>
static int execute(int max, MyShmList *shmlist, MyStdList *stdlist)
@@ -36,6 +83,8 @@
IntType move_me(i);
shmlist->push_back(boost::move(move_me));
stdlist->push_back(i);
+ shmlist->push_front(IntType(i));
+ stdlist->push_front(int(i));
}
if(!CheckEqualContainers(shmlist, stdlist))
return 1;
@@ -44,7 +93,7 @@
};
template<>
-struct push_data_function<false>
+struct list_push_data_function<false>
{
template<class MyShmList, class MyStdList>
static int execute(int max, MyShmList *shmlist, MyStdList *stdlist)
@@ -54,6 +103,8 @@
IntType move_me(i);
shmlist->push_front(boost::move(move_me));
stdlist->push_front(i);
+ shmlist->push_front(IntType(i));
+ stdlist->push_front(int(i));
}
if(!CheckEqualContainers(shmlist, stdlist))
return 1;
@@ -62,7 +113,7 @@
};
template<bool DoublyLinked>
-struct pop_back_function
+struct list_pop_back_function
{
template<class MyStdList, class MyShmList>
static int execute(MyShmList *shmlist, MyStdList *stdlist)
@@ -76,7 +127,7 @@
};
template<>
-struct pop_back_function<false>
+struct list_pop_back_function<false>
{
template<class MyStdList, class MyShmList>
static int execute(MyShmList *shmlist, MyStdList *stdlist)
@@ -93,7 +144,7 @@
typedef std::list<int> MyStdList;
typedef typename MyShmList::value_type IntType;
const int max = 100;
- typedef push_data_function<DoublyLinked> push_data_t;
+ typedef list_push_data_function<DoublyLinked> push_data_t;
try{
MyShmList *shmlist = new MyShmList;
@@ -107,7 +158,7 @@
stdlist->erase(stdlist->begin()++);
if(!CheckEqualContainers(shmlist, stdlist)) return 1;
- if(pop_back_function<DoublyLinked>::execute(shmlist, stdlist)){
+ if(list_pop_back_function<DoublyLinked>::execute(shmlist, stdlist)){
return 1;
}
@@ -173,6 +224,14 @@
return 1;
}
+ for(int i = 0; i < max; ++i){
+ IntType new_int(i);
+ shmlist->insert(shmlist->end(), boost::move(new_int));
+ stdlist->insert(stdlist->end(), i);
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return 1;
+ }
+ if(!test::CheckEqualContainers(shmlist, stdlist)) return 1;
+
shmlist->resize(25);
stdlist->resize(25);
shmlist->resize(50);
@@ -228,6 +287,11 @@
if(!CheckEqualContainers(shmlist, stdlist))
return 1;
}
+
+ if(!list_copyable_only(shmlist, stdlist
+ ,containers_detail::bool_<!is_movable<IntType>::value>())){
+ return 1;
+ }
}
delete shmlist;
Modified: sandbox/move/libs/container/test/movable_int.hpp
==============================================================================
--- sandbox/move/libs/container/test/movable_int.hpp (original)
+++ sandbox/move/libs/container/test/movable_int.hpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -140,6 +140,58 @@
return os;
}
+class copyable_int
+{
+ public:
+ copyable_int()
+ : m_int(0)
+ {}
+
+ explicit copyable_int(int a)
+ : m_int(a)
+ {}
+
+ copyable_int(const copyable_int& mmi)
+ : m_int(mmi.m_int)
+ {}
+
+ copyable_int & operator= (int i)
+ { this->m_int = i; return *this; }
+
+ bool operator ==(const copyable_int &mi) const
+ { return this->m_int == mi.m_int; }
+
+ bool operator !=(const copyable_int &mi) const
+ { return this->m_int != mi.m_int; }
+
+ bool operator <(const copyable_int &mi) const
+ { return this->m_int < mi.m_int; }
+
+ bool operator <=(const copyable_int &mi) const
+ { return this->m_int <= mi.m_int; }
+
+ bool operator >=(const copyable_int &mi) const
+ { return this->m_int >= mi.m_int; }
+
+ bool operator >(const copyable_int &mi) const
+ { return this->m_int > mi.m_int; }
+
+ int get_int() const
+ { return m_int; }
+
+ private:
+ int m_int;
+};
+
+template<class E, class T>
+std::basic_ostream<E, T> & operator<<
+ (std::basic_ostream<E, T> & os, copyable_int const & p)
+
+{
+ os << p.get_int();
+ return os;
+}
+
} //namespace test {
} //namespace container {
} //namespace boost {
Modified: sandbox/move/libs/container/test/set_test.hpp
==============================================================================
--- sandbox/move/libs/container/test/set_test.hpp (original)
+++ sandbox/move/libs/container/test/set_test.hpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -124,9 +124,13 @@
IntType move_me(i);
shmset->insert(boost::move(move_me));
stdset->insert(i);
+ shmset->insert(IntType(i));
+ stdset->insert(i);
IntType move_me2(i);
shmmultiset->insert(boost::move(move_me2));
stdmultiset->insert(i);
+ shmmultiset->insert(IntType(i));
+ stdmultiset->insert(i);
}
if(!CheckEqualContainers(shmset, stdset)){
Modified: sandbox/move/libs/container/test/slist_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/slist_test.cpp (original)
+++ sandbox/move/libs/container/test/slist_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -21,15 +21,17 @@
test::dummy_test_allocator<test::movable_and_copyable_int> >;
typedef slist<int> MyList;
-typedef slist<volatile int> MyVolatileList;
typedef slist<test::movable_int> MyMoveList;
typedef slist<test::movable_and_copyable_int> MyCopyMoveList;
+typedef slist<test::copyable_int> MyCopyList;
class recursive_slist
{
public:
int id_;
slist<recursive_slist> slist_;
+ recursive_slist &operator=(const recursive_slist &o)
+ { slist_ = o.slist_; return *this; }
};
void recursive_slist_test()//Test for recursive types
@@ -47,6 +49,13 @@
slist<recursive_slist> move_assign;
move_assign = boost::move(move_ctor);
move_assign.swap(original);
+ {
+ slist<recursive_slist> recursive, copy;
+ //Test to test both move emulations
+ if(!copy.size()){
+ copy = recursive;
+ }
+ }
}
if(test::list_test<MyList, false>())
@@ -58,7 +67,7 @@
if(test::list_test<MyCopyMoveList, false>())
return 1;
- if(test::list_test<MyVolatileList, false>())
+ if(test::list_test<MyCopyList, false>())
return 1;
const test::EmplaceOptions Options = (test::EmplaceOptions)
Modified: sandbox/move/libs/container/test/stable_vector_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/stable_vector_test.cpp (original)
+++ sandbox/move/libs/container/test/stable_vector_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -34,11 +34,17 @@
public:
int id_;
stable_vector<recursive_vector> vector_;
+ recursive_vector &operator=(const recursive_vector &o)
+ { vector_ = o.vector_; return *this; }
};
void recursive_vector_test()//Test for recursive types
{
- stable_vector<recursive_vector> recursive_vector_vector;
+ stable_vector<recursive_vector> recursive, copy;
+ //Test to test both move emulations
+ if(!copy.size()){
+ copy = recursive;
+ }
}
int main()
@@ -55,6 +61,7 @@
typedef stable_vector<int> MyVector;
typedef stable_vector<test::movable_int> MyMoveVector;
typedef stable_vector<test::movable_and_copyable_int> MyCopyMoveVector;
+ typedef stable_vector<test::copyable_int> MyCopyVector;
if(test::vector_test<MyVector>())
return 1;
@@ -65,6 +72,9 @@
if(test::vector_test<MyCopyMoveVector>())
return 1;
+ if(test::vector_test<MyCopyVector>())
+ return 1;
+
const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE);
if(!boost::container::test::test_emplace
< stable_vector<test::EmplaceInt>, Options>())
Modified: sandbox/move/libs/container/test/tree_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/tree_test.cpp (original)
+++ sandbox/move/libs/container/test/tree_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -18,14 +18,6 @@
#include "map_test.hpp"
#include "emplace_test.hpp"
-///////////////////////////////////////////////////////////////////
-// //
-// This example repeats the same operations with std::set and //
-// shmem_set using the node allocator //
-// and compares the values of both containers //
-// //
-///////////////////////////////////////////////////////////////////
-
using namespace boost::container;
//Alias standard types
@@ -46,11 +38,17 @@
typedef map<test::movable_int, test::movable_int> MyMovableShmMap;
typedef multimap<test::movable_int, test::movable_int> MyMovableShmMultiMap;
typedef set<test::movable_and_copyable_int> MyMoveCopyShmSet;
+typedef set<test::copyable_int> MyCopyShmSet;
typedef multiset<test::movable_and_copyable_int> MyMoveCopyShmMultiSet;
+typedef multiset<test::copyable_int> MyCopyShmMultiSet;
typedef map<test::movable_and_copyable_int
,test::movable_and_copyable_int> MyMoveCopyShmMap;
typedef multimap<test::movable_and_copyable_int
,test::movable_and_copyable_int> MyMoveCopyShmMultiMap;
+typedef map<test::copyable_int
+ ,test::copyable_int> MyCopyShmMap;
+typedef multimap<test::copyable_int
+ ,test::copyable_int> MyCopyShmMultiMap;
//Test recursive structures
class recursive_set
{
@@ -147,6 +145,26 @@
return 1;
}
+ if(0 != test::set_test_copyable<MyMoveCopyShmSet
+ ,MyStdSet
+ ,MyMoveCopyShmMultiSet
+ ,MyStdMultiSet>()){
+ return 1;
+ }
+
+ if(0 != test::set_test<MyCopyShmSet
+ ,MyStdSet
+ ,MyCopyShmMultiSet
+ ,MyStdMultiSet>()){
+ return 1;
+ }
+
+ if(0 != test::set_test_copyable<MyCopyShmSet
+ ,MyStdSet
+ ,MyCopyShmMultiSet
+ ,MyStdMultiSet>()){
+ return 1;
+ }
if (0 != test::map_test<MyShmMap
,MyStdMap
@@ -177,6 +195,27 @@
return 1;
}
+ if (0 != test::map_test_copyable<MyMoveCopyShmMap
+ ,MyStdMap
+ ,MyMoveCopyShmMultiMap
+ ,MyStdMultiMap>()){
+ return 1;
+ }
+
+ if (0 != test::map_test<MyCopyShmMap
+ ,MyStdMap
+ ,MyCopyShmMultiMap
+ ,MyStdMultiMap>()){
+ return 1;
+ }
+
+ if (0 != test::map_test_copyable<MyCopyShmMap
+ ,MyStdMap
+ ,MyCopyShmMultiMap
+ ,MyStdMultiMap>()){
+ return 1;
+ }
+
const test::EmplaceOptions SetOptions = (test::EmplaceOptions)(test::EMPLACE_HINT | test::EMPLACE_ASSOC);
if(!boost::container::test::test_emplace<set<test::EmplaceInt>, SetOptions>())
return 1;
Modified: sandbox/move/libs/container/test/vector_test.cpp
==============================================================================
--- sandbox/move/libs/container/test/vector_test.cpp (original)
+++ sandbox/move/libs/container/test/vector_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -76,6 +76,12 @@
vector<recursive_vector> recursive_vector_vector;
}
+enum Test
+{
+ zero, one, two, three, four, five, six
+};
+
+
int main()
{
recursive_vector_test();
@@ -90,15 +96,27 @@
typedef vector<int> MyVector;
typedef vector<test::movable_int> MyMoveVector;
typedef vector<test::movable_and_copyable_int> MyCopyMoveVector;
+ typedef vector<test::copyable_int> MyCopyVector;
+ typedef vector<Test> MyEnumVector;
+
+
if(test::vector_test<MyVector>())
return 1;
if(test::vector_test<MyMoveVector>())
return 1;
if(test::vector_test<MyCopyMoveVector>())
return 1;
+ if(test::vector_test<MyCopyVector>())
+ return 1;
if(test_expand_bwd())
return 1;
+ MyEnumVector v;
+ Test t;
+ v.push_back(t);
+ v.push_back(::boost::move(t));
+ v.push_back(Test());
+
const test::EmplaceOptions Options = (test::EmplaceOptions)(test::EMPLACE_BACK | test::EMPLACE_BEFORE);
if(!boost::container::test::test_emplace
< vector<test::EmplaceInt>, Options>())
@@ -106,5 +124,51 @@
return 0;
}
-
#include <boost/container/detail/config_end.hpp>
+/*
+
+#include <iostream>
+#include <boost/type_traits/is_fundamental.hpp>
+
+enum Test {a, b, c};
+
+template <class _TypeT>
+struct __rw_is_enum
+{
+struct _C_no { };
+struct _C_yes { int _C_dummy [2]; };
+
+struct _C_indirect {
+// prevent classes with user-defined conversions from matching
+
+// use double to prevent float->int gcc conversion warnings
+_C_indirect (double);
+};
+
+// nested struct gets rid of bogus gcc errors
+struct _C_nest {
+// supply first argument to prevent HP aCC warnings
+static _C_no _C_is (int, ...);
+static _C_yes _C_is (int, _C_indirect);
+
+static _TypeT _C_make_T ();
+};
+
+enum {
+_C_val = sizeof (_C_yes)
+== sizeof (_C_nest::_C_is (0, _C_nest::_C_make_T ()))
+&& !::boost::is_fundamental<_TypeT>::value
+};
+
+};
+
+int main()
+
+{
+ std::cout << __rw_is_enum<Test>::_C_val << std::endl;
+ return 0;
+}
+
+
+
+*/
\ No newline at end of file
Modified: sandbox/move/libs/container/test/vector_test.hpp
==============================================================================
--- sandbox/move/libs/container/test/vector_test.hpp (original)
+++ sandbox/move/libs/container/test/vector_test.hpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -30,25 +30,25 @@
namespace test{
template<class V1, class V2>
-bool copyable_only(V1 *, V2 *, boost::container::containers_detail::false_type)
+bool vector_copyable_only(V1 *, V2 *, boost::container::containers_detail::false_type)
{
return true;
}
//Function to check if both sets are equal
template<class V1, class V2>
-bool copyable_only(V1 *shmvector, V2 *stdvector, boost::container::containers_detail::true_type)
+bool vector_copyable_only(V1 *shmvector, V2 *stdvector, boost::container::containers_detail::true_type)
{
typedef typename V1::value_type IntType;
std::size_t size = shmvector->size();
+ shmvector->insert(shmvector->end(), 50, IntType(1));
stdvector->insert(stdvector->end(), 50, 1);
- shmvector->insert(shmvector->end(), 50, 1);
if(!test::CheckEqualContainers(shmvector, stdvector)) return false;
{
IntType move_me(1);
- stdvector->insert(stdvector->begin()+size/2, 50, 1);
shmvector->insert(shmvector->begin()+size/2, 50, boost::move(move_me));
+ stdvector->insert(stdvector->begin()+size/2, 50, 1);
if(!test::CheckEqualContainers(shmvector, stdvector)) return false;
}
{
@@ -63,6 +63,17 @@
stdvector->assign(stdvector->size()*3-1, 3);
if(!test::CheckEqualContainers(shmvector, stdvector)) return false;
}
+
+ {
+ IntType copy_me(3);
+ const IntType ccopy_me(3);
+ shmvector->push_back(copy_me);
+ stdvector->push_back(int(3));
+ shmvector->push_back(ccopy_me);
+ stdvector->push_back(int(3));
+ if(!test::CheckEqualContainers(shmvector, stdvector)) return false;
+ }
+
return true;
}
@@ -151,16 +162,19 @@
if(!test::CheckEqualContainers(shmvector, stdvector)) return 1;
}
- shmvector->reserve(shmvector->size()*2);
- stdvector->reserve(stdvector->size()*2);
- if(!test::CheckEqualContainers(shmvector, stdvector)) return 1;
+ //shmvector->reserve(shmvector->size()*2);
+ //stdvector->reserve(stdvector->size()*2);
+ //if(!test::CheckEqualContainers(shmvector, stdvector)) return 1;
IntType push_back_this(1);
shmvector->push_back(boost::move(push_back_this));
stdvector->push_back(int(1));
+ shmvector->push_back(IntType(1));
+ stdvector->push_back(int(1));
+
if(!test::CheckEqualContainers(shmvector, stdvector)) return 1;
- if(!copyable_only(shmvector, stdvector
+ if(!vector_copyable_only(shmvector, stdvector
,containers_detail::bool_<!is_movable<IntType>::value>())){
return 1;
}
@@ -173,6 +187,8 @@
IntType insert_this(i);
shmvector->insert(shmvector->begin(), boost::move(insert_this));
stdvector->insert(stdvector->begin(), i);
+ shmvector->insert(shmvector->begin(), IntType(i));
+ stdvector->insert(stdvector->begin(), int(i));
}
if(!test::CheckEqualContainers(shmvector, stdvector)) return 1;
Modified: sandbox/move/libs/move/doc/move.qbk
==============================================================================
--- sandbox/move/libs/move/doc/move.qbk (original)
+++ sandbox/move/libs/move/doc/move.qbk 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -1,14 +1,13 @@
[/
- / Copyright (c) 2008-2009 Ion Gaztanaga
+ / Copyright (c) 2008-2010 Ion Gaztanaga
/
/ Distributed under 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)
/]
-
[library Boost.Move
- [quickbook 1.3]
- [authors [Gaztañaga, Ion]]
- [copyright 2008-2009 Ion Gaztañaga]
+ [quickbook 1.5]
+ [authors [Gaztanaga, Ion]]
+ [copyright 2008-2010 Ion Gaztanaga]
[id move]
[dirname move]
[purpose Move semantics]
@@ -21,9 +20,21 @@
[warning This library is NOT an official Boost library]
+[note [*['For reviewers]] This library has two operating modes, depending on the macro
+ [macroref BOOST_MOVE_OPTIMIZED_EMULATION BOOST_MOVE_OPTIMIZED_EMULATION]. In the review, one of these
+ modes should be chosen as the desired move emulation node.
+ See chapter [link move.two_emulation_modes Two emulation modes] for more details about
+ pros and cons of each operating mode]
+
+[note [*['For reviewers]] If you want to know how the emulation works behind the scenes
+ to propose improvements or corrections, please see chapter
+ [link move.how_the_emulation_works How the emulation works] for more details]
+
[important To be able to use containers of movable values you will need an special version
of [*Boost.Container] bundled with this library]
+[note Tested compilers: MSVC-7.1, 8.0, 9.0, GCC 4.3-MinGW in C++03 and C++0x modes, Intel 10.1]
+
[section:introduction Introduction]
[note
@@ -173,6 +184,12 @@
[clone_ptr_def]
+[important [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF(classname)] macro is *not* needed
+ if the *'Non-optimized' mode* is selected, the usual `const classname &`
+ overload would be fine. See [link move.two_emulation_modes Two emulation modes]
+ for more details about pros/cons of this emulation mode.
+]
+
[endsect]
[*Question]: What about types that don't own resources? (E.g. `std::complex`?)
@@ -188,6 +205,12 @@
[clone_ptr_base_derived]
+[important [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF(classname)] macro is *not* needed
+ if the *'Non-optimized' mode* is selected, the usual `const classname &`
+ overaload would be fine. See [link move.two_emulation_modes Two emulation modes]
+ for more details about pros/cons of this emulation mode.
+]
+
Each subobject will now be treated individually, calling move to bind to the subobject's move
constructors and move assignment operators. `Member` has move operations coded (just like
our earlier `clone_ptr` example) which will completely avoid the tremendously more expensive
@@ -197,8 +220,8 @@
Note above that the argument x is treated as a lvalue reference. That's why it is necessary to
say `move(x)` instead of just x when passing down to the base class. This is a key safety feature of move
-semantics designed to prevent accidently moving twice from some named variable. All moves occur
-explicitly.
+semantics designed to prevent accidently moving twice from some named variable. All moves from
+lvalues occur explicitly.
[endsect]
@@ -545,4 +568,293 @@
[endsect]
+[section:emulation_limitations Emulation limitations]
+
+Like any emulation effort, the library has some limitations users should take in
+care to achieve portable and efficient code when using the library with C++03 conformant compilers:
+
+[section:emulation_limitations_base Initializing base classes]
+
+When initializing base classes in move constructors, users must
+cast the reference to a base class reference before moving it. Example:
+
+[c++]
+
+ //Portable and efficient
+ Derived(BOOST_RV_REF(Derived) x) // Move ctor
+ : Base(boost::move(static_cast<Base&>(x))),
+ mem_(boost::move(x.mem_)) { }
+
+
+If casting is not performed the emulation will not move construct
+the base class, because no conversion is available from `BOOST_RV_REF(Derived)`
+to `BOOST_RV_REF(Base)`. Without the cast we might obtain a compilation
+error (for non-copyable types) or a less-efficient move constructor (for copyable types):
+
+[c++]
+
+ //If Derived is copyable, then Base is copy-constructed.
+ //If not, a compilation error is issued
+ Derived(BOOST_RV_REF(Derived) x) // Move ctor
+ : Base(boost::move(x)),
+ mem_(boost::move(x.mem_)) { }
+
+[endsect]
+
+[section:template_parameters Template parameters for perfect forwarding]
+
+The emulation can't deal with C++0x reference collapsing rules that allow perfect forwarding:
+
+[c++]
+
+ //C++0x
+ template<class T>
+ void forward_function(T &&t)
+ { inner_function(std::forward<T>(t); }
+
+ //Wrong C++03 emulation
+ template<class T>
+ void forward_function(BOOST_RV_REF<T> t)
+ { inner_function(boost::forward<T>(t); }
+
+In C++03 emulation BOOST_RV_REF doesn't catch any const rlvalues. For more details on
+forwarding see [link move.construct_forwarding Constructor Forwarding] chapter.
+
+[endsect]
+
+[section:emulation_limitations_binding Binding of rvalue references to lvalues]
+
+The
+[@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1690.html first rvalue reference]
+proposal allowed the binding of rvalue references to lvalues:
+
+[c++]
+
+ func(Type &&t);
+ //....
+
+ Type t; //Allowed
+ func(t)
+
+
+Later, as explained in
+[@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2812.html ['Fixing a Safety Problem with Rvalue References]]
+this behaviour was considered dangerous and eliminated this binding so that rvalue references adhere to the
+principle of type-safe overloading: ['Every function must be type-safe in isolation, without regard to how it has been overloaded]
+
+[*Boost.Move] can't emulate this type-safe overaloading principle for C++03 compilers:
+
+[c++]
+
+ //Allowed by move emulation
+ movable m;
+ BOOST_RV_REF(movable) r = m;
+
+[endsect]
+
+[section:emulation_limitations_modes Further limitations depending on the emulation mode]
+
+As explained in the section [link move.two_emulation_modes Two emulation modes]
+the library has some more limitations depending on the emulation mode selected by the user.
+See that chapter for more details.
+
+[endsect]
+
+[endsect]
+
+[section:two_emulation_modes Two emulation modes]
+
+This review version of the library has two emulation modes that can be selected using
+the macro [macroref BOOST_MOVE_OPTIMIZED_EMULATION BOOST_MOVE_OPTIMIZED_EMULATION] in
+the header [headerref boost/move/move.hpp move.hpp]. This selection has no
+effect on compilers supporting rvalue-references but it changes the behaviour of the
+move emulation used in C++03 compilers. During the review a mode and its limitations should be chosen
+because no perfect emulation has been found to date:
+
+[section:optimized_mode Optimized mode]
+
+If [macroref BOOST_MOVE_OPTIMIZED_EMULATION BOOST_MOVE_OPTIMIZED_EMULATION] is defined
+in [headerref boost/move/move.hpp move.hpp]
+the library correctly move assigns non-const rvalues of copyable and movable types:
+
+[c++]
+
+ class copyable_and_movable
+ {/**/};
+
+ copyable_and_movable produce(){ return copyable_and_movable(); }
+
+ int main(){
+ copyable_and_movable cm;
+ copyable_and_movable cm;
+ cm = copyable_and_movable(); //temporary object is MOVED, not COPIED
+ return 0;
+ }
+
+The downside is that in this emulation mode, the macro
+[macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE] needs to
+define a copy constructor for `copyable_and_movable` taking a non-const parameter:
+
+[c++]
+
+ //Generated by BOOST_COPYABLE_AND_MOVABLE
+ copyable_and_movable &operator=(copyable_and_movable&){/**/}
+
+Since the non-const overload of the copy constructor is generated, compiler-generated
+assignment operators for classes containing `copyable_and_movable`
+will get the non-const copy constructor overload, which will surely surprise users:
+
+[c++]
+
+ class holder
+ {
+ copyable_and_movable c;
+ };
+
+ void func(const holder& h)
+ {
+ holder copy_h(h); //<--- ERROR: can't convert 'const holder&' to 'holder&'
+ //Compiler-generated copy constructor is non-const:
+ // holder& operator(holder &)
+ //!!!
+ }
+
+This limitation forces the user to define a const version of the copy constructor,
+in all classes holding copyable and movable classes which might be suboptimal in some
+templated code or annoying in several cases.
+
+[endsect]
+
+
+[section:non_optimized_mode Non-optimized mode]
+
+If [macroref BOOST_MOVE_OPTIMIZED_EMULATION BOOST_MOVE_OPTIMIZED_EMULATION] is undefined
+in [headerref boost/move/move.hpp move.hpp] the non-optimized mode is activated
+and it avoids the copy-assignment issue for `holder`, and users don't even
+need to define the [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] overload for their
+classes. Users can use the usual copy-assignment or the compiler-generated one:
+
+[c++]
+
+ copyable_and_movable
+ {
+ //...
+ copyable_and_movable& operator= (const copyable_and_movable&);
+ };
+
+But this emulation mode does not optimize the non-const rvalue move assignment example:
+
+[c++]
+
+ int main(){
+ copyable_and_movable cm;
+ cm = copyable_and_movable(); //temporary object is COPIED
+ return 0;
+ }
+
+There is a workaround for this missing optimization with an explicit
+[funcref boost::forward forward] call:
+
+[c++]
+
+ int main(){
+ copyable_and_movable cm;
+ //Temporary object is MOVED
+ cm = ::boost::forward<copyable_and_movable>(copyable_and_movable());
+ return 0;
+ }
+
+[endsect]
+
+[endsect]
+
+[section:how_the_emulation_works How the emulation works]
+
+For movable classes [*Boost.Move] defines a class named `::boost::rv`:
+
+[c++]
+
+ template <class T>
+ class rv : public T
+ {
+ rv();
+ ~rv();
+ rv(rv const&);
+ void operator=(rv const&);
+ };
+
+which is convertible to the movable base class (usual C++ derived to base conversion). When users mark
+their classes as [macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] or
+[macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE], these macros define conversion
+operators to references to `::boost::rv`:
+
+[c++]
+
+ #define BOOST_MOVABLE_BUT_NOT_COPYABLE(TYPE)\
+ public:\
+ operator ::BOOST_MOVE_NAMESPACE::rv<TYPE>&() \
+ { return *reinterpret_cast< ::BOOST_MOVE_NAMESPACE::rv<TYPE>* >(this); }\
+ operator const ::BOOST_MOVE_NAMESPACE::rv<TYPE>&() const \
+ { return *reinterpret_cast<const ::BOOST_MOVE_NAMESPACE::rv<TYPE>* >(this); }\
+ private:\
+ //More stuff...
+
+[macroref BOOST_MOVABLE_BUT_NOT_COPYABLE BOOST_MOVABLE_BUT_NOT_COPYABLE] also declares a
+private copy constructor and assignment. [macroref BOOST_COPYABLE_AND_MOVABLE BOOST_COPYABLE_AND_MOVABLE]
+defines a non-const copy constructor `TYPE &operator=(TYPE&)` that forwards to a const version:
+
+ #define BOOST_COPYABLE_AND_MOVABLE(TYPE)\
+ public:\
+ TYPE& operator=(TYPE &t)\
+ { this->operator=(static_cast<const ::boost::rv<TYPE> &>(const_cast<const TYPE &>(t))); return *this;}\
+ //More stuff...
+
+When users define the [macroref BOOST_RV_REF BOOST_RV_REF] overload of a copy constructor/assignment, it is
+expanded to a `::boost::rv` reference overload:
+
+[c++]
+
+ #define BOOST_RV_REF(TYPE) ::boost::rv< TYPE >& \
+
+When users define the [macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] overload,
+it is expanded to a const `::boost::rv` references overload (in the 'Optimized mode'):
+
+[c++]
+
+ #define BOOST_COPY_ASSIGN_REF(TYPE) const ::boost::rv< TYPE >&
+
+Now when overload resolution is performed these are the bindings:
+
+* a) non-const rvalues (e.g.: temporaries), bind to `::boost::rv< TYPE >&`
+* b) const rvalue and lvalues, bind to `const ::boost::rv< TYPE >&`
+* c) non-const lvalues (e.g. non-const references) bind to `TYPE&`
+
+The library does not define the equivalent of
+[macroref BOOST_COPY_ASSIGN_REF BOOST_COPY_ASSIGN_REF] for copy construction (say, `BOOST_COPY_CTOR_REF`)
+because nearly all modern compilers implement RVO and this is much more efficient than any move emulation.
+[funcref boost::move move] just casts `TYPE &` into `::boost::rv<TYPE> &`.
+
+Here's an example that demostrates how different rlvalue objects bind to `::boost::rv` references in the
+presence of three overloads and the conversion operators:
+
+[import ../example/doc_how_works.cpp]
+[how_works_example]
+
+[important For 'Non-optimized' emulation mode no `const ::boost::rv<TYPE> &` overload is present
+since [macroref BOOST_COPY_ASSIGN_REF] expands to `const TYPE &`.
+]
+
+[endsect]
+
+
+[section:thanks_to Thanks and credits]
+
+Thanks to all that developed ideas for move emulation: the first emulation was based on Howard Hinnant
+emulation code for `unique_ptr`, David Abrahams suggested the use of `class rv` class,
+and Klaus Triendl discovered how to bind const rlvalues using `class rv`.
+
+Many thanks to all boosters that have tested and improved the library.
+
+[endsect]
+
[xinclude autodoc.xml]
Added: sandbox/move/libs/move/example/copymovable.hpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/example/copymovable.hpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -0,0 +1,46 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2009.
+// Distributed under 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)
+//
+// See http://www.boost.org/libs/move for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+#ifndef BOOST_MOVE_TEST_COPYMOVABLE_HPP
+#define BOOST_MOVE_TEST_COPYMOVABLE_HPP
+
+//[movable_definition
+//header file "copy_movable.hpp"
+#include <boost/move/move.hpp>
+
+//A copy_movable class
+class copy_movable
+{
+ BOOST_COPYABLE_AND_MOVABLE(copy_movable)
+ int value_;
+
+ public:
+ copy_movable() : value_(1){}
+
+ //Move constructor and assignment
+ copy_movable(BOOST_RV_REF(copy_movable) m)
+ { value_ = m.value_; m.value_ = 0; }
+
+ copy_movable(const copy_movable &m)
+ { value_ = m.value_; }
+
+ copy_movable & operator=(BOOST_RV_REF(copy_movable) m)
+ { value_ = m.value_; m.value_ = 0; return *this; }
+
+ copy_movable & operator=(BOOST_COPY_ASSIGN_REF(copy_movable) m)
+ { value_ = m.value_; return *this; }
+
+ bool moved() const //Observer
+ { return value_ == 0; }
+};
+
+//]
+
+#endif //BOOST_MOVE_TEST_COPYMOVABLE_HPP
Modified: sandbox/move/libs/move/example/doc_clone_ptr.cpp
==============================================================================
--- sandbox/move/libs/move/example/doc_clone_ptr.cpp (original)
+++ sandbox/move/libs/move/example/doc_clone_ptr.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -71,7 +71,7 @@
return *this;
}
- Derived& operator=(BOOST_COPY_ASSIGN_REF(Derived) x) // Move assign
+ Derived& operator=(BOOST_COPY_ASSIGN_REF(Derived) x) // Copy assign
{
Base::operator=(static_cast<const Base&>(x));
mem_ = x.mem_;
@@ -103,9 +103,9 @@
clone_ptr& operator=(BOOST_COPY_ASSIGN_REF(clone_ptr) p) // Copy assignment
{
if (this != &p){
- T *p = p.ptr ? p.ptr->clone() : 0;
+ T *tmp_p = p.ptr ? p.ptr->clone() : 0;
delete ptr;
- ptr = p;
+ ptr = tmp_p;
}
return *this;
}
@@ -116,9 +116,11 @@
clone_ptr& operator=(BOOST_RV_REF(clone_ptr) p) //Move assignment
{
- delete ptr;
- ptr = p.ptr;
- p.ptr = 0;
+ if (this != &p){
+ delete ptr;
+ ptr = p.ptr;
+ p.ptr = 0;
+ }
return *this;
}
};
Modified: sandbox/move/libs/move/example/doc_construct_forward.cpp
==============================================================================
--- sandbox/move/libs/move/example/doc_construct_forward.cpp (original)
+++ sandbox/move/libs/move/example/doc_construct_forward.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -13,49 +13,49 @@
#include <boost/move/move.hpp>
#include <iostream>
-class non_movable_test
+class copyable_only_tester
{
public:
- non_movable_test()
- { std::cout << "non_movable_test()" << std::endl; }
+ copyable_only_tester()
+ { std::cout << "copyable_only_tester()" << std::endl; }
- non_movable_test(const non_movable_test&)
- { std::cout << "non_movable_test(const non_movable_test&)" << std::endl; }
+ copyable_only_tester(const copyable_only_tester&)
+ { std::cout << "copyable_only_tester(const copyable_only_tester&)" << std::endl; }
- non_movable_test(int)
- { std::cout << "non_movable_test(int)" << std::endl; }
+ copyable_only_tester(int)
+ { std::cout << "copyable_only_tester(int)" << std::endl; }
- non_movable_test(int, double)
- { std::cout << "non_movable_test(int, double)" << std::endl; }
+ copyable_only_tester(int, double)
+ { std::cout << "copyable_only_tester(int, double)" << std::endl; }
};
-class movable_test
+class copyable_movable_tester
{
// move semantics
- BOOST_COPYABLE_AND_MOVABLE(movable_test)
+ BOOST_COPYABLE_AND_MOVABLE(copyable_movable_tester)
public:
- movable_test()
- { std::cout << "movable_test()" << std::endl; }
+ copyable_movable_tester()
+ { std::cout << "copyable_movable_tester()" << std::endl; }
- movable_test(int)
- { std::cout << "movable_test(int)" << std::endl; }
+ copyable_movable_tester(int)
+ { std::cout << "copyable_movable_tester(int)" << std::endl; }
- movable_test(BOOST_RV_REF(movable_test))
- { std::cout << "movable_test(BOOST_RV_REF(movable_test))" << std::endl; }
+ copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))
+ { std::cout << "copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))" << std::endl; }
- movable_test(const movable_test &)
- { std::cout << "movable_test(const movable_test &)" << std::endl; }
+ copyable_movable_tester(const copyable_movable_tester &)
+ { std::cout << "copyable_movable_tester(const copyable_movable_tester &)" << std::endl; }
- movable_test(BOOST_RV_REF(movable_test), BOOST_RV_REF(movable_test))
- { std::cout << "movable_test(BOOST_RV_REF(movable_test), BOOST_RV_REF(movable_test))" << std::endl; }
+ copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))
+ { std::cout << "copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))" << std::endl; }
- movable_test &operator=(BOOST_RV_REF(movable_test))
- { std::cout << "movable_test & operator=(BOOST_RV_REF(movable_test))" << std::endl;
+ copyable_movable_tester &operator=(BOOST_RV_REF(copyable_movable_tester))
+ { std::cout << "copyable_movable_tester & operator=(BOOST_RV_REF(copyable_movable_tester))" << std::endl;
return *this; }
- movable_test &operator=(BOOST_COPY_ASSIGN_REF(movable_test))
- { std::cout << "movable_test & operator=(BOOST_COPY_ASSIGN_REF(movable_test))" << std::endl;
+ copyable_movable_tester &operator=(BOOST_COPY_ASSIGN_REF(copyable_movable_tester))
+ { std::cout << "copyable_movable_tester & operator=(BOOST_COPY_ASSIGN_REF(copyable_movable_tester))" << std::endl;
return *this; }
};
@@ -67,41 +67,39 @@
//2 argument
template<class MaybeMovable, class MaybeRv, class MaybeRv2>
void function_construct(BOOST_FWD_REF(MaybeRv) x, BOOST_FWD_REF(MaybeRv2) x2)
-{
- MaybeMovable m(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2));
-}
+{ MaybeMovable m(boost::forward<MaybeRv>(x), boost::forward<MaybeRv2>(x2)); }
int main()
{
- movable_test m;
+ copyable_movable_tester m;
//move constructor
- function_construct<movable_test>(boost::move(m));
+ function_construct<copyable_movable_tester>(boost::move(m));
//copy constructor
- function_construct<movable_test>(movable_test());
+ function_construct<copyable_movable_tester>(copyable_movable_tester());
//two rvalue constructor
- function_construct<movable_test>(boost::move(m), boost::move(m));
+ function_construct<copyable_movable_tester>(boost::move(m), boost::move(m));
- non_movable_test nm;
- //copy constructor (non_movable_test has no move ctor.)
- function_construct<non_movable_test>(boost::move(nm));
+ copyable_only_tester nm;
+ //copy constructor (copyable_only_tester has no move ctor.)
+ function_construct<copyable_only_tester>(boost::move(nm));
//copy constructor
- function_construct<non_movable_test>(nm);
+ function_construct<copyable_only_tester>(nm);
//int constructor
- function_construct<non_movable_test>(int(0));
+ function_construct<copyable_only_tester>(int(0));
//int, double constructor
- function_construct<non_movable_test>(int(0), double(0.0));
+ function_construct<copyable_only_tester>(int(0), double(0.0));
//Output is:
- //movable_test()
- //movable_test(BOOST_RV_REF(movable_test))
- //movable_test()
- //movable_test(const movable_test &)
- //movable_test(BOOST_RV_REF(movable_test), BOOST_RV_REF(movable_test))
- //non_movable_test()
- //non_movable_test(const non_movable_test&)
- //non_movable_test(const non_movable_test&)
- //non_movable_test(int)
- //non_movable_test(int, double)
+ //copyable_movable_tester()
+ //copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester))
+ //copyable_movable_tester()
+ //copyable_movable_tester(const copyable_movable_tester &)
+ //copyable_movable_tester(BOOST_RV_REF(copyable_movable_tester), BOOST_RV_REF(copyable_movable_tester))
+ //copyable_only_tester()
+ //copyable_only_tester(const copyable_only_tester&)
+ //copyable_only_tester(const copyable_only_tester&)
+ //copyable_only_tester(int)
+ //copyable_only_tester(int, double)
return 0;
}
//]
Added: sandbox/move/libs/move/example/doc_how_works.cpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/example/doc_how_works.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -0,0 +1,60 @@
+//////////////////////////////////////////////////////////////////////////////
+//
+// (C) Copyright Ion Gaztanaga 2009.
+// Distributed under 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)
+//
+// See http://www.boost.org/libs/move for documentation.
+//
+//////////////////////////////////////////////////////////////////////////////
+
+#include <boost/config.hpp>
+
+#if !defined(BOOST_NO_RVALUE_REFERENCES)
+
+int main()
+{
+ return 0;
+}
+
+#else
+
+//[how_works_example
+#include <boost/move/move.hpp>
+#include <iostream>
+
+class sink_tester
+{
+ public: //conversions provided by BOOST_COPYABLE_AND_MOVABLE
+ operator ::boost::rv<sink_tester>&()
+ { return *reinterpret_cast< ::boost::rv<sink_tester>* >(this); }
+ operator const ::boost::rv<sink_tester>&() const
+ { return *reinterpret_cast<const ::boost::rv<sink_tester>* >(this); }
+};
+
+//Functions returning different r/lvalue types
+ sink_tester rvalue() { return sink_tester(); }
+const sink_tester const_rvalue() { return sink_tester(); }
+ sink_tester & lvalue() { static sink_tester lv; return lv; }
+const sink_tester & const_lvalue() { static const sink_tester clv = sink_tester(); return clv; }
+
+//BOOST_RV_REF overload
+void sink(::boost::rv<sink_tester> &) { std::cout << "non-const rvalue catched" << std::endl; }
+//BOOST_COPY_ASSIGN_REF overload
+void sink(const ::boost::rv<sink_tester> &){ std::cout << "const (r-l)value catched" << std::endl; }
+//Overload provided by BOOST_COPYABLE_AND_MOVABLE
+void sink(sink_tester &) { std::cout << "non-const lvalue catched" << std::endl; }
+
+int main()
+{
+ sink(const_rvalue()); //"const (r-l)value catched"
+ sink(const_lvalue()); //"const (r-l)value catched"
+ sink(lvalue()); //"non-const lvalue catched"
+ sink(rvalue()); //"non-const rvalue catched"
+ return 0;
+}
+//]
+
+#endif
+
Modified: sandbox/move/libs/move/example/movable.hpp
==============================================================================
--- sandbox/move/libs/move/example/movable.hpp (original)
+++ sandbox/move/libs/move/example/movable.hpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -35,6 +35,15 @@
{ return value_ == 0; }
};
+namespace boost{
+
+template<>
+struct has_nothrow_move<movable>
+{
+ static const bool value = true;
+};
+
+} //namespace boost{
//]
#endif //BOOST_MOVE_TEST_MOVABLE_HPP
Deleted: sandbox/move/libs/move/index.html
==============================================================================
--- sandbox/move/libs/move/index.html 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
+++ (empty file)
@@ -1,14 +0,0 @@
-<!--
-Copyright 2008-2009 Ion Gaztanaga
-Distributed under 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)
--->
-<html>
-<head>
-<meta http-equiv="refresh" content="0; URL=doc/html/index.html">
-</head>
-<body>
-Automatic redirection failed, please go to
-doc/html/index.html
-</body>
-</html>
Modified: sandbox/move/libs/move/proj/vc7ide/Move.sln
==============================================================================
--- sandbox/move/libs/move/proj/vc7ide/Move.sln (original)
+++ sandbox/move/libs/move/proj/vc7ide/Move.sln 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -43,6 +43,18 @@
ProjectSection(ProjectDependencies) = postProject
EndProjectSection
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "copy_move_optimization_test", "copy_move_optimization.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "copy_elision_test_test", "copy_elision_test.vcproj", "{C8AD2618-79EB-8612-42FE-2A3AC9667A13}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "doc_how_works", "doc_how_works.vcproj", "{C7C2F583-4FE2-1862-BF87-BA26D31A7995}"
+ ProjectSection(ProjectDependencies) = postProject
+ EndProjectSection
+EndProject
Global
GlobalSection(SolutionConfiguration) = preSolution
Debug = Debug
@@ -93,12 +105,23 @@
{C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32
{C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32
{C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.ActiveCfg = Debug|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Debug.Build.0 = Debug|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.ActiveCfg = Release|Win32
+ {C8AD2618-79EB-8612-42FE-2A3AC9667A13}.Release.Build.0 = Release|Win32
+ {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Debug.ActiveCfg = Debug|Win32
+ {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Debug.Build.0 = Debug|Win32
+ {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Release.ActiveCfg = Release|Win32
+ {C7C2F583-4FE2-1862-BF87-BA26D31A7995}.Release.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionItems) = postSolution
..\..\doc\Jamfile.v2 = ..\..\doc\Jamfile.v2
..\..\..\..\boost\move\move.hpp = ..\..\..\..\boost\move\move.hpp
..\..\doc\move.qbk = ..\..\doc\move.qbk
- todo.txt = todo.txt
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
EndGlobalSection
Added: sandbox/move/libs/move/proj/vc7ide/copy_elision_test.vcproj
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/proj/vc7ide/copy_elision_test.vcproj 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="copy_elision_test_test"
+ ProjectGUID="{C8AD2618-79EB-8612-42FE-2A3AC9667A13}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../Bin/Win32/Debug"
+ IntermediateDirectory="Debug/copy_elision_test_test"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="FALSE"
+ TreatWChar_tAsBuiltInType="TRUE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ OutputFile="$(OutDir)/copy_elision_test_test_d.exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="../../../../stage/lib"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/copy_elision_test_test.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ FixedBaseAddress="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../Bin/Win32/Release"
+ IntermediateDirectory="Release/copy_elision_test_test"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
+ RuntimeLibrary="2"
+ TreatWChar_tAsBuiltInType="TRUE"
+ ForceConformanceInForLoopScope="FALSE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ OutputFile="$(OutDir)/copy_elision_test_test.exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="../../../../stage/lib"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{818563C3-6640-0A65-55CB-202E5BAD7FAF}">
+ <File
+ RelativePath="..\..\test\copy_elision_test.cpp">
+ </File>
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Added: sandbox/move/libs/move/proj/vc7ide/doc_how_works.vcproj
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/proj/vc7ide/doc_how_works.vcproj 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="7.10"
+ Name="doc_how_works"
+ ProjectGUID="{C7C2F583-4FE2-1862-BF87-BA26D31A7995}"
+ Keyword="Win32Proj">
+ <Platforms>
+ <Platform
+ Name="Win32"/>
+ </Platforms>
+ <Configurations>
+ <Configuration
+ Name="Debug|Win32"
+ OutputDirectory="../../Bin/Win32/Debug"
+ IntermediateDirectory="Debug/doc_how_works"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ Optimization="0"
+ AdditionalIncludeDirectories="../../../.."
+ PreprocessorDefinitions="WIN32;_DEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
+ MinimalRebuild="TRUE"
+ BasicRuntimeChecks="3"
+ RuntimeLibrary="3"
+ DisableLanguageExtensions="FALSE"
+ TreatWChar_tAsBuiltInType="TRUE"
+ ForceConformanceInForLoopScope="TRUE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="3"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ OutputFile="$(OutDir)/doc_how_works_d.exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="../../../../stage/lib"
+ GenerateDebugInformation="TRUE"
+ ProgramDatabaseFile="$(OutDir)/doc_how_works.pdb"
+ SubSystem="1"
+ TargetMachine="1"
+ FixedBaseAddress="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ <Configuration
+ Name="Release|Win32"
+ OutputDirectory="../../Bin/Win32/Release"
+ IntermediateDirectory="Release/doc_how_works"
+ ConfigurationType="1"
+ CharacterSet="2">
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories="../../../.."
+ PreprocessorDefinitions="WIN32;NDEBUG;_CONSOLE;BOOST_DATE_TIME_NO_LIB"
+ RuntimeLibrary="2"
+ TreatWChar_tAsBuiltInType="TRUE"
+ ForceConformanceInForLoopScope="FALSE"
+ UsePrecompiledHeader="0"
+ WarningLevel="4"
+ Detect64BitPortabilityProblems="TRUE"
+ DebugInformationFormat="0"/>
+ <Tool
+ Name="VCCustomBuildTool"/>
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="winmm.lib"
+ OutputFile="$(OutDir)/doc_how_works.exe"
+ LinkIncremental="1"
+ AdditionalLibraryDirectories="../../../../stage/lib"
+ GenerateDebugInformation="TRUE"
+ SubSystem="1"
+ OptimizeReferences="2"
+ EnableCOMDATFolding="2"
+ TargetMachine="1"/>
+ <Tool
+ Name="VCMIDLTool"/>
+ <Tool
+ Name="VCPostBuildEventTool"/>
+ <Tool
+ Name="VCPreBuildEventTool"/>
+ <Tool
+ Name="VCPreLinkEventTool"/>
+ <Tool
+ Name="VCResourceCompilerTool"/>
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"/>
+ <Tool
+ Name="VCXMLDataGeneratorTool"/>
+ <Tool
+ Name="VCWebDeploymentTool"/>
+ <Tool
+ Name="VCManagedWrapperGeneratorTool"/>
+ <Tool
+ Name="VCAuxiliaryManagedWrapperGeneratorTool"/>
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <Filter
+ Name="Source Files"
+ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx"
+ UniqueIdentifier="{34957FC1-7BC5-05A6-1646-2A25472AA2FF}">
+ <File
+ RelativePath="..\..\example\doc_how_works.cpp">
+ </File>
+ </Filter>
+ <Filter
+ Name="Header Files"
+ Filter="h;hpp;hxx;hm;inl;inc;xsd"
+ UniqueIdentifier="{93A78280-B78D-4B31-7E8B-6255ACE1E5FB}">
+ </Filter>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
Deleted: sandbox/move/libs/move/proj/vc7ide/todo.txt
==============================================================================
--- sandbox/move/libs/move/proj/vc7ide/todo.txt 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
+++ (empty file)
@@ -1 +0,0 @@
-BOOST_MOVE_MOVABLE_ONLY
\ No newline at end of file
Modified: sandbox/move/libs/move/test/construct_forward.cpp
==============================================================================
--- sandbox/move/libs/move/test/construct_forward.cpp (original)
+++ sandbox/move/libs/move/test/construct_forward.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -8,8 +8,10 @@
// See http://www.boost.org/libs/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////
+
#include <boost/move/move.hpp>
#include "../example/movable.hpp"
+#include "../example/copymovable.hpp"
#include <cstdio>
class non_movable
@@ -19,6 +21,61 @@
{}
};
+template<class MaybeRvalue>
+void catch_test(BOOST_RV_REF(MaybeRvalue) x
+ ,typename ::boost::enable_if< ::boost::is_movable<MaybeRvalue> >::type* = 0)
+{ (void)x;}
+
+template<class MaybeRvalue>
+void catch_test(BOOST_COPY_ASSIGN_REF(MaybeRvalue) x
+ ,typename ::boost::enable_if< ::boost::is_movable<MaybeRvalue> >::type* = 0)
+
+{ (void)x;}
+
+template<class MaybeRvalue>
+void catch_test(MaybeRvalue &x
+ ,typename ::boost::enable_if< ::boost::is_movable<MaybeRvalue> >::type* = 0)
+{ (void)x;}
+
+template<class MaybeRvalue>
+void catch_test(const MaybeRvalue& x
+ ,typename ::boost::disable_if< ::boost::is_movable<MaybeRvalue> >::type* = 0)
+{ (void)x;}
+
+movable create_movable()
+{ return movable(); }
+
+copy_movable create_copy_movable()
+{ return copy_movable(); }
+
+non_movable create_non_movable()
+{ return non_movable(); }
+
+
+void catch_test()
+{
+ movable m;
+ const movable constm;
+ catch_test<movable>(boost::move(m));
+ #ifdef BOOST_MOVE_MACRO_MOVE_ASSIGN_FROM_NON_CONST_RVALUE
+ catch_test<movable>(create_movable());
+ #endif
+ catch_test<movable>(m);
+ catch_test<movable>(constm);
+ copy_movable cm;
+ const copy_movable constcm;
+ catch_test<copy_movable>(boost::move(cm));
+ catch_test<copy_movable>(create_copy_movable());
+ catch_test<copy_movable>(cm);
+ catch_test<copy_movable>(constcm);
+ non_movable nm;
+ const non_movable constnm;
+ catch_test<non_movable>(boost::move(nm));
+ catch_test<non_movable>(create_non_movable());
+ catch_test<non_movable>(nm);
+ catch_test<non_movable>(constnm);
+}
+
template<class MaybeMovableOnly, class MaybeRvalue>
void function_construct(BOOST_FWD_REF(MaybeRvalue) x)
{
@@ -27,13 +84,19 @@
MaybeMovableOnly m(boost::forward<MaybeRvalue>(x));
}
-int main()
+void forward_test()
{
movable m;
function_construct<movable>(boost::move(m));
- non_movable nm;
- function_construct<non_movable>(boost::move(nm));
- const non_movable cnm;
- function_construct<non_movable>(cnm);
+// non_movable nm;
+// function_construct<non_movable>(boost::move(nm));
+// const non_movable cnm;
+// function_construct<non_movable>(cnm);
+}
+
+int main()
+{
+ catch_test();
+ forward_test();
return 0;
}
Added: sandbox/move/libs/move/test/copy_elision_test.cpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/test/copy_elision_test.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -0,0 +1,170 @@
+// Copyright David Abrahams 2009. Distributed under 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)
+
+#include <iostream>
+
+#ifdef NO_MOVE
+# undef BOOST_COPY_ASSIGN_REF
+# define BOOST_COPY_ASSIGN_REF(X) X const&
+# undef BOOST_COPYABLE_AND_MOVABLE
+# define BOOST_COPYABLE_AND_MOVABLE(X)
+# define MOVE(x) (x)
+#else
+#include <boost/move/move.hpp>
+# define MOVE(x) boost::move(x)
+#endif
+
+struct X
+{
+ X() : id(instances++)
+ {
+ std::cout << "X" << id << ": construct\n";
+ }
+
+ X(X const& rhs) : id(instances++)
+ {
+ std::cout << "X" << id << ": <- " << "X" << rhs.id << ": **copy**\n";
+ ++copies;
+ }
+
+ // This particular test doesn't exercise assignment, but for
+ // completeness:
+ X& operator=(BOOST_COPY_ASSIGN_REF(X) rhs)
+ {
+ std::cout << "X" << id << ": <- " << "X" << rhs.id << ": assign\n";
+ return *this;
+ }
+
+#ifndef NO_MOVE
+ X& operator=(BOOST_RV_REF(X) rhs)
+ {
+ std::cout << "X" << id << ": <- " << "X" << rhs.id << ": move assign\n";
+ return *this;
+ }
+
+ X(BOOST_RV_REF(X) rhs) : id(instances++)
+ {
+ std::cout << "X" << id << ": <- " << "X" << rhs.id << ": ..move construct..\n";
+ ++copies;
+ }
+#endif
+
+ ~X() { std::cout << "X" << id << ": destroy\n"; }
+
+ unsigned id;
+
+ static unsigned copies;
+ static unsigned instances;
+
+ BOOST_COPYABLE_AND_MOVABLE(X)
+};
+
+unsigned X::copies = 0;
+unsigned X::instances = 0;
+
+#define CHECK_COPIES( stmt, min, max, comment ) \
+{ \
+ unsigned const old_copies = X::copies; \
+ \
+ std::cout << "\n" comment "\n" #stmt "\n===========\n"; \
+ { \
+ stmt; \
+ } \
+ unsigned const n = X::copies - old_copies; \
+ if (n > max) \
+ std::cout << "*** max is too low or compiler is buggy ***\n"; \
+ if (n < min) \
+ std::cout << "*** min is too high or compiler is buggy ***\n"; \
+ \
+ std::cout << "-----------\n" \
+ << n << "/" << max \
+ << " possible copies/moves made\n" \
+ << max - n << "/" << max - min \
+ << " possible elisions performed\n\n"; \
+ \
+ if (n > min) \
+ std::cout << "*** " << n - min \
+ << " possible elisions missed! ***\n"; \
+}
+
+struct trace
+{
+ trace(char const* name)
+ : name(name)
+ {
+ std::cout << "->: " << name << "\n";
+ }
+
+ ~trace()
+ {
+ std::cout << "<-: " << name << "\n";
+ }
+
+ char const* name;
+};
+
+void sink(X a)
+{
+ trace t("sink");
+}
+
+X nrvo_source()
+{
+ trace t("nrvo_source");
+ X a;
+ return a;
+}
+
+X urvo_source()
+{
+ trace t("urvo_source");
+ return X();
+}
+
+X identity(X a)
+{
+ trace t("identity");
+ return a;
+}
+
+X lvalue_;
+X& lvalue()
+{
+ return lvalue_;
+}
+typedef X rvalue;
+
+X ternary( bool y )
+{
+ X a, b;
+ return MOVE(y?a:b);
+}
+
+int main(int argc, char* argv[])
+{
+ (void)argv;
+ // Double parens prevent "most vexing parse"
+ CHECK_COPIES( X a(( lvalue() )), 1, 1, "Direct initialization from lvalue");
+ CHECK_COPIES( X a(( rvalue() )), 0, 1, "Direct initialization from rvalue");
+
+ CHECK_COPIES( X a = lvalue(), 1, 1, "Copy initialization from lvalue" );
+ CHECK_COPIES( X a = rvalue(), 0, 1, "Copy initialization from rvalue" );
+
+ CHECK_COPIES( sink( lvalue() ), 1, 1, "Pass lvalue by value" );
+ CHECK_COPIES( sink( rvalue() ), 0, 1, "Pass rvalue by value" );
+
+ CHECK_COPIES( nrvo_source(), 0, 1, "Named return value optimization (NRVO)" );
+ CHECK_COPIES( urvo_source(), 0, 1, "Unnamed return value optimization (URVO)" );
+
+ // Just to prove these things compose properly
+ CHECK_COPIES( X a(urvo_source()), 0, 2, "Return value used as ctor arg" );
+
+ // Expect to miss one possible elision here
+ CHECK_COPIES( identity( rvalue() ), 0, 2, "Return rvalue passed by value" );
+
+ // Expect to miss an elision in at least one of the following lines
+ CHECK_COPIES( X a = ternary( argc == 1000 ), 0, 2, "Return result of ternary operation" );
+ CHECK_COPIES( X a = ternary( argc != 1000 ), 0, 2, "Return result of ternary operation again" );
+ return 0;
+}
Modified: sandbox/move/libs/move/test/copy_move_optimization.cpp
==============================================================================
--- sandbox/move/libs/move/test/copy_move_optimization.cpp (original)
+++ sandbox/move/libs/move/test/copy_move_optimization.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -26,24 +26,24 @@
~obj()
{}
- obj(BOOST_COPY_ASSIGN_REF(obj) trule)
+ obj(const obj &)
{
std::cout << "copy construct from const obj" << "\n";
}
// copy construct from movable object (non-const rvalue, explicitly moved lvalue)
- obj(BOOST_RV_REF(obj) trule)
+ obj(BOOST_RV_REF(obj))
{
std::cout << "move construct from movable rvalue" << "\n";
}
- obj& operator =(BOOST_COPY_ASSIGN_REF(obj) trule)
+ obj& operator =(BOOST_COPY_ASSIGN_REF(obj))
{
std::cout << "copy assign from const obj" << "\n";
return *this;
}
- obj& operator =(BOOST_RV_REF(obj) trule)
+ obj& operator =(BOOST_RV_REF(obj))
{
std::cout << "move assign from movable rvalue" << "\n";
return *this;
@@ -56,8 +56,15 @@
obj& lvalue_func() { static obj o; return o; }
const obj& const_lvalue_func() { static obj o; return o; }
+obj produce() { return obj(); }
+
+void consume(obj){}
+
int main()
{
+ { consume(produce()); }
+ { obj o = produce(); }
+ { obj o(produce()); }
{
obj o1(rvalue_func());
obj o2 = const_rvalue_func();
@@ -65,7 +72,12 @@
obj o4 = const_lvalue_func();
// can't explicitly move temporaries
//obj o5 = boost::move(rvalue_func());
- obj o6 = boost::move(const_rvalue_func());
+ obj o5;
+ //Maybe missed optimization: copied
+ o5 = rvalue_func();
+ //Explicit forward works OK and optimized
+ o5 = boost::forward<obj>(rvalue_func());
+
obj o7 = boost::move(lvalue_func());
obj o8 = boost::move(const_lvalue_func());
@@ -76,11 +88,11 @@
o = const_lvalue_func();
// can't explicitly move temporaries
//o = boost::move(rvalue_func());
+ o = boost::forward<obj>(rvalue_func());
o = boost::move(const_rvalue_func());
o = boost::move(lvalue_func());
o = boost::move(const_lvalue_func());
}
-
return 0;
}
Modified: sandbox/move/libs/move/test/move.cpp
==============================================================================
--- sandbox/move/libs/move/test/move.cpp (original)
+++ sandbox/move/libs/move/test/move.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -44,9 +44,6 @@
}
-#include <boost/move/move.hpp>
-#include "../example/movable.hpp"
-
//Catch by value
void function_value(movable)
{}
@@ -91,10 +88,13 @@
struct copyable
{};
+movable create_movable()
+{ return movable(); }
int main()
{
BOOST_STATIC_ASSERT((boost::has_nothrow_move<movable>::value == true));
BOOST_STATIC_ASSERT((boost::has_nothrow_move<copyable>::value == false));
+
{
movable m;
movable m2(boost::move(m));
@@ -130,5 +130,6 @@
movable m3(move_return_function2());
}
limitations_test();
+
return 0;
}
Modified: sandbox/move/libs/move/test/move_iterator.cpp
==============================================================================
--- sandbox/move/libs/move/test/move_iterator.cpp (original)
+++ sandbox/move/libs/move/test/move_iterator.cpp 2010-04-25 08:34:43 EDT (Sun, 25 Apr 2010)
@@ -8,6 +8,7 @@
// See http://www.boost.org/libs/move for documentation.
//
//////////////////////////////////////////////////////////////////////////////
+
#include <boost/move/move.hpp>
#include <boost/container/vector.hpp>
#include "../example/movable.hpp"
@@ -50,3 +51,54 @@
return 0;
}
+
+/*
+#include <boost/move/move.hpp>
+
+
+class copy_movable
+{
+ BOOST_COPYABLE_AND_MOVABLE(copy_movable)
+ int value_;
+
+ public:
+ copy_movable() : value_(1){}
+
+ //Move constructor and assignment
+ copy_movable(BOOST_RV_REF(copy_movable) m)
+ { value_ = m.value_; m.value_ = 0; }
+
+ copy_movable(const copy_movable &m)
+ { value_ = m.value_; }
+
+ copy_movable & operator=(BOOST_RV_REF(copy_movable) m)
+ { value_ = m.value_; m.value_ = 0; return *this; }
+
+ copy_movable & operator=(BOOST_COPY_ASSIGN_REF(copy_movable) m)
+ { value_ = m.value_; return *this; }
+
+ bool moved() const //Observer
+ { return value_ == 0; }
+};
+
+struct copy_movable_wrapper
+{
+ copy_movable cm;
+};
+
+copy_movable produce()
+{ return copy_movable(); }
+
+
+int main()
+{
+ copy_movable cm;
+ cm = produce();
+
+ const copy_movable_wrapper cmw;
+ copy_movable_wrapper cmw2;
+ cmw2 = cmw;
+
+ return 0;
+}
+*/
\ No newline at end of file
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