|
Boost : |
Subject: [boost] [move] Unifying move emulation code in boost
From: Ion Gaztañaga (igaztanaga_at_[hidden])
Date: 2009-01-04 16:54:02
Hi,
Howard's unique_ptr contribution has shown again the need for a unified
move emulation in Boost. We already have move emulation at least in 5
libraries:
-> Interprocess: based on sandbox boost.move library, return types are
wrapped in a move_return type.
-> Unordered: based on Adobe's move library. It's more advanced than the
previous one, but Adobe's own library says
(http://stlab.adobe.com/group__move__related.html) that a Movable type
must satisfy the requirements of concept Regular, which has copy
constructor (thus disabling move-only types!). I don't know if the move
emulation itself uses Regular requirements.
-> Thread: similar to Howard's unique_ptr move emulation code, user code
never sees move_xxx or similar classes.
-> Ptr_container: a simple emulation used for static_move_ptr, that
could be replaced with a boost::unique_ptr class.
-> Variant: MOJO-based emulation (similar to the one used by
Interprocess). I think it can be easily replaced with unique_ptr-style
emulation.
We've been waiting the move library for months, but the fact is that we
can't continue having ad-hoc solutions for each library. boost::thread
objects must be stored somewhere and unordered containers and
boost::interprocess containers are already move-aware. I want to make
Intrusive also move-aware but I won't do it until there is some general
consensus on what's the common move emulation.
I think code changes in boost::thread and boost::unordered would be
minimal if we adopt a solution similar to the one used by Howard's
unique_ptr. Interprocess changes are heavier but I'm reading to adapt
the library to that solution.
I've written (attached) a small, surely not complete, but usable
boost/move.hpp header (ok, it could go to boost/detail/move.hpp until a
decent review is done) that is tested with a movable class in the file
movable_test.cpp, both with Visual 7.1 and move-enabled GCC 4.3.
The goal of this post is to know if that header file would be enough for
all current libraries using move emulation. I have more suggestions (new
traits like has_trivial_destructor_after_move<>...) but the main
question is if that header can be used to agree a common protocol
between us. It would be really nice if we could rework our code for
Boost 1.39.
If the header contains enough for everyone, I'm ready to write some
documentation and tests. I know that this Move library is not what many
expect (common macros and utilities to write the same code for
rvalue-enabled and older compilers) but I'm afraid entropy has already
grown too much ;-) and we can't continue waiting while we add more and
more emulation code to Boost.
Regards,
Ion
// 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)
// (C) Copyright 2007-8 Anthony Williams
// (C) Copyright 2009 Howard Hinnant
// (C) Copyright 2009 Ion Gaztanaga
#include <boost/config.hpp>
#include <boost/type_traits/is_convertible.hpp>
#ifndef BOOST_HAS_RVALUE_REFS
#ifndef BOOST_NO_SFINAE
#include <boost/utility/enable_if.hpp>
#endif
#else //#ifndef BOOST_HAS_RVALUE_REFS
#include <boost/type_traits/remove_reference.hpp>
#endif
namespace boost {
#include <boost/config/abi_prefix.hpp>
#ifndef BOOST_HAS_RVALUE_REFS
template<class T>
class rv
{
private:
rv &operator=(const rv&);
T& r_;
public:
explicit rv(T& r) : r_(r) {}
T* operator->() {return &r_;}
T& operator*() {return r_;}
};
template<class T>
class is_movable
{
public:
static const bool value = boost::is_convertible<T&, rv<T> >::value;
};
#ifndef BOOST_NO_SFINAE
template<typename T>
typename boost::enable_if<boost::is_movable<T>, T>::type move(T& t)
{
return T(rv<T>(t));
}
#endif
template<typename T>
rv<T> move(rv<T> t)
{
return t;
}
#define BOOST_ENABLE_MOVE_EMULATION(TYPE)\
operator boost::rv<TYPE>() \
{ return boost::rv<TYPE>(*this); }\
//
#define BOOST_SWAP_BASED_MOVE_ASSIGN(TYPE)\
TYPE& operator=(boost::rv<TYPE> r) \
{ \
TYPE tmp(r); \
this->swap(tmp); \
return *this; \
} \
//
#else //#ifndef BOOST_HAS_RVALUE_REFS
#define BOOST_ENABLE_MOVE_EMULATION(TYPE)\
//
#define BOOST_SWAP_BASED_MOVE_ASSIGN(TYPE)\
TYPE& operator=(TYPE &&r) \
{ \
TYPE tmp(boost::move(r)); \
this->swap(tmp); \
return *this; \
} \
//
template <class T>
struct move_identity_type
{
typedef T type;
};
template <class T>
inline T&& forward(typename boost::move_identity_type<T>::type&& t)
{ return t; }
template <class T>
inline typename boost::remove_reference<T>::type&& move(T&& t)
{ return t; }
template <class T, class U>
class move_is_convertible
{
typedef char true_t;
class false_t { char dummy[2]; };
static true_t dispatch(U);
static false_t dispatch(...);
static T trigger();
public:
enum { value = sizeof(dispatch(trigger())) == sizeof(true_t) };
};
template<class T>
class is_movable
{
public:
static const bool value = move_is_convertible<T&&, T>::value;
};
#endif //#ifndef BOOST_HAS_RVALUE_REFS
#include <boost/config/abi_suffix.hpp>
} //namespace boost {
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk