diff --git a/include/boost/unordered/detail/implementation.hpp b/include/boost/unordered/detail/implementation.hpp index 4272b17c..1b9dee56 100644 --- a/include/boost/unordered/detail/implementation.hpp +++ b/include/boost/unordered/detail/implementation.hpp @@ -750,6 +750,118 @@ namespace boost { #if defined(BOOST_MSVC) #pragma warning(pop) #endif + + ////////////////////////////////////////////////////////////////////////// + // value_base + // + // Space used to store values. + + template struct value_base + { + typedef ValueType value_type; + + typename boost::aligned_storage::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 class optional + { + BOOST_MOVABLE_BUT_NOT_COPYABLE(optional) + + boost::unordered::detail::value_base value_; + bool has_value_; + + void destroy() + { + if (has_value_) { + boost::unordered::detail::func::destroy(value_.value_ptr()); + has_value_ = false; + } + } + + void move(optional& 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) 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) 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 const& x) + { + return has_value_ ? x.has_value_ && value_.value() == x.value_.value() + : !x.has_value_; + } + + bool operator!=(optional const& x) { return !((*this) == x); } + + void swap(optional& 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& x, optional& y) { x.swap(y); } + }; } } } @@ -2831,31 +2943,6 @@ namespace boost { : static_cast(f); } - // The space used to store values in a node. - - template struct value_base - { - typedef ValueType value_type; - - typename boost::aligned_storage::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 struct table : boost::unordered::detail::functions diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index e32f6123..06f2bb1a 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -2456,72 +2456,51 @@ namespace boost { private: node_pointer ptr_; - bool has_alloc_; - boost::unordered::detail::value_base alloc_; + boost::unordered::detail::optional 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 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 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()); + 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 diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index bbd243d0..8f991660 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -1970,15 +1970,11 @@ namespace boost { private: node_pointer ptr_; bool has_alloc_; - boost::unordered::detail::value_base alloc_; + boost::unordered::detail::optional 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 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 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()); + 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