forked from boostorg/unordered
Store nodes in a single linked list, with hash values so that their buckets can be found when needed. Iterators now only have to store a pointer to the node and don't have to iterate over empty buckets to reach the next node. This allows the container to meet the iterator requirements - fixing the speed issues with `equal_range` and `erase`. Also, define iterators in their own namespace, so that they don't accidentally pull in detail functions via ADL. I've simplified the code slightly by removing some of the special cases for empty containers. Renamed a few things as well and other minor changes that were made as I went along. [SVN r71327]
246 lines
7.7 KiB
C++
246 lines
7.7 KiB
C++
/*
|
|
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_UNORDERED_DETAIL_MOVE_HEADER
|
|
#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
|
|
|
#include <boost/config.hpp>
|
|
#include <boost/mpl/bool.hpp>
|
|
#include <boost/mpl/and.hpp>
|
|
#include <boost/mpl/or.hpp>
|
|
#include <boost/mpl/not.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>
|
|
#include <boost/detail/workaround.hpp>
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#if defined(BOOST_NO_SFINAE)
|
|
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
#elif defined(__GNUC__) && \
|
|
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
|
|
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
|
|
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
|
|
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
|
|
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
#endif
|
|
|
|
/*************************************************************************************************/
|
|
|
|
namespace boost {
|
|
namespace unordered {
|
|
namespace detail {
|
|
|
|
/*************************************************************************************************/
|
|
|
|
namespace move_detail {
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
|
|
|
|
/*************************************************************************************************/
|
|
|
|
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 { };
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
|
|
/*************************************************************************************************/
|
|
|
|
/*
|
|
REVISIT (sparent@adobe.com): 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;
|
|
private:
|
|
move_from& operator=(move_from const&);
|
|
};
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
|
|
|
|
/*************************************************************************************************/
|
|
|
|
/*!
|
|
\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> >
|
|
> { };
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
|
|
// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
|
|
// unless the trait is specialized.
|
|
|
|
template <typename T>
|
|
struct is_movable : ::boost::mpl::false_ { };
|
|
|
|
#endif
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#if !defined(BOOST_NO_SFINAE)
|
|
|
|
/*************************************************************************************************/
|
|
|
|
/*!
|
|
\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::unordered::detail::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::unordered::detail::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; }
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#else // BOOST_NO_SFINAE
|
|
|
|
// On compilers without SFINAE, define copy_sink to always use the copy function.
|
|
|
|
template <typename T,
|
|
typename U = T,
|
|
typename R = void*>
|
|
struct copy_sink
|
|
{
|
|
typedef R type;
|
|
};
|
|
|
|
// Always copy the element unless this is overloaded.
|
|
|
|
template <typename T>
|
|
T& move(T& x) {
|
|
return x;
|
|
}
|
|
|
|
#endif // BOOST_NO_SFINAE
|
|
|
|
} // namespace detail
|
|
} // namespace unordered
|
|
} // namespace boost
|
|
|
|
/*************************************************************************************************/
|
|
|
|
#endif
|
|
|
|
/*************************************************************************************************/
|