forked from boostorg/unordered
Use nothrow move assignment for function objects, when available.
Originally I was going to use two different versions of `hash_functions`, but the recent discussion on binary compatibility persuaded me not to. [SVN r84276]
This commit is contained in:
@ -15,6 +15,8 @@
|
|||||||
#include <boost/unordered/detail/allocate.hpp>
|
#include <boost/unordered/detail/allocate.hpp>
|
||||||
#include <boost/type_traits/aligned_storage.hpp>
|
#include <boost/type_traits/aligned_storage.hpp>
|
||||||
#include <boost/type_traits/alignment_of.hpp>
|
#include <boost/type_traits/alignment_of.hpp>
|
||||||
|
#include <boost/type_traits/is_nothrow_move_constructible.hpp>
|
||||||
|
#include <boost/type_traits/is_nothrow_move_assignable.hpp>
|
||||||
#include <boost/swap.hpp>
|
#include <boost/swap.hpp>
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
@ -670,12 +672,16 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
// atomically assigns the new function objects in a strongly
|
// atomically assigns the new function objects in a strongly
|
||||||
// exception safe manner.
|
// exception safe manner.
|
||||||
|
|
||||||
template <class H, class P> class set_hash_functions;
|
template <class H, class P, bool NoThrowMoveAssign>
|
||||||
|
class set_hash_functions;
|
||||||
|
|
||||||
template <class H, class P>
|
template <class H, class P>
|
||||||
class functions
|
class functions
|
||||||
{
|
{
|
||||||
friend class boost::unordered::detail::set_hash_functions<H, P>;
|
friend class boost::unordered::detail::set_hash_functions<H, P,
|
||||||
|
boost::is_nothrow_move_assignable<H>::value &&
|
||||||
|
boost::is_nothrow_move_assignable<P>::value
|
||||||
|
>;
|
||||||
functions& operator=(functions const&);
|
functions& operator=(functions const&);
|
||||||
|
|
||||||
typedef compressed<H, P> function_pair;
|
typedef compressed<H, P> function_pair;
|
||||||
@ -692,6 +698,11 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
static_cast<void const*>(&funcs_[current_]));
|
static_cast<void const*>(&funcs_[current_]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function_pair& current() {
|
||||||
|
return *static_cast<function_pair*>(
|
||||||
|
static_cast<void*>(&funcs_[current_]));
|
||||||
|
}
|
||||||
|
|
||||||
void construct(bool which, H const& hf, P const& eq)
|
void construct(bool which, H const& hf, P const& eq)
|
||||||
{
|
{
|
||||||
new((void*) &funcs_[which]) function_pair(hf, eq);
|
new((void*) &funcs_[which]) function_pair(hf, eq);
|
||||||
@ -709,6 +720,11 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
typedef boost::unordered::detail::set_hash_functions<H, P,
|
||||||
|
boost::is_nothrow_move_assignable<H>::value &&
|
||||||
|
boost::is_nothrow_move_assignable<P>::value
|
||||||
|
> set_hash_functions;
|
||||||
|
|
||||||
functions(H const& hf, P const& eq)
|
functions(H const& hf, P const& eq)
|
||||||
: current_(false)
|
: current_(false)
|
||||||
{
|
{
|
||||||
@ -733,26 +749,28 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
return current().second();
|
return current().second();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class H, class P>
|
template <class H, class P>
|
||||||
class set_hash_functions
|
class set_hash_functions<H, P, false>
|
||||||
{
|
{
|
||||||
set_hash_functions(set_hash_functions const&);
|
set_hash_functions(set_hash_functions const&);
|
||||||
set_hash_functions& operator=(set_hash_functions const&);
|
set_hash_functions& operator=(set_hash_functions const&);
|
||||||
|
|
||||||
|
typedef functions<H, P> functions_type;
|
||||||
|
|
||||||
functions<H,P>& functions_;
|
functions_type& functions_;
|
||||||
bool tmp_functions_;
|
bool tmp_functions_;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
set_hash_functions(functions<H,P>& f, H const& h, P const& p)
|
set_hash_functions(functions_type& f, H const& h, P const& p)
|
||||||
: functions_(f),
|
: functions_(f),
|
||||||
tmp_functions_(!f.current_)
|
tmp_functions_(!f.current_)
|
||||||
{
|
{
|
||||||
f.construct(tmp_functions_, h, p);
|
f.construct(tmp_functions_, h, p);
|
||||||
}
|
}
|
||||||
|
|
||||||
set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
|
set_hash_functions(functions_type& f, functions_type const& other)
|
||||||
: functions_(f),
|
: functions_(f),
|
||||||
tmp_functions_(!f.current_)
|
tmp_functions_(!f.current_)
|
||||||
{
|
{
|
||||||
@ -771,6 +789,37 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class H, class P>
|
||||||
|
class set_hash_functions<H, P, true>
|
||||||
|
{
|
||||||
|
set_hash_functions(set_hash_functions const&);
|
||||||
|
set_hash_functions& operator=(set_hash_functions const&);
|
||||||
|
|
||||||
|
typedef functions<H, P> functions_type;
|
||||||
|
|
||||||
|
functions_type& functions_;
|
||||||
|
H hash_;
|
||||||
|
P pred_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
set_hash_functions(functions_type& f, H const& h, P const& p) :
|
||||||
|
functions_(f),
|
||||||
|
hash_(h),
|
||||||
|
pred_(p) {}
|
||||||
|
|
||||||
|
set_hash_functions(functions_type& f, functions_type const& other) :
|
||||||
|
functions_(f),
|
||||||
|
hash_(other.hash_function()),
|
||||||
|
pred_(other.key_eq()) {}
|
||||||
|
|
||||||
|
void commit()
|
||||||
|
{
|
||||||
|
functions_.current().first() = boost::move(hash_);
|
||||||
|
functions_.current().second() = boost::move(pred_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
|
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
|
||||||
// e.g. for int
|
// e.g. for int
|
||||||
|
@ -159,6 +159,7 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
typedef boost::unordered::detail::functions<
|
typedef boost::unordered::detail::functions<
|
||||||
typename Types::hasher,
|
typename Types::hasher,
|
||||||
typename Types::key_equal> functions;
|
typename Types::key_equal> functions;
|
||||||
|
typedef typename functions::set_hash_functions set_hash_functions;
|
||||||
|
|
||||||
typedef typename Types::allocator allocator;
|
typedef typename Types::allocator allocator;
|
||||||
typedef typename boost::unordered::detail::
|
typedef typename boost::unordered::detail::
|
||||||
@ -469,10 +470,8 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
// Only swaps the allocators if propagate_on_container_swap
|
// Only swaps the allocators if propagate_on_container_swap
|
||||||
void swap(table& x)
|
void swap(table& x)
|
||||||
{
|
{
|
||||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
set_hash_functions op1(*this, x);
|
||||||
op1(*this, x);
|
set_hash_functions op2(x, *this);
|
||||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
|
||||||
op2(x, *this);
|
|
||||||
|
|
||||||
// I think swap can throw if Propagate::value,
|
// I think swap can throw if Propagate::value,
|
||||||
// since the allocators' swap can throw. Not sure though.
|
// since the allocators' swap can throw. Not sure though.
|
||||||
@ -637,8 +636,7 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
void assign(table const& x, false_type)
|
void assign(table const& x, false_type)
|
||||||
{
|
{
|
||||||
// Strong exception safety.
|
// Strong exception safety.
|
||||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
set_hash_functions new_func_this(*this, x);
|
||||||
new_func_this(*this, x);
|
|
||||||
new_func_this.commit();
|
new_func_this.commit();
|
||||||
mlf_ = x.mlf_;
|
mlf_ = x.mlf_;
|
||||||
recalculate_max_load();
|
recalculate_max_load();
|
||||||
@ -666,8 +664,7 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
assign(x, false_type());
|
assign(x, false_type());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
set_hash_functions new_func_this(*this, x);
|
||||||
new_func_this(*this, x);
|
|
||||||
|
|
||||||
// Delete everything with current allocators before assigning
|
// Delete everything with current allocators before assigning
|
||||||
// the new ones.
|
// the new ones.
|
||||||
@ -714,8 +711,7 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
move_assign_no_alloc(x);
|
move_assign_no_alloc(x);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
set_hash_functions new_func_this(*this, x);
|
||||||
new_func_this(*this, x);
|
|
||||||
new_func_this.commit();
|
new_func_this.commit();
|
||||||
mlf_ = x.mlf_;
|
mlf_ = x.mlf_;
|
||||||
recalculate_max_load();
|
recalculate_max_load();
|
||||||
@ -740,8 +736,7 @@ namespace boost { namespace unordered { namespace detail {
|
|||||||
|
|
||||||
void move_assign_no_alloc(table& x)
|
void move_assign_no_alloc(table& x)
|
||||||
{
|
{
|
||||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
set_hash_functions new_func_this(*this, x);
|
||||||
new_func_this(*this, x);
|
|
||||||
// No throw from here.
|
// No throw from here.
|
||||||
mlf_ = x.mlf_;
|
mlf_ = x.mlf_;
|
||||||
max_load_ = x.max_load_;
|
max_load_ = x.max_load_;
|
||||||
|
Reference in New Issue
Block a user