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:
Daniel James
2018-01-03 20:55:44 +00:00
parent be0acc575f
commit 7615fabc80
3 changed files with 159 additions and 148 deletions

View File

@ -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>

View File

@ -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>

View File

@ -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>