Boost logo

Boost-Commit :

From: daniel_james_at_[hidden]
Date: 2008-04-05 14:19:53


Author: danieljames
Date: 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
New Revision: 44063
URL: http://svn.boost.org/trac/boost/changeset/44063

Log:
Starting work on a boostified version of the adobe move library.
Added:
   sandbox/move/
   sandbox/move/boost/
   sandbox/move/boost/move.hpp (contents, props changed)
   sandbox/move/libs/
   sandbox/move/libs/move/
   sandbox/move/libs/move/doc/
   sandbox/move/libs/move/doc/Jamfile.v2 (contents, props changed)
   sandbox/move/libs/move/doc/listing1.cpp (contents, props changed)
   sandbox/move/libs/move/doc/listing2.cpp (contents, props changed)
   sandbox/move/libs/move/doc/listing3.cpp (contents, props changed)
   sandbox/move/libs/move/doc/move.qbk (contents, props changed)
   sandbox/move/libs/move/test/
   sandbox/move/libs/move/test/Jamfile.v2 (contents, props changed)
   sandbox/move/libs/move/test/main.cpp (contents, props changed)
   sandbox/move/libs/move/test/vector.hpp (contents, props changed)
   sandbox/move/project-root.jam (contents, props changed)

Added: sandbox/move/boost/move.hpp
==============================================================================
--- (empty file)
+++ sandbox/move/boost/move.hpp 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,336 @@
+/*
+ Copyright 2005-2007 Adobe Systems Incorporated
+
+ 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).
+*/
+
+/*************************************************************************************************/
+
+#ifndef BOOST_MOVE_HPP
+#define BOOST_MOVE_HPP
+
+#include <cassert>
+#include <iterator>
+#include <memory>
+
+#include <boost/iterator/iterator_adaptor.hpp>
+#include <boost/mpl/bool.hpp>
+#include <boost/mpl/and.hpp>
+#include <boost/mpl/or.hpp>
+#include <boost/mpl/not.hpp>
+#include <boost/mpl/assert.hpp>
+#include <boost/range/begin.hpp>
+#include <boost/range/end.hpp>
+#include <boost/type_traits/is_convertible.hpp>
+#include <boost/type_traits/is_same.hpp>
+#include <boost/type_traits/is_class.hpp>
+#include <boost/utility/enable_if.hpp>
+
+/*************************************************************************************************/
+
+namespace boost {
+
+/*************************************************************************************************/
+
+namespace move_detail {
+
+/*************************************************************************************************/
+
+template <typename T>
+struct class_has_move_assign {
+ class type {
+ typedef T& (T::*E)(T t);
+ typedef char (&no_type)[1];
+ typedef char (&yes_type)[2];
+ template <E e> struct sfinae { typedef yes_type type; };
+ template <class U>
+ static typename sfinae<&U::operator=>::type test(int);
+ template <class U>
+ static no_type test(...);
+ public:
+ enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
+ };
+ };
+
+/*************************************************************************************************/
+
+template<typename T>
+struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
+
+/*************************************************************************************************/
+
+class test_can_convert_anything { };
+
+/*************************************************************************************************/
+
+/*
+ REVISIT (sparent_at_[hidden]): This is a work around for Boost 1.34.1 and VC++ 2008 where
+ boost::is_convertible<T, T> fails to compile.
+*/
+
+template <typename T, typename U>
+struct is_convertible : boost::mpl::or_<
+ boost::is_same<T, U>,
+ boost::is_convertible<T, U>
+> { };
+
+/*************************************************************************************************/
+
+} //namespace move_detail
+
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief move_from is used for move_ctors.
+*/
+
+template <typename T>
+struct move_from
+{
+ explicit move_from(T& x) : source(x) { }
+ T& source;
+};
+
+/*!
+\ingroup move_related
+\brief The is_movable trait can be used to identify movable types.
+*/
+template <typename T>
+struct is_movable : boost::mpl::and_<
+ boost::is_convertible<move_from<T>, T>,
+ move_detail::has_move_assign<T>,
+ boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
+ > { };
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief copy_sink and move_sink are used to select between overloaded operations according to
+ whether type T is movable and convertible to type U.
+\sa move
+*/
+
+template <typename T,
+ typename U = T,
+ typename R = void*>
+struct copy_sink : boost::enable_if<
+ boost::mpl::and_<
+ boost::move_detail::is_convertible<T, U>,
+ boost::mpl::not_<is_movable<T> >
+ >,
+ R
+ >
+{ };
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief move_sink and copy_sink are used to select between overloaded operations according to
+ whether type T is movable and convertible to type U.
+ \sa move
+*/
+
+template <typename T,
+ typename U = T,
+ typename R = void*>
+struct move_sink : boost::enable_if<
+ boost::mpl::and_<
+ boost::move_detail::is_convertible<T, U>,
+ is_movable<T>
+ >,
+ R
+ >
+{ };
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief This version of move is selected when T is_movable . It in turn calls the move
+constructor. This call, with the help of the return value optimization, will cause x to be moved
+instead of copied to its destination. See adobe/test/move/main.cpp for examples.
+
+*/
+template <typename T>
+T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief This version of move is selected when T is not movable . The net result will be that
+x gets copied.
+*/
+template <typename T>
+T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Iterator pair version of move. Similar to std::copy but with move semantics,
+for movable types, otherwise with copy semantics.
+*/
+template <typename I, // I models InputIterator
+ typename O> // O models OutputIterator
+O move(I f, I l, O result)
+{
+ while (f != l) {
+ *result = move(*f);
+ ++f; ++result;
+ }
+ return result;
+}
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief \ref concept_convertible_to_range version of move. Similar to copy but with move semantics,
+for movable types, otherwise with copy semantics.
+*/
+template <typename I, // I models InputRange
+ typename O> // O models OutputIterator
+inline O move(I& in, O out) { return move(boost::begin(in), boost::end(in), out); }
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Iterator pair version of move_backwards. Similar to std::copy_backwards but with move semantics,
+for movable types, otherwise with copy semantics.
+*/
+template <typename I, // I models BidirectionalIterator
+ typename O> // O models BidirectionalIterator
+O move_backward(I f, I l, O result)
+{
+ while (f != l) {
+ --l; --result;
+ *result = move(*l);
+ }
+ return result;
+}
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief \ref concept_convertible_to_range version of move_backwards. Similar to std::copy_backwards but
+with move semantics, for movable types, otherwise with copy semantics.
+*/
+template <typename I, // I models BidirectionalRange
+ typename O> // O models BidirectionalIterator
+inline O move_backward(I& in, O out)
+{ return move_backward(boost::begin(in), boost::end(in), out); }
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Similar to std::back_insert_iterator but
+with move semantics, for movable types, otherwise with copy semantics.
+*/
+
+template <typename C> // C models Container
+class back_move_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
+{
+ C* container_m;
+
+ public:
+ typedef C container_type;
+
+ explicit back_move_iterator(C& x) : container_m(&x) { }
+
+ back_move_iterator& operator=(typename C::value_type x)
+ { container_m->push_back(move(x)); return *this; }
+
+ back_move_iterator& operator*() { return *this; }
+ back_move_iterator& operator++() { return *this; }
+ back_move_iterator& operator++(int) { return *this; }
+};
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Similar to std::back_inserter but
+with move semantics, for movable types, otherwise with copy semantics.
+*/
+
+template <typename C> // C models Container
+inline back_move_iterator<C> back_mover(C& x) { return back_move_iterator<C>(x); }
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Placement move construction, selected when T is_movable is true
+*/
+
+template <typename T> // T models Regular
+inline void move_construct(T* p, T& x, typename move_sink<T>::type = 0)
+{
+ ::new(static_cast<void*>(p)) T(move_from<T>(x));
+}
+
+/*************************************************************************************************/
+
+
+/*!
+\ingroup move_related
+\brief Placement copy construction, selected when T is_movable is false
+*/
+template <typename T> // T models Regular
+inline void move_construct(T* p, const T& x, typename copy_sink<T>::type = 0)
+{
+ ::new(static_cast<void*>(p)) T(x);
+}
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Similar to std::uninitialized_copy but
+with move semantics, for movable types.
+*/
+template <typename I, // I models InputIterator
+ typename F> // F models ForwardIterator
+F uninitialized_move(I f, I l, F r,
+ typename move_sink<typename std::iterator_traits<I>::value_type>::type = 0)
+{
+ while (f != l) {
+ move_construct(&*r, *f);
+ ++f; ++r;
+ }
+ return r;
+}
+
+/*************************************************************************************************/
+
+/*!
+\ingroup move_related
+\brief Behaves as to std::uninitialized_copy , invoked when I's value_type is not movable.
+*/
+template <typename I, // I models InputIterator
+ typename F> // F models ForwardIterator
+F uninitialized_move(I f, I l, F r,
+ typename copy_sink<typename std::iterator_traits<I>::value_type>::type = 0)
+{
+ return std::uninitialized_copy(f, l, r);
+}
+
+/*************************************************************************************************/
+
+} // namespace boost
+
+/*************************************************************************************************/
+
+#endif
+
+/*************************************************************************************************/

Added: sandbox/move/libs/move/doc/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/doc/Jamfile.v2 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,37 @@
+# Copyright Daniel James 2008. Use, modification, and distribution are
+# subject to the Boost Software License, Version 1.0. (See accompanying
+# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+
+import doxygen ;
+
+doxygen autodoc
+ :
+ [ glob ../../../boost/move.hpp ]
+ :
+ <xsl:param>boost.doxygen.detailns=move_detail
+ ;
+
+xml move
+ :
+ move.qbk
+ ;
+
+boostbook standalone
+ :
+ move
+ :
+ <xsl:param>admon.graphics.path=images/
+ <xsl:param>navig.graphics.path=images/
+ <xsl:param>chunk.first.sections=1
+ <dependency>autodoc
+ <dependency>css
+ <dependency>images
+ ;
+
+install css : [ glob $(BOOST_ROOT)/doc/src/*.css ]
+ : <location>html ;
+install images : [ glob $(BOOST_ROOT)/doc/src/images/*.png ]
+ : <location>html/images ;
+explicit css ;
+explicit images ;
+

Added: sandbox/move/libs/move/doc/listing1.cpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/doc/listing1.cpp 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,68 @@
+//[listing1
+#include <iostream>
+#include <algorithm>
+
+#include <boost/operators.hpp>
+
+#include <boost/move.hpp>
+
+using std::swap;
+
+struct implementation : boost::equality_comparable<implementation>
+{
+ explicit implementation(int x = 0) : member(x) { }
+
+ implementation(const implementation& x) : member(x.member)
+ { std::cout << "copy remote part: " << member << std::endl; }
+
+ implementation& operator=(const implementation& x)
+ {
+ member = x.member;
+ std::cout << "assign remote part: " << member << std::endl;
+ return *this;
+ }
+
+ friend bool operator==(const implementation& x, const implementation& y)
+ { return x.member == y.member; }
+
+ int member;
+};
+
+class movable : public boost::equality_comparable<movable>
+{
+ public:
+// model concept Regular
+
+ explicit movable(int x = 0) : member(new implementation(x)) { }
+ ~movable() { delete member; }
+ movable(const movable& x) : member(new implementation(*x.member)) { }
+ // operator=() implemented below
+
+ friend bool operator==(const movable& x, const movable &y)
+ { return *x.member == *y.member; }
+
+ friend void swap(movable& x, movable& y)
+ { swap(x.member, y.member); }
+
+// model concept Movable
+
+ // move-ctor assumes ownership of remote part
+ movable(boost::move_from<movable> x) : member(x.source.member)
+ { x.source.member = 0; }
+
+ // operator=() on a movable type takes parameter by value and consumes it
+ movable& operator=(movable x)
+ { swap(*this, x); return *this; }
+
+ private:
+ implementation* member;
+};
+
+int main()
+{
+ movable x(10);
+ movable y = x;
+
+ return 0;
+}
+//]

Added: sandbox/move/libs/move/doc/listing2.cpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/doc/listing2.cpp 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,14 @@
+//[listing2
+//...
+movable f(int x, int y)
+{ return movable(x * y); }
+
+int main()
+{
+ movable x = f(10, 5);
+ movable y;
+ y = f(4, 3);
+
+ return 0;
+}
+//]

Added: sandbox/move/libs/move/doc/listing3.cpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/doc/listing3.cpp 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,19 @@
+//[listing3
+//...
+
+struct sink
+{
+ explicit sink(movable x) : member(boost::move(x)) { }
+
+ movable member;
+};
+
+int main()
+{
+ movable x = f(10, 5);
+ sink y(x); // must copy.
+ sink z(f(20, 2)); // no copy.
+
+ return 0;
+}
+//]

Added: sandbox/move/libs/move/doc/move.qbk
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/doc/move.qbk 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,164 @@
+[/ Copyright 2005-2007 Adobe Systems Incorporated
+ / 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.4]
+ [copyright 2005 2006 2007 Adobe Systems Incorporated]
+ [purpose
+ The move library is a collection of utilities for creating and using
+ types that leverage return value optimization (RVO) to avoid
+ unnecessary copies.]
+ [id move]
+ [dirname move]
+ [license
+ 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]
+ ]
+]
+
+[def __move_related__ [link move Move Library]]
+[def __concept_movable__ [@http://stlab.adobe.com/group__concept__movable.html Movable]]
+[def __concept_regular_type__ [@http://stlab.adobe.com/group__concept__regular__type.html Regular]]
+
+[section Tutorial]
+
+User defined types often have remote parts either because they are implemented using a
+pointer-to-implementation or are variable sized. Such objects can be expensive to copy
+and are often copied unnecessarily when they are returned from functions or stored in other
+objects or containers. The __move_related__ is a collection of utilities to implement types which
+can be moved to elide copying in such situations as well as utilities to assist in moving value.
+
+[section Implementing a Movable Type]
+
+A movable type models __concept_movable__. There are three components of a movable type:
+
+* Satisfy the requirements of concept __concept_regular_type__.
+* Implement a move-ctor using `move_from<>`.
+* Modify the assignment operator to take the operand by value and consume it.
+
+A typical implementation of the move-ctor will simply extract the remote part, leaving the
+source in a destructible state.
+
+The assignment operator takes the operand parameter by value. Typically the simplest way
+to destory the local remote part and consume the remote part of the operand is to swap
+contents with the operand. This is similar to the copy-ctor and swap idiom for implementing
+assignment.
+
+'''<xref linkend="listing1"/>''' shows an example movable class that implements a typical pointer-to-implementation
+(PiPl) idiom and shows that it can be used as any regular type.
+
+[import listing1.cpp]
+'''<example id="listing1">
+<title>Movable class</title>
+'''[listing1]'''
+<simpara>Output:</simpara>
+<screen>
+copy remote part: 10
+</screen>
+</example>'''
+
+[endsect]
+
+[section Returning a Movable Type]
+
+We can return a movable type from a function by value and unnessary copies will be avoided as
+the following example illustrates:
+
+[import listing2.cpp]
+'''<example id="listing2">
+<title>Return a movable type</title>
+'''[listing2]'''
+<simpara>Output:</simpara>
+<screen>
+
+</screen>
+</example>'''
+
+In this example it is not necessary to make any copies. The result of f() is constructed directly
+in place for x through a compiler optimization known as return value optimization or RVO. In the
+case of assigning to y, the same optimization allows the compiler to construct the operand for
+assignment as the result of f() which is them moved into y.
+
+[endsect]
+
+[section Implementing a Sink Function]
+
+A /sink/ is any function that copies it's argument, usually for the purpose of storing it.
+A sink is often a constructor or an insert function on a container. The `operator=()` on a movable
+type is a form of a sink function. To implement a sink function pass the argument by value and then
+use `boost::move()` to move the argument into place. Note that this technique cannot be used to
+implement `operator=()` on because it relies on assignment. '''<xref linkend="listing3"/>''' implements an example sink
+function.
+
+[import listing3.cpp]
+'''<example id="listing3">
+<title>Sink Function</title>
+'''[listing3]'''
+<simpara>Output:</simpara>
+<screen>
+copy remote part: 50
+</screen>
+</example>'''
+
+
+Here again unnessary copies are eliminated. Although `boost::move()` can be used anytime to force the
+move of an object, it should only be used as part of an explicit sink function otherwise it hinders
+the understanding of code.
+
+[endsect]
+
+[endsect]
+
+[section Utilities]
+
+There are many utilities as part of the move library which can be used to move elements instead of
+copying them. These are useful when building containers or dealing with sink operations which must
+manage a collection of movable objects. Generally these operations parallel the associated copying
+algorithms from STL. Examples:
+
+[table
+ [[Move][Copy][Comment]]
+ [[`boost::move()`][`std::copy`][Not to be confused with the single argument boost::move()]]
+ [[`boost::move_backward()`][`std::copy_backward`]]
+ [[`boost::back_move_iterator()`][`std::back_insert_iterator`]]
+ [[`boost::back_mover()`][`std::back_inserter`]]
+ [[`boost::move_construct()`][`std::construct`]]
+ [[`boost::uninitialized_move()`][`std::uninitialized_copy`]]
+]
+
+[endsect]
+
+[section Advanced Topics]
+
+The `boost::move()` function is a NOP if the argument is not movable, however, when a non-movable
+item is passed to a sink this may still result in an unnecessary copy - one to the sink and one to
+copy the argument of the sink into place. To avoid the additional copy, two forms of a sink function
+can be provided, one for movable types and one for copyable types. The `boost::move_sink<>` and
+`boost::copy_sink<>` tags can be used to select between the two functions. See the
+implementation of `boost::move_construct()` as an example.
+
+If a sink function is a member of a template class, the same issue with regard to unnecessary copies
+can occur. In this case, it is desirable to distinguish between the a copy and move sink as above
+but also to allow implicit conversions to the type stored in the container. To allow this use the
+two argument form of `boost::move_sink<>` and `boost::copy_sink<>`. See the implementation of
+`adobe::vector::push_back()` as an example.
+
+[endsect]
+
+[section Theory of Operation]
+
+/to be written/
+
+[endsect]
+
+[section Acknowledgments]
+
+This is based on the [@http://stlab.adobe.com/group__move__related.html Adobe Move Library]
+which was inspired by the move library written by Dave Abrahams and the work on move
+done by Dave Abrahams and Howard Hinnant.
+
+[endsect]
+
+[xinclude autodoc.xml]

Added: sandbox/move/libs/move/test/Jamfile.v2
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/test/Jamfile.v2 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,3 @@
+import testing ;
+project boost/move ;
+run main.cpp /boost/unit_test//boost_unit_test_framework ;

Added: sandbox/move/libs/move/test/main.cpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/test/main.cpp 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,118 @@
+/*
+ Copyright 2005-2007 Adobe Systems Incorporated
+ Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
+ or a copy at http://stlab.adobe.com/licenses.html)
+*/
+
+/*************************************************************************************************/
+
+#define BOOST_TEST_MAIN
+#include <boost/test/unit_test.hpp>
+
+#include <iterator>
+#include <vector>
+
+#include <boost/range/begin.hpp>
+#include <boost/range/end.hpp>
+
+#include <boost/move.hpp>
+#include "./vector.hpp"
+
+/*************************************************************************************************/
+
+// Taken from adobe::destroy
+
+template <typename T> // T models Regular
+inline void destroy(T* p) { p->~T(); }
+
+template <typename F> // F models ForwardIterator
+inline void destroy(F f, F l)
+{
+ while (f != l) {
+ destroy(&*f);
+ ++f;
+ }
+}
+
+/*************************************************************************************************/
+
+BOOST_AUTO_TEST_CASE(move_test)
+{
+ typedef test_vector<int> vector_t;
+ typedef test_vector<vector_t> vector_vector_t;
+ typedef std::vector<int> std_vector_t;
+ typedef test_vector<std_vector_t> vector_std_vector_t;
+
+ // Test is_movable<> template function
+
+ BOOST_CHECK(!boost::is_movable<std_vector_t>::value);
+ BOOST_CHECK(boost::is_movable<vector_t>::value);
+
+ { // Test move_sink<> via push_back
+ vector_t x(3, 4);
+
+ x.push_back(7);
+ int* addr = x.begin();
+ vector_vector_t y;
+ y.push_back(boost::move(x));
+
+ BOOST_CHECK_EQUAL(addr, &y[0][0]);
+ }
+
+ { // Test move with a copy only type
+ std_vector_t x(3, 4);
+ vector_std_vector_t y;
+ y.push_back(boost::move(x)); // really copies
+ }
+
+ { // Test move algorithm and back_mover
+ vector_t x(3, 4);
+ x.push_back(7);
+
+ vector_vector_t y;
+ y.push_back(x);
+ y.push_back(x);
+ y.push_back(x);
+
+ vector_vector_t z;
+ int* addr = &y.back().back();
+ boost::move(y, boost::back_mover(z));
+ BOOST_CHECK_EQUAL(addr, &z.back().back());
+ }
+
+ { // Test move_backward
+ vector_t x(3, 4);
+ x.push_back(7);
+
+ vector_vector_t y;
+ y.push_back(x);
+ y.push_back(x);
+ y.push_back(x);
+
+ vector_vector_t z(y);
+ int* addr = &y.back().back();
+ boost::move_backward(y, z.end());
+ BOOST_CHECK_EQUAL(addr, &z.back().back());
+ }
+
+ { // Test move_construct
+ vector_t x(3, 4);
+ vector_t y(x);
+ x.~vector_t();
+ int* addr = y.begin();
+ boost::move_construct(&x, y);
+ BOOST_CHECK_EQUAL(addr, x.begin());
+ }
+
+ { // Test uninitialized_move
+ vector_t x[3];
+ vector_t y[3];
+ y[0].push_back(7);
+
+ destroy(&x[0], &x[3]);
+
+ int* addr = y[0].begin();
+ boost::uninitialized_move(&y[0], &y[3], &x[0]);
+ BOOST_CHECK_EQUAL(addr, x[0].begin());
+ }
+}

Added: sandbox/move/libs/move/test/vector.hpp
==============================================================================
--- (empty file)
+++ sandbox/move/libs/move/test/vector.hpp 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,123 @@
+
+// Copyright 2008 Daniel James.
+// 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)
+
+// A vector-like class to test moving without the aid of adobe::vector. (Not a
+// compliant STL sequence, and not at all fit for purpose).
+
+#if !defined(BOOST_MOVE_TEST_VECTOR_HEADER)
+#define BOOST_MOVE_TEST_VECTOR_HEADER
+
+#include <boost/operators.hpp>
+
+template <class T>
+class test_vector : public boost::equality_comparable<test_vector<T> >
+{
+ struct array {
+ T* begin_;
+ T* end_;
+ T* storage_end_;
+
+ explicit array(std::size_t size = 0)
+ : begin_(size == 0 ? (T*) 0 : (T*) new char[size * sizeof(T)]),
+ end_(begin_), storage_end_(begin_ + size)
+ {
+ }
+
+ ~array()
+ {
+ if(begin_) {
+ for(T* it = begin_; it != end_; ++it) {
+ it->~T();
+ }
+ delete[]((char*) begin_);
+ }
+ }
+
+ void swap(array& x) {
+ std::swap(begin_, x.begin_);
+ std::swap(end_, x.end_);
+ std::swap(storage_end_, x.storage_end_);
+ }
+ private:
+ array(array const&);
+ array& operator=(array const&);
+ };
+
+ array data_;
+public:
+ typedef T value_type;
+ typedef T* iterator;
+ typedef T const* const_iterator;
+
+ test_vector() : data_() {}
+ test_vector(std::size_t n, T const& x)
+ : data_(n) {
+ std::uninitialized_fill_n(data_.begin_, n, x);
+ data_.end_ = data_.begin_ + n;
+ }
+ ~test_vector() {}
+ test_vector(test_vector const& x)
+ : data_(x.size())
+ {
+ data_.end_ = std::uninitialized_copy(x.begin(), x.end(), data_.begin_);
+ }
+
+ friend bool operator==(test_vector const& x, test_vector const& y) {
+ return x.size() == y.size() && std::equal(x.begin(), x.end(), y.begin());
+ }
+
+ std::size_t size() const{
+ return data_.end_ - data_.begin_;
+ }
+
+ friend void swap(test_vector& x, test_vector& y) {
+ x.data_.swap(y.data_);
+ }
+
+ // model concept Movable
+
+ test_vector(boost::move_from<test_vector> x)
+ : data_() {
+ swap(*this, x.source);
+ }
+
+ test_vector& operator=(test_vector x)
+ { swap(*this, x); return *this; }
+
+ T* begin() { return data_.begin_; }
+ T* end() { return data_.end_; }
+ T const* begin() const { return data_.begin_; }
+ T const* end() const { return data_.end_; }
+ T const* cbegin() const { return data_.begin_; }
+ T const* cend() const { return data_.end_; }
+
+ T& operator[](std::ptrdiff_t n) { return *(data_.begin_ + n); }
+ T const& operator[](std::ptrdiff_t n) const{ return *(data_.begin_ + n); }
+
+ T& back() { return *(data_.end_ - 1); }
+ T const& back() const{ return *(data_.end_ - 1); }
+
+ template <class U>
+ void push_back(U const& x, typename boost::copy_sink<U, T>::type = 0) {
+ if(data_.end_ == data_.storage_end_) resize(data_.begin_ ? size() * 2 : 4);
+ std::uninitialized_fill_n(data_.end_, 1, x);
+ ++data_.end_;
+ }
+
+ template <class U>
+ void push_back(U x, typename boost::move_sink<U, T>::type = 0) {
+ if(data_.end_ == data_.storage_end_) resize(data_.begin_ ? size() * 2 : 4);
+ data_.end_ = boost::uninitialized_move(&x, &x + 1, data_.end_);
+ }
+private:
+ void resize(std::size_t new_size) {
+ array new_data(new_size);
+ new_data.end_ = boost::uninitialized_move(
+ data_.begin_, data_.end_, new_data.begin_);
+ data_.swap(new_data);
+ }
+};
+
+#endif

Added: sandbox/move/project-root.jam
==============================================================================
--- (empty file)
+++ sandbox/move/project-root.jam 2008-04-05 14:19:52 EDT (Sat, 05 Apr 2008)
@@ -0,0 +1,53 @@
+#
+# Copyright (c) 2006 João Abecasis
+#
+# 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)
+#
+
+##
+## IMPORTANT NOTE: This file MUST NOT be copied over a boost installation
+##
+
+path-constant top : . ;
+
+import modules ;
+import path ;
+
+local boost-root = [ modules.peek : BOOST_ROOT ] ;
+local math-header-include = $(top)/../.. ;
+
+if ! $(boost-root)
+{
+ local boost-search-dirs = [ modules.peek : BOOST_BUILD_PATH ] ;
+
+ for local dir in $(boost-search-dirs)
+ {
+ if [ path.glob $(dir)/../../../ : boost/version.hpp ]
+ {
+ boost-root += $(dir)/../../../ ;
+ }
+ }
+
+ if $(boost-root)
+ {
+ boost-root = [ path.make $(boost-root[1]) ] ;
+ }
+ else
+ {
+ ECHO "Warning: couldn't find BOOST_ROOT in" $(boost-root) ;
+ }
+}
+
+use-project /boost/unit_test : $(boost-root)/libs/test/build ;
+
+project move
+ : requirements
+ <include>.
+ <include>$(boost-root)
+ : # build everything in ./bin.v2
+ build-dir bin.v2
+ ;
+
+path-constant BOOST_ROOT : $(boost-root) ;


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