blob: 2a010cda57dfd2eae5cb01a9059e5177dfd346ce [file] [log] [blame]
//////////////////////////////////////////////////////////////////////////////
//
// (C) Copyright 2007, 2008 Steven Watanabe, Joseph Gauterin, Niels Dekker
// (C) Copyright Ion Gaztanaga 2005-2013. 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/container for documentation.
//
//////////////////////////////////////////////////////////////////////////////
#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP
#define BOOST_MOVE_ADL_MOVE_SWAP_HPP
#ifndef BOOST_CONFIG_HPP
# include <boost/config.hpp>
#endif
#
#if defined(BOOST_HAS_PRAGMA_ONCE)
# pragma once
#endif
//Based on Boost.Core's swap.
//Many thanks to Steven Watanabe, Joseph Gauterin and Niels Dekker.
#include <boost/config.hpp>
#include <cstddef> //for std::size_t
//Try to avoid including <algorithm>, as it's quite big
#if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB)
#include <utility> //Dinkum libraries define std::swap in utility which is lighter than algorithm
#elif defined(BOOST_GNU_STDLIB)
//For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions
//use the good old stl_algobase header, which is quite lightweight
#if !defined(BOOST_GCC) || ((__GNUC__ < 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ < 3)))
#include <bits/stl_algobase.h>
#elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
//In GCC 4.3 a tiny stl_move.h was created with swap and move utilities
#include <bits/stl_move.h>
#else
//In GCC 4.4 stl_move.h was renamed to move.h
#include <bits/move.h>
#endif
#elif defined(_LIBCPP_VERSION)
#include <type_traits> //The initial import of libc++ defines std::swap and still there
#elif __cplusplus >= 201103L
#include <utility> //Fallback for C++ >= 2011
#else
#include <algorithm> //Fallback for C++98/03
#endif
#include <boost/move/utility_core.hpp> //for boost::move
#if !defined(BOOST_MOVE_DOXYGEN_INVOKED)
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
namespace boost_move_member_swap {
struct dont_care
{
dont_care(...);
};
struct private_type
{
static private_type p;
private_type const &operator,(int) const;
};
typedef char yes_type;
struct no_type{ char dummy[2]; };
template<typename T>
no_type is_private_type(T const &);
yes_type is_private_type(private_type const &);
template <typename Type>
class has_member_function_named_swap
{
struct BaseMixin
{
void swap();
};
struct Base : public Type, public BaseMixin { Base(); };
template <typename T, T t> class Helper{};
template <typename U>
static no_type deduce(U*, Helper<void (BaseMixin::*)(), &U::swap>* = 0);
static yes_type deduce(...);
public:
static const bool value = sizeof(yes_type) == sizeof(deduce((Base*)(0)));
};
template<typename Fun, bool HasFunc>
struct has_member_swap_impl
{
static const bool value = false;
};
template<typename Fun>
struct has_member_swap_impl<Fun, true>
{
struct FunWrap : Fun
{
FunWrap();
using Fun::swap;
private_type swap(dont_care) const;
};
static Fun &declval_fun();
static FunWrap declval_wrap();
static bool const value =
sizeof(no_type) == sizeof(is_private_type( (declval_wrap().swap(declval_fun()), 0)) );
};
template<typename Fun>
struct has_member_swap : public has_member_swap_impl
<Fun, has_member_function_named_swap<Fun>::value>
{};
} //namespace boost_move_member_swap
namespace boost_move_adl_swap{
template<class P1, class P2, bool = P1::value>
struct and_op_impl
{ static const bool value = false; };
template<class P1, class P2>
struct and_op_impl<P1, P2, true>
{ static const bool value = P2::value; };
template<class P1, class P2>
struct and_op
: and_op_impl<P1, P2>
{};
//////
template<class P1, class P2, bool = P1::value>
struct and_op_not_impl
{ static const bool value = false; };
template<class P1, class P2>
struct and_op_not_impl<P1, P2, true>
{ static const bool value = !P2::value; };
template<class P1, class P2>
struct and_op_not
: and_op_not_impl<P1, P2>
{};
template<class T>
void swap_proxy(T& x, T& y, typename boost::move_detail::enable_if_c<!boost::move_detail::has_move_emulation_enabled_impl<T>::value>::type* = 0)
{
//use std::swap if argument dependent lookup fails
//Use using directive ("using namespace xxx;") instead as some older compilers
//don't do ADL with using declarations ("using ns::func;").
using namespace std;
swap(x, y);
}
template<class T>
void swap_proxy(T& x, T& y
, typename boost::move_detail::enable_if< and_op_not_impl<boost::move_detail::has_move_emulation_enabled_impl<T>
, boost_move_member_swap::has_member_swap<T> >
>::type* = 0)
{ T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t); }
template<class T>
void swap_proxy(T& x, T& y
, typename boost::move_detail::enable_if< and_op_impl< boost::move_detail::has_move_emulation_enabled_impl<T>
, boost_move_member_swap::has_member_swap<T> >
>::type* = 0)
{ x.swap(y); }
} //namespace boost_move_adl_swap{
#else
namespace boost_move_adl_swap{
template<class T>
void swap_proxy(T& x, T& y)
{
using std::swap;
swap(x, y);
}
} //namespace boost_move_adl_swap{
#endif //#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
namespace boost_move_adl_swap{
template<class T, std::size_t N>
void swap_proxy(T (& x)[N], T (& y)[N])
{
for (std::size_t i = 0; i < N; ++i){
::boost_move_adl_swap::swap_proxy(x[i], y[i]);
}
}
} //namespace boost_move_adl_swap {
#endif //!defined(BOOST_MOVE_DOXYGEN_INVOKED)
namespace boost{
//! Exchanges the values of a and b, using Argument Dependent Lookup (ADL) to select a
//! specialized swap function if available. If no specialized swap function is available,
//! std::swap is used.
//!
//! <b>Exception</b>: If T uses Boost.Move's move emulation and the compiler has
//! no rvalue references then:
//!
//! - If T has a <code>T::swap(T&)</code> member, that member is called.
//! - Otherwise a move-based swap is called, equivalent to:
//! <code>T t(::boost::move(x)); x = ::boost::move(y); y = ::boost::move(t);</code>.
template<class T>
void adl_move_swap(T& x, T& y)
{
::boost_move_adl_swap::swap_proxy(x, y);
}
} //namespace boost{
#endif //#ifndef BOOST_MOVE_ADL_MOVE_SWAP_HPP