|
Alec Leamas |
5ed0b82 |
/*
|
|
Alec Leamas |
5ed0b82 |
Copyright 2005-2007 Adobe Systems Incorporated
|
|
Alec Leamas |
5ed0b82 |
Distributed under the MIT License (see accompanying file LICENSE_1_0_0.txt
|
|
Alec Leamas |
5ed0b82 |
or a copy at http://stlab.adobe.com/licenses.html)
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
#ifndef ADOBE_MOVE_HPP
|
|
Alec Leamas |
5ed0b82 |
#define ADOBE_MOVE_HPP
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
#include <cassert>
|
|
Alec Leamas |
5ed0b82 |
#include <iterator>
|
|
Alec Leamas |
5ed0b82 |
#include <memory>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
#include <boost/iterator/iterator_adaptor.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/mpl/bool.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/mpl/and.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/mpl/or.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/mpl/not.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/mpl/assert.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/range/begin.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/range/end.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/type_traits/is_convertible.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/type_traits/is_same.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/type_traits/is_class.hpp>
|
|
Alec Leamas |
5ed0b82 |
#include <boost/utility/enable_if.hpp>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\defgroup move_related Move Library
|
|
Alec Leamas |
5ed0b82 |
\ingroup utility
|
|
Alec Leamas |
5ed0b82 |
\brief
|
|
Alec Leamas |
5ed0b82 |
The move library is a collection of utilities for creating and using types that leverage
|
|
Alec Leamas |
5ed0b82 |
return value optimization (RVO) to avoid unnecessary copies.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\section move_tutorial Tutorial
|
|
Alec Leamas |
5ed0b82 |
User defined types often have remote parts either because they are implemented using a
|
|
Alec Leamas |
5ed0b82 |
pointer-to-implementation or are variable sized. Such objects can be expensive to copy
|
|
Alec Leamas |
5ed0b82 |
and are often copied unnecessarily when they are returned from functions or stored in other
|
|
Alec Leamas |
5ed0b82 |
objects or containers. The \ref move_related is a collection of utilities to implement types which
|
|
Alec Leamas |
5ed0b82 |
can be moved to elide copying in such situations as well as utilities to assist in moving value.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Implementing a Movable Type
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
A movable type models \ref concept_movable. There are three components of a movable type:
|
|
Alec Leamas |
5ed0b82 |
- Satisfy the requirements of concept \ref concept_regular_type.
|
|
Alec Leamas |
5ed0b82 |
- Implement a move-ctor using move_from<>.
|
|
Alec Leamas |
5ed0b82 |
- Modify the assignment operator to take the operand by value and consume it.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
A typical implementation of the move-ctor will simply extract the remote part, leaving the
|
|
Alec Leamas |
5ed0b82 |
source in a destructible state.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
The assignment operator takes the operand parameter by value. Typically the simplest way
|
|
Alec Leamas |
5ed0b82 |
to destory the local remote part and consume the remote part of the operand is to swap
|
|
Alec Leamas |
5ed0b82 |
contents with the operand. This is similar to the copy-ctor and swap idiom for implementing
|
|
Alec Leamas |
5ed0b82 |
assignment.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
Listing 1 shows an example movable class that implements a typical pointer-to-implementation
|
|
Alec Leamas |
5ed0b82 |
(PiPl) idiom and shows that it can be used as any regular type.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\code
|
|
Alec Leamas |
5ed0b82 |
#include <iostream>
|
|
Alec Leamas |
5ed0b82 |
#include <algorithm>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
#include <boost/operators.hpp>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
#include <adobe/move.hpp>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
using std::swap;
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
struct implementation : boost::equality_comparable<implementation>
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
explicit implementation(int x = 0) : member(x) { }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
implementation(const implementation& x) : member(x.member)
|
|
Alec Leamas |
5ed0b82 |
{ std::cout << "copy remote part: " << member << std::endl; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
implementation& operator=(const implementation& x)
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
member = x.member;
|
|
Alec Leamas |
5ed0b82 |
std::cout << "assign remote part: " << member << std::endl;
|
|
Alec Leamas |
5ed0b82 |
return *this;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
friend bool operator==(const implementation& x, const implementation& y)
|
|
Alec Leamas |
5ed0b82 |
{ return x.member == y.member; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
int member;
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
class movable : public boost::equality_comparable<movable>
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
public:
|
|
Alec Leamas |
5ed0b82 |
// model concept Regular
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
explicit movable(int x = 0) : member(new implementation(x)) { }
|
|
Alec Leamas |
5ed0b82 |
~movable() { delete member; }
|
|
Alec Leamas |
5ed0b82 |
movable(const movable& x) : member(new implementation(*x.member)) { }
|
|
Alec Leamas |
5ed0b82 |
// operator=() implemented below
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
friend bool operator==(const movable& x, const movable &y)
|
|
Alec Leamas |
5ed0b82 |
{ return *x.member == *y.member; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
friend void swap(movable& x, movable& y)
|
|
Alec Leamas |
5ed0b82 |
{ swap(x.member, y.member); }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
// model concept Movable
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
// move-ctor assumes ownership of remote part
|
|
Alec Leamas |
5ed0b82 |
movable(adobe::move_from<movable> x) : member(x.source.member)
|
|
Alec Leamas |
5ed0b82 |
{ x.source.member = 0; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
// operator=() on a movable type takes parameter by value and consumes it
|
|
Alec Leamas |
5ed0b82 |
movable& operator=(movable x)
|
|
Alec Leamas |
5ed0b82 |
{ swap(*this, x); return *this; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
private:
|
|
Alec Leamas |
5ed0b82 |
implementation* member;
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
int main()
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
movable x(10);
|
|
Alec Leamas |
5ed0b82 |
movable y = x;
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
return 0;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
\endcode
|
|
Alec Leamas |
5ed0b82 |
<center>Listing 1</center>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\verbatim
|
|
Alec Leamas |
5ed0b82 |
copy remote part: 10
|
|
Alec Leamas |
5ed0b82 |
\endverbatim
|
|
Alec Leamas |
5ed0b82 |
<center>Output of Listing 1</center>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Returning a Movable Type
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
We can return a movable type from a function by value and unnessary copies will be avoided as
|
|
Alec Leamas |
5ed0b82 |
Listing 2 illustrates:
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\code
|
|
Alec Leamas |
5ed0b82 |
//...
|
|
Alec Leamas |
5ed0b82 |
movable f(int x, int y)
|
|
Alec Leamas |
5ed0b82 |
{ return movable(x * y); }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
int main()
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
movable x = f(10, 5);
|
|
Alec Leamas |
5ed0b82 |
movable y;
|
|
Alec Leamas |
5ed0b82 |
y = f(4, 3);
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
return 0;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
\endcode
|
|
Alec Leamas |
5ed0b82 |
<center>Listing 2</center>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\verbatim
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\endverbatim
|
|
Alec Leamas |
5ed0b82 |
<center>Ouput of Listing 2</center>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
In this example it is not necessary to make any copies. The result of f() is constructed directly
|
|
Alec Leamas |
5ed0b82 |
in place for x through a compiler optimization known as return value optimization or RVO. In the
|
|
Alec Leamas |
5ed0b82 |
case of assigning to y, the same optimization allows the compiler to construct the operand for
|
|
Alec Leamas |
5ed0b82 |
assignment as the result of f() which is them moved into y.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Implementing a Sink Function
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
A sink is any function that copies it's argument, usually for the purpose of storing it.
|
|
Alec Leamas |
5ed0b82 |
A sink is often a constructor or an insert function on a container. The \c operator=() on a movable
|
|
Alec Leamas |
5ed0b82 |
type is a form of a sink function. To implement a sink function pass the argument by value and then
|
|
Alec Leamas |
5ed0b82 |
use \c adobe::move() to move the argument into place. Note that this technique cannot be used to
|
|
Alec Leamas |
5ed0b82 |
implement \c operator=() on because it relies on assignment. Listing 3 implements an example sink
|
|
Alec Leamas |
5ed0b82 |
function.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\code
|
|
Alec Leamas |
5ed0b82 |
//...
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
struct sink
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
explicit sink(movable x) : member(adobe::move(x)) { }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
movable member;
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
int main()
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
movable x = f(10, 5);
|
|
Alec Leamas |
5ed0b82 |
sink y(x); // must copy.
|
|
Alec Leamas |
5ed0b82 |
sink z(f(20, 2)); // no copy.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
return 0;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
\endcode
|
|
Alec Leamas |
5ed0b82 |
<center>Listing 3</center>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\verbatim
|
|
Alec Leamas |
5ed0b82 |
copy remote part: 50
|
|
Alec Leamas |
5ed0b82 |
\endverbatim
|
|
Alec Leamas |
5ed0b82 |
<center>Output of Listing 3</center>
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
Here again unnessary copies are eliminated. Although adobe::move() can be used anytime to force the
|
|
Alec Leamas |
5ed0b82 |
move of an object, it should only be used as part of an explicit sink function otherwise it hinders
|
|
Alec Leamas |
5ed0b82 |
the understanding of code.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Utilities
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
There are many utilities as part of the move library which can be used to move elements instead of
|
|
Alec Leamas |
5ed0b82 |
copying them. These are useful when building containers or dealing with sink operations which must
|
|
Alec Leamas |
5ed0b82 |
manage a collection of movable objects. Generally these operations parallel the associated copying
|
|
Alec Leamas |
5ed0b82 |
algorithms from STL. Examples:
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
MoveCopyComment
|
|
Alec Leamas |
5ed0b82 |
adobe::move()std::copyNot to be confused with the single argument adobe::move()
|
|
Alec Leamas |
5ed0b82 |
adobe::move_backward()std::copy_backward
|
|
Alec Leamas |
5ed0b82 |
adobe::back_move_iterator()std::back_insert_iterator
|
|
Alec Leamas |
5ed0b82 |
adobe::back_mover()std::back_inserter
|
|
Alec Leamas |
5ed0b82 |
adobe::move_construct()std::construct
|
|
Alec Leamas |
5ed0b82 |
adobe::uninitialized_move()std::uninitialized_copy
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Advanced Topics
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
The \c adobe::move() function is a NOP if the argument is not movable, however, when a non-movable
|
|
Alec Leamas |
5ed0b82 |
item is passed to a sink this may still result in an unnecessary copy - one to the sink and one to
|
|
Alec Leamas |
5ed0b82 |
copy the argument of the sink into place. To avoid the additional copy, two forms of a sink function
|
|
Alec Leamas |
5ed0b82 |
can be provided, one for movable types and one for copyable types. The \c adobe::move_sink<> and
|
|
Alec Leamas |
5ed0b82 |
\c adobe::copy_sink<> tags can be used to select between the two functions. See the
|
|
Alec Leamas |
5ed0b82 |
implementation of \c adobe::move_construct() as an example.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
If a sink function is a member of a template class, the same issue with regard to unnecessary copies
|
|
Alec Leamas |
5ed0b82 |
can occur. In this case, it is desirable to distinguish between the a copy and move sink as above
|
|
Alec Leamas |
5ed0b82 |
but also to allow implicit conversions to the type stored in the container. To allow this use the
|
|
Alec Leamas |
5ed0b82 |
two argument form of \c adobe::move_sink<> and \c adobe::copy_sink<>. See the implementation of
|
|
Alec Leamas |
5ed0b82 |
\c adobe::vector::push_back() as an example.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Theory of Operation
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
to be written
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
\par Acknowledgments:
|
|
Alec Leamas |
5ed0b82 |
The move library was inspired by the move library written by Dave Abrahams and the work on move
|
|
Alec Leamas |
5ed0b82 |
done by Dave Abrahams and Howard Hinnant.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
namespace adobe {
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
namespace implementation {
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template <typename T>
|
|
Alec Leamas |
5ed0b82 |
struct class_has_move_assign {
|
|
Alec Leamas |
5ed0b82 |
class type {
|
|
Alec Leamas |
5ed0b82 |
typedef T& (T::*E)(T t);
|
|
Alec Leamas |
5ed0b82 |
typedef char (&no_type)[1];
|
|
Alec Leamas |
5ed0b82 |
typedef char (&yes_type)[2];
|
|
Alec Leamas |
5ed0b82 |
template <E e> struct sfinae { typedef yes_type type; };
|
|
Alec Leamas |
5ed0b82 |
template <class U>
|
|
Alec Leamas |
5ed0b82 |
static typename sfinae<&U::operator=>::type test(int);
|
|
Alec Leamas |
5ed0b82 |
template <class U>
|
|
Alec Leamas |
5ed0b82 |
static no_type test(...);
|
|
Alec Leamas |
5ed0b82 |
public:
|
|
Alec Leamas |
5ed0b82 |
enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template<typename T>
|
|
Alec Leamas |
5ed0b82 |
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
class test_can_convert_anything { };
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
} //namespace implementation
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*
|
|
Alec Leamas |
5ed0b82 |
REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
|
|
Alec Leamas |
5ed0b82 |
boost::is_convertible<T, T> fails to compile.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template <typename T, typename U>
|
|
Alec Leamas |
5ed0b82 |
struct is_convertible : boost::mpl::or_<
|
|
Alec Leamas |
5ed0b82 |
boost::is_same<T, U>,
|
|
Alec Leamas |
5ed0b82 |
boost::is_convertible<T, U>
|
|
Alec Leamas |
5ed0b82 |
> { };
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief move_from is used for move_ctors.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template <typename T>
|
|
Alec Leamas |
5ed0b82 |
struct move_from
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
explicit move_from(T& x) : source(x) { }
|
|
Alec Leamas |
5ed0b82 |
T& source;
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief The is_movable trait can be used to identify movable types.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template <typename T>
|
|
Alec Leamas |
5ed0b82 |
struct is_movable : boost::mpl::and_<
|
|
Alec Leamas |
5ed0b82 |
boost::is_convertible<move_from<T>, T>,
|
|
Alec Leamas |
5ed0b82 |
implementation::has_move_assign<T>,
|
|
Alec Leamas |
5ed0b82 |
boost::mpl::not_<boost::is_convertible<implementation::test_can_convert_anything, T> >
|
|
Alec Leamas |
5ed0b82 |
> { };
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief copy_sink and move_sink are used to select between overloaded operations according to
|
|
Alec Leamas |
5ed0b82 |
whether type T is movable and convertible to type U.
|
|
Alec Leamas |
5ed0b82 |
\sa move
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template
|
|
Alec Leamas |
5ed0b82 |
typename U = T,
|
|
Alec Leamas |
5ed0b82 |
typename R = void*>
|
|
Alec Leamas |
5ed0b82 |
struct copy_sink : boost::enable_if<
|
|
Alec Leamas |
5ed0b82 |
boost::mpl::and_<
|
|
Alec Leamas |
5ed0b82 |
adobe::is_convertible<T, U>,
|
|
Alec Leamas |
5ed0b82 |
boost::mpl::not_<is_movable<T> >
|
|
Alec Leamas |
5ed0b82 |
>,
|
|
Alec Leamas |
5ed0b82 |
R
|
|
Alec Leamas |
5ed0b82 |
>
|
|
Alec Leamas |
5ed0b82 |
{ };
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief move_sink and copy_sink are used to select between overloaded operations according to
|
|
Alec Leamas |
5ed0b82 |
whether type T is movable and convertible to type U.
|
|
Alec Leamas |
5ed0b82 |
\sa move
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template
|
|
Alec Leamas |
5ed0b82 |
typename U = T,
|
|
Alec Leamas |
5ed0b82 |
typename R = void*>
|
|
Alec Leamas |
5ed0b82 |
struct move_sink : boost::enable_if<
|
|
Alec Leamas |
5ed0b82 |
boost::mpl::and_<
|
|
Alec Leamas |
5ed0b82 |
adobe::is_convertible<T, U>,
|
|
Alec Leamas |
5ed0b82 |
is_movable<T>
|
|
Alec Leamas |
5ed0b82 |
>,
|
|
Alec Leamas |
5ed0b82 |
R
|
|
Alec Leamas |
5ed0b82 |
>
|
|
Alec Leamas |
5ed0b82 |
{ };
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief This version of move is selected when T is_movable . It in turn calls the move
|
|
Alec Leamas |
5ed0b82 |
constructor. This call, with the help of the return value optimization, will cause x to be moved
|
|
Alec Leamas |
5ed0b82 |
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template <typename T>
|
|
Alec Leamas |
5ed0b82 |
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief This version of move is selected when T is not movable . The net result will be that
|
|
Alec Leamas |
5ed0b82 |
x gets copied.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template <typename T>
|
|
Alec Leamas |
5ed0b82 |
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief Iterator pair version of move. Similar to std::copy but with move semantics,
|
|
Alec Leamas |
5ed0b82 |
for movable types, otherwise with copy semantics.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template
|
|
Alec Leamas |
5ed0b82 |
typename O> // O models OutputIterator
|
|
Alec Leamas |
5ed0b82 |
O move(I f, I l, O result)
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
while (f != l) {
|
|
Alec Leamas |
5ed0b82 |
*result = adobe::move(*f);
|
|
Alec Leamas |
5ed0b82 |
++f; ++result;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
return result;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief \ref concept_convertible_to_range version of move. Similar to copy but with move semantics,
|
|
Alec Leamas |
5ed0b82 |
for movable types, otherwise with copy semantics.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template
|
|
Alec Leamas |
5ed0b82 |
typename O> // O models OutputIterator
|
|
Alec Leamas |
5ed0b82 |
inline O move(I& in, O out) { return adobe::move(boost::begin(in), boost::end(in), out); }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief Iterator pair version of move_backwards. Similar to std::copy_backwards but with move semantics,
|
|
Alec Leamas |
5ed0b82 |
for movable types, otherwise with copy semantics.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template
|
|
Alec Leamas |
5ed0b82 |
typename O> // O models BidirectionalIterator
|
|
Alec Leamas |
5ed0b82 |
O move_backward(I f, I l, O result)
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
while (f != l) {
|
|
Alec Leamas |
5ed0b82 |
--l; --result;
|
|
Alec Leamas |
5ed0b82 |
*result = adobe::move(*l);
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
return result;
|
|
Alec Leamas |
5ed0b82 |
}
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief \ref concept_convertible_to_range version of move_backwards. Similar to std::copy_backwards but
|
|
Alec Leamas |
5ed0b82 |
with move semantics, for movable types, otherwise with copy semantics.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
template
|
|
Alec Leamas |
5ed0b82 |
typename O> // O models BidirectionalIterator
|
|
Alec Leamas |
5ed0b82 |
inline O move_backward(I& in, O out)
|
|
Alec Leamas |
5ed0b82 |
{ return adobe::move_backward(boost::begin(in), boost::end(in), out); }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief Similar to std::back_insert_iterator but
|
|
Alec Leamas |
5ed0b82 |
with move semantics, for movable types, otherwise with copy semantics.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template <typename C> // C models Container
|
|
Alec Leamas |
5ed0b82 |
class back_move_iterator : public std::iterator<std::output_iterator_tag, void, void, void, void>
|
|
Alec Leamas |
5ed0b82 |
{
|
|
Alec Leamas |
5ed0b82 |
C* container_m;
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
public:
|
|
Alec Leamas |
5ed0b82 |
typedef C container_type;
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
explicit back_move_iterator(C& x) : container_m(&x) { }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
back_move_iterator& operator=(typename C::value_type x)
|
|
Alec Leamas |
5ed0b82 |
{ container_m->push_back(adobe::move(x)); return *this; }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
back_move_iterator& operator*() { return *this; }
|
|
Alec Leamas |
5ed0b82 |
back_move_iterator& operator++() { return *this; }
|
|
Alec Leamas |
5ed0b82 |
back_move_iterator& operator++(int) { return *this; }
|
|
Alec Leamas |
5ed0b82 |
};
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*!
|
|
Alec Leamas |
5ed0b82 |
\ingroup move_related
|
|
Alec Leamas |
5ed0b82 |
\brief Similar to std::back_inserter but
|
|
Alec Leamas |
5ed0b82 |
with move semantics, for movable types, otherwise with copy semantics.
|
|
Alec Leamas |
5ed0b82 |
*/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
template <typename C> // C models Container
|
|
Alec Leamas |
5ed0b82 |
inline back_move_iterator<C> back_mover(C& x) { return back_move_iterator<C>(x); }
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
} // namespace adobe
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
#endif
|
|
Alec Leamas |
5ed0b82 |
|
|
Alec Leamas |
5ed0b82 |
/*************************************************************************************************/
|