forked from boostorg/unordered
Rewrite node handles using a lightweight limited optional
Will try to use std::optional when available. Also using allocator_traits::is_always_equal support.
This commit is contained in:
@@ -750,6 +750,118 @@ namespace boost {
|
|||||||
#if defined(BOOST_MSVC)
|
#if defined(BOOST_MSVC)
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// value_base
|
||||||
|
//
|
||||||
|
// Space used to store values.
|
||||||
|
|
||||||
|
template <typename ValueType> struct value_base
|
||||||
|
{
|
||||||
|
typedef ValueType value_type;
|
||||||
|
|
||||||
|
typename boost::aligned_storage<sizeof(value_type),
|
||||||
|
boost::alignment_of<value_type>::value>::type data_;
|
||||||
|
|
||||||
|
value_base() : data_() {}
|
||||||
|
|
||||||
|
void* address() { return this; }
|
||||||
|
|
||||||
|
value_type& value() { return *(ValueType*)this; }
|
||||||
|
|
||||||
|
value_type const& value() const { return *(ValueType const*)this; }
|
||||||
|
|
||||||
|
value_type* value_ptr() { return (ValueType*)this; }
|
||||||
|
|
||||||
|
value_type const* value_ptr() const { return (ValueType const*)this; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
value_base& operator=(value_base const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
//////////////////////////////////////////////////////////////////////////
|
||||||
|
// optional
|
||||||
|
// TODO: Use std::optional when available.
|
||||||
|
|
||||||
|
template <typename T> class optional
|
||||||
|
{
|
||||||
|
BOOST_MOVABLE_BUT_NOT_COPYABLE(optional<T>)
|
||||||
|
|
||||||
|
boost::unordered::detail::value_base<T> value_;
|
||||||
|
bool has_value_;
|
||||||
|
|
||||||
|
void destroy()
|
||||||
|
{
|
||||||
|
if (has_value_) {
|
||||||
|
boost::unordered::detail::func::destroy(value_.value_ptr());
|
||||||
|
has_value_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void move(optional<T>& x)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!has_value_ && x.has_value_);
|
||||||
|
new (value_.value_ptr()) T(boost::move(x.value_.value()));
|
||||||
|
boost::unordered::detail::func::destroy(x.value_.value_ptr());
|
||||||
|
has_value_ = true;
|
||||||
|
x.has_value_ = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
optional() BOOST_NOEXCEPT : has_value_(false) {}
|
||||||
|
|
||||||
|
optional(BOOST_RV_REF(optional<T>) x) : has_value_(false)
|
||||||
|
{
|
||||||
|
if (x.has_value_) {
|
||||||
|
move(x);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit optional(T const& x) : has_value_(true)
|
||||||
|
{
|
||||||
|
new (value_.value_ptr()) T(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional& operator=(BOOST_RV_REF(optional<T>) x)
|
||||||
|
{
|
||||||
|
destroy();
|
||||||
|
if (x.has_value_) {
|
||||||
|
move(x);
|
||||||
|
}
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
~optional() { destroy(); }
|
||||||
|
|
||||||
|
bool has_value() const { return has_value_; }
|
||||||
|
T& operator*() { return value_.value(); }
|
||||||
|
T const& operator*() const { return value_.value(); }
|
||||||
|
T* operator->() { return value_.value_ptr(); }
|
||||||
|
T const* operator->() const { return value_.value_ptr(); }
|
||||||
|
|
||||||
|
bool operator==(optional<T> const& x)
|
||||||
|
{
|
||||||
|
return has_value_ ? x.has_value_ && value_.value() == x.value_.value()
|
||||||
|
: !x.has_value_;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(optional<T> const& x) { return !((*this) == x); }
|
||||||
|
|
||||||
|
void swap(optional<T>& x)
|
||||||
|
{
|
||||||
|
if (has_value_ != x.has_value_) {
|
||||||
|
if (has_value_) {
|
||||||
|
x.move(*this);
|
||||||
|
} else {
|
||||||
|
move(x);
|
||||||
|
}
|
||||||
|
} else if (has_value_) {
|
||||||
|
boost::swap(value_.value(), x.value_.value());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
friend void swap(optional<T>& x, optional<T>& y) { x.swap(y); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2831,31 +2943,6 @@ namespace boost {
|
|||||||
: static_cast<std::size_t>(f);
|
: static_cast<std::size_t>(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The space used to store values in a node.
|
|
||||||
|
|
||||||
template <typename ValueType> struct value_base
|
|
||||||
{
|
|
||||||
typedef ValueType value_type;
|
|
||||||
|
|
||||||
typename boost::aligned_storage<sizeof(value_type),
|
|
||||||
boost::alignment_of<value_type>::value>::type data_;
|
|
||||||
|
|
||||||
value_base() : data_() {}
|
|
||||||
|
|
||||||
void* address() { return this; }
|
|
||||||
|
|
||||||
value_type& value() { return *(ValueType*)this; }
|
|
||||||
|
|
||||||
value_type const& value() const { return *(ValueType const*)this; }
|
|
||||||
|
|
||||||
value_type* value_ptr() { return (ValueType*)this; }
|
|
||||||
|
|
||||||
value_type const* value_ptr() const { return (ValueType const*)this; }
|
|
||||||
|
|
||||||
private:
|
|
||||||
value_base& operator=(value_base const&);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename Types>
|
template <typename Types>
|
||||||
struct table : boost::unordered::detail::functions<typename Types::hasher,
|
struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||||
typename Types::key_equal>
|
typename Types::key_equal>
|
||||||
|
@@ -2456,72 +2456,51 @@ namespace boost {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
node_pointer ptr_;
|
node_pointer ptr_;
|
||||||
bool has_alloc_;
|
boost::unordered::detail::optional<value_allocator> alloc_;
|
||||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
|
||||||
|
|
||||||
node_handle_map(node_pointer ptr, allocator_type const& a)
|
node_handle_map(node_pointer ptr, allocator_type const& a)
|
||||||
: ptr_(ptr), has_alloc_(false)
|
: ptr_(ptr), alloc_(a)
|
||||||
{
|
{
|
||||||
if (ptr_) {
|
|
||||||
new ((void*)&alloc_) value_allocator(a);
|
|
||||||
has_alloc_ = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(),
|
BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), alloc_() {}
|
||||||
has_alloc_(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
~node_handle_map()
|
~node_handle_map()
|
||||||
{
|
{
|
||||||
if (has_alloc_ && ptr_) {
|
if (ptr_) {
|
||||||
node_allocator node_alloc(alloc_.value());
|
node_allocator node_alloc(*alloc_);
|
||||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||||
ptr_, node_alloc);
|
ptr_, node_alloc);
|
||||||
}
|
}
|
||||||
if (has_alloc_) {
|
|
||||||
alloc_.value_ptr()->~value_allocator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
|
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
|
||||||
: ptr_(n.ptr_),
|
: ptr_(n.ptr_),
|
||||||
has_alloc_(false)
|
alloc_(boost::move(n.alloc_))
|
||||||
{
|
{
|
||||||
if (n.has_alloc_) {
|
n.ptr_ = node_pointer();
|
||||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
|
||||||
has_alloc_ = true;
|
|
||||||
n.ptr_ = node_pointer();
|
|
||||||
n.alloc_.value_ptr()->~value_allocator();
|
|
||||||
n.has_alloc_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
|
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!has_alloc_ ||
|
BOOST_ASSERT(!alloc_.has_value() ||
|
||||||
value_allocator_traits::
|
value_allocator_traits::
|
||||||
propagate_on_container_move_assignment::value ||
|
propagate_on_container_move_assignment::value ||
|
||||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
(n.alloc_.has_value() && alloc_ == n.alloc_));
|
||||||
|
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
node_allocator node_alloc(alloc_.value());
|
node_allocator node_alloc(*alloc_);
|
||||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||||
ptr_, node_alloc);
|
ptr_, node_alloc);
|
||||||
ptr_ = node_pointer();
|
ptr_ = node_pointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_alloc_) {
|
if (!alloc_.has_value() ||
|
||||||
alloc_.value_ptr()->~value_allocator();
|
value_allocator_traits::propagate_on_container_move_assignment::
|
||||||
has_alloc_ = false;
|
value) {
|
||||||
|
alloc_ = boost::move(n.alloc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_alloc_ && n.has_alloc_) {
|
|
||||||
move_allocator(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr_ = n.ptr_;
|
ptr_ = n.ptr_;
|
||||||
n.ptr_ = node_pointer();
|
n.ptr_ = node_pointer();
|
||||||
|
|
||||||
@@ -2535,7 +2514,7 @@ namespace boost {
|
|||||||
|
|
||||||
mapped_type& mapped() const { return ptr_->value().second; }
|
mapped_type& mapped() const { return ptr_->value().second; }
|
||||||
|
|
||||||
allocator_type get_allocator() const { return alloc_.value(); }
|
allocator_type get_allocator() const { return *alloc_; }
|
||||||
|
|
||||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||||
|
|
||||||
@@ -2544,38 +2523,19 @@ namespace boost {
|
|||||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||||
|
|
||||||
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
|
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
|
||||||
value_allocator_traits::propagate_on_container_swap::value
|
value_allocator_traits::propagate_on_container_swap::value ||
|
||||||
/* || value_allocator_traits::is_always_equal::value */)
|
value_allocator_traits::is_always_equal::value)
|
||||||
{
|
{
|
||||||
if (!has_alloc_) {
|
BOOST_ASSERT(
|
||||||
if (n.has_alloc_) {
|
!alloc_.has_value() || !n.alloc_.has_value() ||
|
||||||
move_allocator(n);
|
value_allocator_traits::propagate_on_container_swap::value ||
|
||||||
}
|
alloc_ == n.alloc_);
|
||||||
} else if (!n.has_alloc_) {
|
if (value_allocator_traits::propagate_on_container_swap::value ||
|
||||||
n.move_allocator(*this);
|
!alloc_.has_value() || !n.alloc_.has_value()) {
|
||||||
} else {
|
boost::swap(alloc_, n.alloc_);
|
||||||
swap_impl(
|
|
||||||
n, boost::unordered::detail::integral_constant<bool,
|
|
||||||
value_allocator_traits::propagate_on_container_swap::value>());
|
|
||||||
}
|
}
|
||||||
boost::swap(ptr_, n.ptr_);
|
boost::swap(ptr_, n.ptr_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void move_allocator(node_handle_map& n)
|
|
||||||
{
|
|
||||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
|
||||||
n.alloc_.value_ptr()->~value_allocator();
|
|
||||||
has_alloc_ = true;
|
|
||||||
n.has_alloc_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap_impl(node_handle_map&, boost::unordered::detail::false_type) {}
|
|
||||||
|
|
||||||
void swap_impl(node_handle_map& n, boost::unordered::detail::true_type)
|
|
||||||
{
|
|
||||||
boost::swap(alloc_, n.alloc_);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class N, class K, class T, class A>
|
template <class N, class K, class T, class A>
|
||||||
|
@@ -1970,15 +1970,11 @@ namespace boost {
|
|||||||
private:
|
private:
|
||||||
node_pointer ptr_;
|
node_pointer ptr_;
|
||||||
bool has_alloc_;
|
bool has_alloc_;
|
||||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
boost::unordered::detail::optional<value_allocator> alloc_;
|
||||||
|
|
||||||
node_handle_set(node_pointer ptr, allocator_type const& a)
|
node_handle_set(node_pointer ptr, allocator_type const& a)
|
||||||
: ptr_(ptr), has_alloc_(false)
|
: ptr_(ptr), alloc_(a)
|
||||||
{
|
{
|
||||||
if (ptr_) {
|
|
||||||
new ((void*)&alloc_) value_allocator(a);
|
|
||||||
has_alloc_ = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -1989,52 +1985,39 @@ namespace boost {
|
|||||||
|
|
||||||
~node_handle_set()
|
~node_handle_set()
|
||||||
{
|
{
|
||||||
if (has_alloc_ && ptr_) {
|
if (ptr_) {
|
||||||
node_allocator node_alloc(alloc_.value());
|
node_allocator node_alloc(*alloc_);
|
||||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||||
ptr_, node_alloc);
|
ptr_, node_alloc);
|
||||||
}
|
}
|
||||||
if (has_alloc_) {
|
|
||||||
alloc_.value_ptr()->~value_allocator();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node_handle_set(BOOST_RV_REF(node_handle_set) n) BOOST_NOEXCEPT
|
node_handle_set(BOOST_RV_REF(node_handle_set) n) BOOST_NOEXCEPT
|
||||||
: ptr_(n.ptr_),
|
: ptr_(n.ptr_),
|
||||||
has_alloc_(false)
|
alloc_(boost::move(n.alloc_))
|
||||||
{
|
{
|
||||||
if (n.has_alloc_) {
|
n.ptr_ = node_pointer();
|
||||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
|
||||||
has_alloc_ = true;
|
|
||||||
n.ptr_ = node_pointer();
|
|
||||||
n.alloc_.value_ptr()->~value_allocator();
|
|
||||||
n.has_alloc_ = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node_handle_set& operator=(BOOST_RV_REF(node_handle_set) n)
|
node_handle_set& operator=(BOOST_RV_REF(node_handle_set) n)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!has_alloc_ ||
|
BOOST_ASSERT(!alloc_.has_value() ||
|
||||||
value_allocator_traits::
|
value_allocator_traits::
|
||||||
propagate_on_container_move_assignment::value ||
|
propagate_on_container_move_assignment::value ||
|
||||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
(n.alloc_.has_value() && alloc_ == n.alloc_));
|
||||||
|
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
node_allocator node_alloc(alloc_.value());
|
node_allocator node_alloc(*alloc_);
|
||||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||||
ptr_, node_alloc);
|
ptr_, node_alloc);
|
||||||
ptr_ = node_pointer();
|
ptr_ = node_pointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has_alloc_) {
|
if (!alloc_.has_value() ||
|
||||||
alloc_.value_ptr()->~value_allocator();
|
value_allocator_traits::propagate_on_container_move_assignment::
|
||||||
has_alloc_ = false;
|
value) {
|
||||||
|
alloc_ = boost::move(n.alloc_);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!has_alloc_ && n.has_alloc_) {
|
|
||||||
move_allocator(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr_ = n.ptr_;
|
ptr_ = n.ptr_;
|
||||||
n.ptr_ = node_pointer();
|
n.ptr_ = node_pointer();
|
||||||
|
|
||||||
@@ -2043,7 +2026,7 @@ namespace boost {
|
|||||||
|
|
||||||
value_type& value() const { return ptr_->value(); }
|
value_type& value() const { return ptr_->value(); }
|
||||||
|
|
||||||
allocator_type get_allocator() const { return alloc_.value(); }
|
allocator_type get_allocator() const { return *alloc_; }
|
||||||
|
|
||||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||||
|
|
||||||
@@ -2052,38 +2035,19 @@ namespace boost {
|
|||||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||||
|
|
||||||
void swap(node_handle_set& n) BOOST_NOEXCEPT_IF(
|
void swap(node_handle_set& n) BOOST_NOEXCEPT_IF(
|
||||||
value_allocator_traits::propagate_on_container_swap::value
|
value_allocator_traits::propagate_on_container_swap::value ||
|
||||||
/* || value_allocator_traits::is_always_equal::value */)
|
value_allocator_traits::is_always_equal::value)
|
||||||
{
|
{
|
||||||
if (!has_alloc_) {
|
BOOST_ASSERT(
|
||||||
if (n.has_alloc_) {
|
!alloc_.has_value() || !n.alloc_.has_value() ||
|
||||||
move_allocator(n);
|
value_allocator_traits::propagate_on_container_swap::value ||
|
||||||
}
|
alloc_ == n.alloc_);
|
||||||
} else if (!n.has_alloc_) {
|
if (value_allocator_traits::propagate_on_container_swap::value ||
|
||||||
n.move_allocator(*this);
|
!alloc_.has_value() || !n.alloc_.has_value()) {
|
||||||
} else {
|
boost::swap(alloc_, n.alloc_);
|
||||||
swap_impl(
|
|
||||||
n, boost::unordered::detail::integral_constant<bool,
|
|
||||||
value_allocator_traits::propagate_on_container_swap::value>());
|
|
||||||
}
|
}
|
||||||
boost::swap(ptr_, n.ptr_);
|
boost::swap(ptr_, n.ptr_);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
|
||||||
void move_allocator(node_handle_set& n)
|
|
||||||
{
|
|
||||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
|
||||||
n.alloc_.value_ptr()->~value_allocator();
|
|
||||||
has_alloc_ = true;
|
|
||||||
n.has_alloc_ = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void swap_impl(node_handle_set&, boost::unordered::detail::false_type) {}
|
|
||||||
|
|
||||||
void swap_impl(node_handle_set& n, boost::unordered::detail::true_type)
|
|
||||||
{
|
|
||||||
boost::swap(alloc_, n.alloc_);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename N, typename T, typename A>
|
template <typename N, typename T, typename A>
|
||||||
|
Reference in New Issue
Block a user