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)
|
||||
#pragma warning(pop)
|
||||
#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);
|
||||
}
|
||||
|
||||
// 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>
|
||||
struct table : boost::unordered::detail::functions<typename Types::hasher,
|
||||
typename Types::key_equal>
|
||||
|
@ -2456,72 +2456,51 @@ namespace boost {
|
||||
|
||||
private:
|
||||
node_pointer ptr_;
|
||||
bool has_alloc_;
|
||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
||||
boost::unordered::detail::optional<value_allocator> alloc_;
|
||||
|
||||
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:
|
||||
BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(),
|
||||
has_alloc_(false)
|
||||
{
|
||||
}
|
||||
BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), alloc_() {}
|
||||
|
||||
~node_handle_map()
|
||||
{
|
||||
if (has_alloc_ && ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(*alloc_);
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
}
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
has_alloc_(false)
|
||||
alloc_(boost::move(n.alloc_))
|
||||
{
|
||||
if (n.has_alloc_) {
|
||||
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;
|
||||
}
|
||||
n.ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
|
||||
{
|
||||
BOOST_ASSERT(!has_alloc_ ||
|
||||
BOOST_ASSERT(!alloc_.has_value() ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
||||
(n.alloc_.has_value() && alloc_ == n.alloc_));
|
||||
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
node_allocator node_alloc(*alloc_);
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = false;
|
||||
if (!alloc_.has_value() ||
|
||||
value_allocator_traits::propagate_on_container_move_assignment::
|
||||
value) {
|
||||
alloc_ = boost::move(n.alloc_);
|
||||
}
|
||||
|
||||
if (!has_alloc_ && n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
|
||||
ptr_ = n.ptr_;
|
||||
n.ptr_ = node_pointer();
|
||||
|
||||
@ -2535,7 +2514,7 @@ namespace boost {
|
||||
|
||||
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()
|
||||
|
||||
@ -2544,38 +2523,19 @@ namespace boost {
|
||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value
|
||||
/* || value_allocator_traits::is_always_equal::value */)
|
||||
value_allocator_traits::propagate_on_container_swap::value ||
|
||||
value_allocator_traits::is_always_equal::value)
|
||||
{
|
||||
if (!has_alloc_) {
|
||||
if (n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
} else if (!n.has_alloc_) {
|
||||
n.move_allocator(*this);
|
||||
} else {
|
||||
swap_impl(
|
||||
n, boost::unordered::detail::integral_constant<bool,
|
||||
value_allocator_traits::propagate_on_container_swap::value>());
|
||||
BOOST_ASSERT(
|
||||
!alloc_.has_value() || !n.alloc_.has_value() ||
|
||||
value_allocator_traits::propagate_on_container_swap::value ||
|
||||
alloc_ == n.alloc_);
|
||||
if (value_allocator_traits::propagate_on_container_swap::value ||
|
||||
!alloc_.has_value() || !n.alloc_.has_value()) {
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
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>
|
||||
|
@ -1970,15 +1970,11 @@ namespace boost {
|
||||
private:
|
||||
node_pointer ptr_;
|
||||
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)
|
||||
: ptr_(ptr), has_alloc_(false)
|
||||
: ptr_(ptr), alloc_(a)
|
||||
{
|
||||
if (ptr_) {
|
||||
new ((void*)&alloc_) value_allocator(a);
|
||||
has_alloc_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -1989,52 +1985,39 @@ namespace boost {
|
||||
|
||||
~node_handle_set()
|
||||
{
|
||||
if (has_alloc_ && ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(*alloc_);
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
}
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_set(BOOST_RV_REF(node_handle_set) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
has_alloc_(false)
|
||||
alloc_(boost::move(n.alloc_))
|
||||
{
|
||||
if (n.has_alloc_) {
|
||||
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;
|
||||
}
|
||||
n.ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
node_handle_set& operator=(BOOST_RV_REF(node_handle_set) n)
|
||||
{
|
||||
BOOST_ASSERT(!has_alloc_ ||
|
||||
BOOST_ASSERT(!alloc_.has_value() ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
||||
(n.alloc_.has_value() && alloc_ == n.alloc_));
|
||||
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
node_allocator node_alloc(*alloc_);
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = false;
|
||||
if (!alloc_.has_value() ||
|
||||
value_allocator_traits::propagate_on_container_move_assignment::
|
||||
value) {
|
||||
alloc_ = boost::move(n.alloc_);
|
||||
}
|
||||
|
||||
if (!has_alloc_ && n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
|
||||
ptr_ = n.ptr_;
|
||||
n.ptr_ = node_pointer();
|
||||
|
||||
@ -2043,7 +2026,7 @@ namespace boost {
|
||||
|
||||
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()
|
||||
|
||||
@ -2052,38 +2035,19 @@ namespace boost {
|
||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
void swap(node_handle_set& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value
|
||||
/* || value_allocator_traits::is_always_equal::value */)
|
||||
value_allocator_traits::propagate_on_container_swap::value ||
|
||||
value_allocator_traits::is_always_equal::value)
|
||||
{
|
||||
if (!has_alloc_) {
|
||||
if (n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
} else if (!n.has_alloc_) {
|
||||
n.move_allocator(*this);
|
||||
} else {
|
||||
swap_impl(
|
||||
n, boost::unordered::detail::integral_constant<bool,
|
||||
value_allocator_traits::propagate_on_container_swap::value>());
|
||||
BOOST_ASSERT(
|
||||
!alloc_.has_value() || !n.alloc_.has_value() ||
|
||||
value_allocator_traits::propagate_on_container_swap::value ||
|
||||
alloc_ == n.alloc_);
|
||||
if (value_allocator_traits::propagate_on_container_swap::value ||
|
||||
!alloc_.has_value() || !n.alloc_.has_value()) {
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
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>
|
||||
|
Reference in New Issue
Block a user