diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 4c20b168..a83edad2 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -14,23 +14,31 @@ #pragma once #endif +// Some of these includes are required for other detail headers. #include #include #include -#include -#include #include #include #include #include #include #include +#include +#include +#include +#include #include #include #include +#include #include +#include #include +#include +#include #include +#include #if !defined(BOOST_NO_CXX11_HDR_TUPLE) #include @@ -808,6 +816,18 @@ namespace boost { namespace unordered { namespace detail { namespace func { # endif #else + template + inline void call_construct(Alloc&, T* address) + { + new ((void*) address) T(); + } + + template + inline void call_construct(Alloc&, T* address, + BOOST_FWD_REF(A0) a0) + { + new ((void*) address) T(boost::forward(a0)); + } template inline void destroy_value_impl(Alloc&, T* x) { @@ -1053,74 +1073,182 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) namespace boost { namespace unordered { namespace detail { - //////////////////////////////////////////////////////////////////////////// + /////////////////////////////////////////////////////////////////// // - // array_constructor - // - // Allocate and construct an array in an exception safe manner, and - // clean up if an exception is thrown before the container takes charge - // of it. + // Node construction - template - struct array_constructor + template + struct node_constructor { - typedef boost::unordered::detail::allocator_traits traits; - typedef typename traits::pointer pointer; + typedef NodeAlloc node_allocator; + typedef boost::unordered::detail::allocator_traits + node_allocator_traits; + typedef typename node_allocator_traits::value_type node; + typedef typename node_allocator_traits::pointer node_pointer; + typedef typename node::value_type value_type; - Allocator& alloc_; - pointer ptr_; - pointer constructed_; - std::size_t length_; + node_allocator& alloc_; + node_pointer node_; + bool node_constructed_; - array_constructor(Allocator& a) - : alloc_(a), ptr_(), constructed_(), length_(0) + node_constructor(node_allocator& n) : + alloc_(n), + node_(), + node_constructed_(false) { - constructed_ = pointer(); - ptr_ = pointer(); } - ~array_constructor() { - if (ptr_) { - for(pointer p = ptr_; p != constructed_; ++p) { - boost::unordered::detail::func::destroy( - boost::addressof(*p)); - } + ~node_constructor(); - traits::deallocate(alloc_, ptr_, length_); - } - } + void create_node(); - template - void construct(V const& v, std::size_t l) + // no throw + node_pointer release() { - BOOST_ASSERT(!ptr_); - length_ = l; - ptr_ = traits::allocate(alloc_, length_); - pointer end = ptr_ + static_cast(length_); - for(constructed_ = ptr_; constructed_ != end; ++constructed_) { - new ((void*) boost::addressof(*constructed_)) V(v); - } - } - - pointer get() const - { - return ptr_; - } - - pointer release() - { - pointer p(ptr_); - ptr_ = pointer(); + BOOST_ASSERT(node_ && node_constructed_); + node_pointer p = node_; + node_ = node_pointer(); return p; } - private: + void reclaim(node_pointer p) { + BOOST_ASSERT(!node_); + node_ = p; + node_constructed_ = true; + boost::unordered::detail::func::destroy_value_impl(alloc_, + node_->value_ptr()); + } - array_constructor(array_constructor const&); - array_constructor& operator=(array_constructor const&); + private: + node_constructor(node_constructor const&); + node_constructor& operator=(node_constructor const&); }; + + template + node_constructor::~node_constructor() + { + if (node_) { + if (node_constructed_) { + boost::unordered::detail::func::destroy( + boost::addressof(*node_)); + } + + node_allocator_traits::deallocate(alloc_, node_, 1); + } + } + + template + void node_constructor::create_node() + { + BOOST_ASSERT(!node_); + node_constructed_ = false; + + node_ = node_allocator_traits::allocate(alloc_, 1); + + new ((void*) boost::addressof(*node_)) node(); + node_->init(node_); + node_constructed_ = true; + } + + template + struct node_tmp + { + typedef boost::unordered::detail::allocator_traits + node_allocator_traits; + typedef typename node_allocator_traits::pointer node_pointer; + + NodeAlloc& alloc_; + node_pointer node_; + + explicit node_tmp(node_pointer n, NodeAlloc& a): + alloc_(a), + node_(n) + { + } + + ~node_tmp(); + + // no throw + node_pointer release() + { + node_pointer p = node_; + node_ = node_pointer(); + return p; + } + }; + + template + node_tmp::~node_tmp() + { + if (node_) { + boost::unordered::detail::func::destroy_value_impl(alloc_, + node_->value_ptr()); + boost::unordered::detail::func::destroy( + boost::addressof(*node_)); + node_allocator_traits::deallocate(alloc_, node_, 1); + } + } }}} +namespace boost { namespace unordered { namespace detail { namespace func { + + // Some nicer construct_value functions, might try to + // improve implementation later. + + template + inline typename boost::unordered::detail::allocator_traits::pointer + construct_value_generic(Alloc& alloc, BOOST_UNORDERED_EMPLACE_ARGS) + { + node_constructor a(alloc); + a.create_node(); + construct_value_impl(alloc, a.node_->value_ptr(), + BOOST_UNORDERED_EMPLACE_FORWARD); + return a.release(); + } + + template + inline typename boost::unordered::detail::allocator_traits::pointer + construct_value(Alloc& alloc, BOOST_FWD_REF(U) x) + { + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, a.node_->value_ptr(), boost::forward(x)); + return a.release(); + } + + // TODO: When possible, it might be better to use std::pair's + // constructor for std::piece_construct with std::tuple. + template + inline typename boost::unordered::detail::allocator_traits::pointer + construct_pair(Alloc& alloc, BOOST_FWD_REF(Key) k) + { + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, boost::addressof(a.node_->value_ptr()->first), + boost::forward(k)); + boost::unordered::detail::func::call_construct( + alloc, boost::addressof(a.node_->value_ptr()->second)); + return a.release(); + } + + template + inline typename boost::unordered::detail::allocator_traits::pointer + construct_pair(Alloc& alloc, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) + { + node_constructor a(alloc); + a.create_node(); + boost::unordered::detail::func::call_construct( + alloc, boost::addressof(a.node_->value_ptr()->first), + boost::forward(k)); + boost::unordered::detail::func::call_construct( + alloc, boost::addressof(a.node_->value_ptr()->second), + boost::forward(m)); + return a.release(); + } +}}}} + #if defined(BOOST_MSVC) #pragma warning(pop) #endif diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index ac5bd6d8..232944b0 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -14,14 +14,6 @@ #include #include -#include -#include -#include -#include -#include -#include -#include -#include namespace boost { namespace unordered { namespace detail { @@ -317,124 +309,6 @@ namespace boost { namespace unordered { namespace iterator_detail { namespace boost { namespace unordered { namespace detail { - /////////////////////////////////////////////////////////////////// - // - // Node construction - - template - struct node_constructor - { - private: - - typedef NodeAlloc node_allocator; - typedef boost::unordered::detail::allocator_traits - node_allocator_traits; - typedef typename node_allocator_traits::value_type node; - typedef typename node_allocator_traits::pointer node_pointer; - typedef typename node::value_type value_type; - - protected: - - node_allocator& alloc_; - node_pointer node_; - bool node_constructed_; - bool value_constructed_; - - public: - - node_constructor(node_allocator& n) : - alloc_(n), - node_(), - node_constructed_(false), - value_constructed_(false) - { - } - - ~node_constructor(); - - void construct(); - - template - void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS) - { - construct(); - boost::unordered::detail::func::construct_value_impl( - alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD); - value_constructed_ = true; - } - - template - void construct_with_value2(BOOST_FWD_REF(A0) a0) - { - construct(); - boost::unordered::detail::func::construct_value_impl( - alloc_, node_->value_ptr(), - BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward(a0))); - value_constructed_ = true; - } - - value_type const& value() const { - BOOST_ASSERT(node_ && node_constructed_ && value_constructed_); - return node_->value(); - } - - // no throw - node_pointer release() - { - BOOST_ASSERT(node_ && node_constructed_); - node_pointer p = node_; - node_ = node_pointer(); - return p; - } - - private: - node_constructor(node_constructor const&); - node_constructor& operator=(node_constructor const&); - }; - - template - node_constructor::~node_constructor() - { - if (node_) { - if (value_constructed_) { - boost::unordered::detail::func::destroy_value_impl(alloc_, - node_->value_ptr()); - } - - if (node_constructed_) { - boost::unordered::detail::func::destroy( - boost::addressof(*node_)); - } - - node_allocator_traits::deallocate(alloc_, node_, 1); - } - } - - template - void node_constructor::construct() - { - if(!node_) { - node_constructed_ = false; - value_constructed_ = false; - - node_ = node_allocator_traits::allocate(alloc_, 1); - - new ((void*) boost::addressof(*node_)) node(); - node_->init(node_); - node_constructed_ = true; - } - else { - BOOST_ASSERT(node_constructed_); - - if (value_constructed_) - { - boost::unordered::detail::func::destroy_value_impl(alloc_, - node_->value_ptr()); - value_constructed_ = false; - } - } - } - /////////////////////////////////////////////////////////////////// // // Node Holder @@ -442,11 +316,9 @@ namespace boost { namespace unordered { namespace detail { // Temporary store for nodes. Deletes any that aren't used. template - struct node_holder : private node_constructor + struct node_holder { private: - typedef node_constructor base; - typedef NodeAlloc node_allocator; typedef boost::unordered::detail::allocator_traits node_allocator_traits; @@ -456,13 +328,14 @@ namespace boost { namespace unordered { namespace detail { typedef typename node::link_pointer link_pointer; typedef boost::unordered::iterator_detail::iterator iterator; + node_constructor constructor_; node_pointer nodes_; public: template explicit node_holder(Table& b) : - base(b.node_alloc()), + constructor_(b.node_alloc()), nodes_() { if (b.size_) { @@ -475,61 +348,71 @@ namespace boost { namespace unordered { namespace detail { ~node_holder(); - void node_for_assignment() + node_pointer pop_node() { - if (!this->node_ && nodes_) { - this->node_ = nodes_; - nodes_ = static_cast(nodes_->next_); - this->node_->init(this->node_); - this->node_->next_ = link_pointer(); - - this->node_constructed_ = true; - this->value_constructed_ = true; - } + node_pointer n = nodes_; + nodes_ = static_cast(nodes_->next_); + n->init(n); + n->next_ = link_pointer(); + return n; } template - inline void assign_impl(T const& v) { - if (this->node_ && this->value_constructed_) { - this->node_->value() = v; + inline node_pointer copy_of(T const& v) { + if (nodes_) { + node_tmp a(pop_node(), constructor_.alloc_); + a.node_->value() = v; + return a.release(); } else { - this->construct_with_value2(v); + constructor_.create_node(); + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), v); + return constructor_.release(); } } template - inline void assign_impl(std::pair const& v) { - this->construct_with_value2(v); + inline node_pointer copy_of(std::pair const& v) { + if (nodes_) { + constructor_.reclaim(pop_node()); + } + else { + constructor_.create_node(); + } + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), v); + return constructor_.release(); } template - inline void move_assign_impl(T& v) { - if (this->node_ && this->value_constructed_) { - this->node_->value() = boost::move(v); + inline node_pointer move_copy_of(T& v) { + if (nodes_) { + node_tmp a(pop_node(), constructor_.alloc_); + a.node_->value() = boost::move(v); + return a.release(); } else { - this->construct_with_value2(boost::move(v)); + constructor_.create_node(); + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), + boost::move(v)); + return constructor_.release(); } } template - inline void move_assign_impl(std::pair& v) { - this->construct_with_value2(boost::move(v)); - } - - node_pointer copy_of(value_type const& v) - { - node_for_assignment(); - assign_impl(v); - return base::release(); - } - - node_pointer move_copy_of(value_type& v) - { - node_for_assignment(); - move_assign_impl(v); - return base::release(); + inline node_pointer move_copy_of(std::pair& v) { + if (nodes_) { + constructor_.reclaim(pop_node()); + } + else { + constructor_.create_node(); + } + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), + boost::move(v)); + return constructor_.release(); } iterator begin() const @@ -545,10 +428,10 @@ namespace boost { namespace unordered { namespace detail { node_pointer p = nodes_; nodes_ = static_cast(p->next_); - boost::unordered::detail::func::destroy_value_impl(this->alloc_, + boost::unordered::detail::func::destroy_value_impl(constructor_.alloc_, p->value_ptr()); boost::unordered::detail::func::destroy(boost::addressof(*p)); - node_allocator_traits::deallocate(this->alloc_, p, 1); + node_allocator_traits::deallocate(constructor_.alloc_, p, 1); } } diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index b7b40f1a..691d3154 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -12,7 +12,6 @@ #pragma once #endif -#include #include namespace boost { namespace unordered { namespace detail { @@ -130,55 +129,6 @@ namespace boost { namespace unordered { namespace detail { typedef typename pick::link_pointer link_pointer; }; - template - struct multiset - { - typedef boost::unordered::detail::multiset types; - - typedef A allocator; - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef T key_type; - - typedef boost::unordered::detail::allocator_traits traits; - typedef boost::unordered::detail::pick_grouped_node pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::grouped_table_impl table; - typedef boost::unordered::detail::set_extractor extractor; - - typedef typename boost::unordered::detail::pick_policy::type policy; - }; - - template - struct multimap - { - typedef boost::unordered::detail::multimap types; - - typedef A allocator; - typedef std::pair value_type; - typedef H hasher; - typedef P key_equal; - typedef K key_type; - - typedef boost::unordered::detail::allocator_traits traits; - typedef boost::unordered::detail::pick_grouped_node pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::grouped_table_impl table; - typedef boost::unordered::detail::map_extractor - extractor; - - typedef typename boost::unordered::detail::pick_policy::type policy; - }; - template struct grouped_table_impl : boost::unordered::detail::table { @@ -195,6 +145,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename table::key_equal key_equal; typedef typename table::key_type key_type; typedef typename table::node_constructor node_constructor; + typedef typename table::node_tmp node_tmp; typedef typename table::extractor extractor; typedef typename table::iterator iterator; typedef typename table::c_iterator c_iterator; @@ -380,14 +331,6 @@ namespace boost { namespace unordered { namespace detail { pos->group_prev_ = n; } - inline iterator add_node( - node_constructor& a, - std::size_t key_hash, - iterator pos) - { - return add_node(a.release(), key_hash, pos); - } - inline iterator add_node( node_pointer n, std::size_t key_hash, @@ -432,23 +375,23 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } - iterator emplace_impl(node_constructor& a) + iterator emplace_impl(node_pointer n) { - key_type const& k = this->get_key(a.value()); + node_tmp a(n, this->node_alloc()); + key_type const& k = this->get_key(a.node_->value()); std::size_t key_hash = this->hash(k); iterator position = this->find_node(key_hash, k); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. this->reserve_for_insert(this->size_ + 1); - return this->add_node(a, key_hash, position); + return this->add_node(a.release(), key_hash, position); } - void emplace_impl_no_rehash(node_constructor& a) + void emplace_impl_no_rehash(node_pointer n) { - key_type const& k = this->get_key(a.value()); + node_tmp a(n, this->node_alloc()); + key_type const& k = this->get_key(a.node_->value()); std::size_t key_hash = this->hash(k); - this->add_node(a, key_hash, this->find_node(key_hash, k)); + iterator position = this->find_node(key_hash, k); + this->add_node(a.release(), key_hash, position); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -472,10 +415,9 @@ namespace boost { namespace unordered { namespace detail { template iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) { - node_constructor a(this->node_alloc()); - a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); - - return iterator(emplace_impl(a)); + return iterator(emplace_impl( + boost::unordered::detail::func::construct_value_generic( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); } //////////////////////////////////////////////////////////////////////// @@ -491,18 +433,18 @@ namespace boost { namespace unordered { namespace detail { std::size_t distance = std::distance(i, j); if(distance == 1) { - node_constructor a(this->node_alloc()); - a.construct_with_value2(*i); - emplace_impl(a); + emplace_impl( + boost::unordered::detail::func::construct_value( + this->node_alloc(), *i)); } else { // Only require basic exception safety here this->reserve_for_insert(this->size_ + distance); - node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct_with_value2(*i); - emplace_impl_no_rehash(a); + emplace_impl_no_rehash( + boost::unordered::detail::func::construct_value( + this->node_alloc(), *i)); } } } @@ -511,10 +453,10 @@ namespace boost { namespace unordered { namespace detail { void insert_range(I i, I j, typename boost::unordered::detail::disable_if_forward::type = 0) { - node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct_with_value2(*i); - emplace_impl(a); + emplace_impl( + boost::unordered::detail::func::construct_value( + this->node_alloc(), *i)); } } @@ -628,17 +570,64 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////// // fill_buckets - template - void fill_buckets(iterator n, NodeCreator& creator) - { - while (n.node_) { + void copy_buckets(table const& src) { + this->create_buckets(this->bucket_count_); + + for (iterator n = src.begin(); n.node_;) { std::size_t key_hash = n.node_->hash_; iterator group_end(n.node_->group_prev_->next_); - - iterator pos = this->add_node(creator.create(*n), key_hash, iterator()); + iterator pos = this->add_node( + boost::unordered::detail::func::construct_value( + this->node_alloc(), *n), key_hash, iterator()); for (++n; n != group_end; ++n) { - this->add_node(creator.create(*n), key_hash, pos); + this->add_node( + boost::unordered::detail::func::construct_value( + this->node_alloc(), *n), key_hash, pos); + } + } + } + + void move_buckets(table const& src) { + this->create_buckets(this->bucket_count_); + + for (iterator n = src.begin(); n.node_;) { + std::size_t key_hash = n.node_->hash_; + iterator group_end(n.node_->group_prev_->next_); + iterator pos = this->add_node( + boost::unordered::detail::func::construct_value( + this->node_alloc(), boost::move(*n)), key_hash, iterator()); + for (++n; n != group_end; ++n) + { + this->add_node( + boost::unordered::detail::func::construct_value( + this->node_alloc(), boost::move(*n)), key_hash, pos); + } + } + } + + void assign_buckets(table const& src) { + node_holder holder(*this); + for (iterator n = src.begin(); n.node_;) { + std::size_t key_hash = n.node_->hash_; + iterator group_end(n.node_->group_prev_->next_); + iterator pos = this->add_node(holder.copy_of(*n), key_hash, iterator()); + for (++n; n != group_end; ++n) + { + this->add_node(holder.copy_of(*n), key_hash, pos); + } + } + } + + void move_assign_buckets(table& src) { + node_holder holder(*this); + for (iterator n = src.begin(); n.node_;) { + std::size_t key_hash = n.node_->hash_; + iterator group_end(n.node_->group_prev_->next_); + iterator pos = this->add_node(holder.move_copy_of(*n), key_hash, iterator()); + for (++n; n != group_end; ++n) + { + this->add_node(holder.move_copy_of(*n), key_hash, pos); } } } diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp new file mode 100644 index 00000000..22f8e633 --- /dev/null +++ b/include/boost/unordered/detail/map.hpp @@ -0,0 +1,61 @@ + +// Copyright (C) 2005-2016 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +namespace boost { namespace unordered { namespace detail { + template + struct map + { + typedef boost::unordered::detail::map types; + + typedef A allocator; + typedef std::pair value_type; + typedef H hasher; + typedef P key_equal; + typedef K key_type; + + typedef boost::unordered::detail::allocator_traits + traits; + typedef boost::unordered::detail::pick_node pick; + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + + typedef boost::unordered::detail::table_impl table; + typedef boost::unordered::detail::map_extractor + extractor; + + typedef typename boost::unordered::detail::pick_policy::type policy; + }; + + template + struct multimap + { + typedef boost::unordered::detail::multimap types; + + typedef A allocator; + typedef std::pair value_type; + typedef H hasher; + typedef P key_equal; + typedef K key_type; + + typedef boost::unordered::detail::allocator_traits traits; + typedef boost::unordered::detail::pick_grouped_node pick; + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + + typedef boost::unordered::detail::grouped_table_impl table; + typedef boost::unordered::detail::map_extractor + extractor; + + typedef typename boost::unordered::detail::pick_policy::type policy; + }; + +}}} diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp new file mode 100644 index 00000000..3ed9dde0 --- /dev/null +++ b/include/boost/unordered/detail/set.hpp @@ -0,0 +1,57 @@ + +// Copyright (C) 2005-2016 Daniel James +// Distributed under the Boost Software License, Version 1.0. (See accompanying +// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#include +#include +#include + +namespace boost { namespace unordered { namespace detail { + template + struct set + { + typedef boost::unordered::detail::set types; + + typedef A allocator; + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef T key_type; + + typedef boost::unordered::detail::allocator_traits traits; + typedef boost::unordered::detail::pick_node pick; + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + + typedef boost::unordered::detail::table_impl table; + typedef boost::unordered::detail::set_extractor extractor; + + typedef typename boost::unordered::detail::pick_policy::type policy; + }; + + template + struct multiset + { + typedef boost::unordered::detail::multiset types; + + typedef A allocator; + typedef T value_type; + typedef H hasher; + typedef P key_equal; + typedef T key_type; + + typedef boost::unordered::detail::allocator_traits traits; + typedef boost::unordered::detail::pick_grouped_node pick; + typedef typename pick::node node; + typedef typename pick::bucket bucket; + typedef typename pick::link_pointer link_pointer; + + typedef boost::unordered::detail::grouped_table_impl table; + typedef boost::unordered::detail::set_extractor extractor; + + typedef typename boost::unordered::detail::pick_policy::type policy; + }; +}}} diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index a337f45b..ab4000b4 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -13,10 +13,6 @@ #endif #include -#include -#include -#include -#include #if defined(BOOST_MSVC) #pragma warning(push) @@ -68,70 +64,6 @@ namespace boost { namespace unordered { namespace detail { value_base& operator=(value_base const&); }; - template - struct copy_nodes - { - typedef boost::unordered::detail::allocator_traits - node_allocator_traits; - - node_constructor constructor; - - explicit copy_nodes(NodeAlloc& a) : constructor(a) {} - - typename node_allocator_traits::pointer create( - typename node_allocator_traits::value_type::value_type const& v) - { - constructor.construct_with_value2(v); - return constructor.release(); - } - }; - - template - struct move_nodes - { - typedef boost::unordered::detail::allocator_traits - node_allocator_traits; - - node_constructor constructor; - - explicit move_nodes(NodeAlloc& a) : constructor(a) {} - - typename node_allocator_traits::pointer create( - typename node_allocator_traits::value_type::value_type& v) - { - constructor.construct_with_value2(boost::move(v)); - return constructor.release(); - } - }; - - template - struct assign_nodes - { - node_holder holder; - - explicit assign_nodes(Buckets& b) : holder(b) {} - - typename Buckets::node_pointer create( - typename Buckets::value_type const& v) - { - return holder.copy_of(v); - } - }; - - template - struct move_assign_nodes - { - node_holder holder; - - explicit move_assign_nodes(Buckets& b) : holder(b) {} - - typename Buckets::node_pointer create( - typename Buckets::value_type& v) - { - return holder.move_copy_of(v); - } - }; - template struct table : boost::unordered::detail::functions< @@ -175,6 +107,8 @@ namespace boost { namespace unordered { namespace detail { bucket_pointer; typedef boost::unordered::detail::node_constructor node_constructor; + typedef boost::unordered::detail::node_tmp + node_tmp; typedef boost::unordered::iterator_detail:: iterator iterator; @@ -391,9 +325,7 @@ namespace boost { namespace unordered { namespace detail { void init(table const& x) { if (x.size_) { - create_buckets(bucket_count_); - copy_nodes node_creator(node_alloc()); - static_cast(this)->fill_buckets(x.begin(), node_creator); + static_cast(this)->copy_buckets(x); } } @@ -404,11 +336,7 @@ namespace boost { namespace unordered { namespace detail { } else if(x.size_) { // TODO: Could pick new bucket size? - create_buckets(bucket_count_); - - move_nodes node_creator(node_alloc()); - node_holder nodes(x); - static_cast(this)->fill_buckets(nodes.begin(), node_creator); + static_cast(this)->move_buckets(x); } } @@ -417,34 +345,53 @@ namespace boost { namespace unordered { namespace detail { void create_buckets(std::size_t new_count) { - boost::unordered::detail::array_constructor - constructor(bucket_alloc()); - - // Creates an extra bucket to act as the start node. - constructor.construct(bucket(), new_count + 1); + std::size_t length = new_count + 1; + bucket_pointer new_buckets = bucket_allocator_traits::allocate( + bucket_alloc(), length); + bucket_pointer constructed = new_buckets; - if (buckets_) - { - // Copy the nodes to the new buckets, including the dummy - // node if there is one. - (constructor.get() + - static_cast(new_count))->next_ = - (buckets_ + static_cast( - bucket_count_))->next_; - destroy_buckets(); - } - else if (bucket::extra_node) - { - node_constructor a(node_alloc()); - a.construct(); + BOOST_TRY { + bucket_pointer end = new_buckets + + static_cast(length); + for(; constructed != end; ++constructed) { + new ((void*) boost::addressof(*constructed)) bucket(); + } - (constructor.get() + - static_cast(new_count))->next_ = - a.release(); + if (buckets_) + { + // Copy the nodes to the new buckets, including the dummy + // node if there is one. + (new_buckets + + static_cast(new_count))->next_ = + (buckets_ + static_cast( + bucket_count_))->next_; + destroy_buckets(); + } + else if (bucket::extra_node) + { + node_constructor a(node_alloc()); + a.create_node(); + + (new_buckets + + static_cast(new_count))->next_ = + a.release(); + } } + BOOST_CATCH(...) { + for(bucket_pointer p = new_buckets; p != constructed; ++p) { + boost::unordered::detail::func::destroy( + boost::addressof(*p)); + } + + bucket_allocator_traits::deallocate(bucket_alloc(), + new_buckets, length); + + BOOST_RETHROW; + } + BOOST_CATCH_END bucket_count_ = new_count; - buckets_ = constructor.release(); + buckets_ = new_buckets; recalculate_max_load(); } @@ -650,11 +597,7 @@ namespace boost { namespace unordered { namespace detail { clear_buckets(); } - // assign_nodes takes ownership of the container's elements, - // assigning to them if possible, and deleting any that are - // left over. - assign_nodes node_creator(*this); - static_cast(this)->fill_buckets(x.begin(), node_creator); + static_cast(this)->assign_buckets(x); } void assign(table const& x, true_type) @@ -679,9 +622,7 @@ namespace boost { namespace unordered { namespace detail { // Finally copy the elements. if (x.size_) { - create_buckets(bucket_count_); - copy_nodes node_creator(node_alloc()); - static_cast(this)->fill_buckets(x.begin(), node_creator); + static_cast(this)->copy_buckets(x); } } } @@ -735,12 +676,7 @@ namespace boost { namespace unordered { namespace detail { clear_buckets(); } - // move_assign_nodes takes ownership of the container's - // elements, assigning to them if possible, and deleting - // any that are left over. - move_assign_nodes
node_creator(*this); - node_holder nodes(x); - static_cast(this)->fill_buckets(nodes.begin(), node_creator); + static_cast(this)->move_assign_buckets(x); } } diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index a318d0b3..07923981 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -12,7 +12,6 @@ #pragma once #endif -#include #include #include #include @@ -126,54 +125,6 @@ namespace boost { namespace unordered { namespace detail { typedef typename pick::link_pointer link_pointer; }; - template - struct set - { - typedef boost::unordered::detail::set types; - - typedef A allocator; - typedef T value_type; - typedef H hasher; - typedef P key_equal; - typedef T key_type; - - typedef boost::unordered::detail::allocator_traits traits; - typedef boost::unordered::detail::pick_node pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::table_impl table; - typedef boost::unordered::detail::set_extractor extractor; - - typedef typename boost::unordered::detail::pick_policy::type policy; - }; - - template - struct map - { - typedef boost::unordered::detail::map types; - - typedef A allocator; - typedef std::pair value_type; - typedef H hasher; - typedef P key_equal; - typedef K key_type; - - typedef boost::unordered::detail::allocator_traits - traits; - typedef boost::unordered::detail::pick_node pick; - typedef typename pick::node node; - typedef typename pick::bucket bucket; - typedef typename pick::link_pointer link_pointer; - - typedef boost::unordered::detail::table_impl table; - typedef boost::unordered::detail::map_extractor - extractor; - - typedef typename boost::unordered::detail::pick_policy::type policy; - }; - template struct table_impl : boost::unordered::detail::table { @@ -190,6 +141,7 @@ namespace boost { namespace unordered { namespace detail { typedef typename table::key_equal key_equal; typedef typename table::key_type key_type; typedef typename table::node_constructor node_constructor; + typedef typename table::node_tmp node_tmp; typedef typename table::extractor extractor; typedef typename table::iterator iterator; typedef typename table::c_iterator c_iterator; @@ -307,13 +259,6 @@ namespace boost { namespace unordered { namespace detail { // Emplace/Insert - inline iterator add_node( - node_constructor& a, - std::size_t key_hash) - { - return add_node(a.release(), key_hash); - } - inline iterator add_node( node_pointer n, std::size_t key_hash) @@ -346,23 +291,21 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } + inline iterator resize_and_add_node(node_pointer n, std::size_t key_hash) + { + node_tmp b(n, this->node_alloc()); + this->reserve_for_insert(this->size_ + 1); + return this->add_node(b.release(), key_hash); + } + value_type& operator[](key_type const& k) { std::size_t key_hash = this->hash(k); iterator pos = this->find_node(key_hash, k); - if (pos.node_) return *pos; - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(this->node_alloc()); - a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3( - boost::unordered::piecewise_construct, - boost::make_tuple(k), - boost::make_tuple())); - - this->reserve_for_insert(this->size_ + 1); - return *add_node(a, key_hash); + return *this->resize_and_add_node( + boost::unordered::detail::func::construct_pair(this->node_alloc(), k), + key_hash); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -412,32 +355,17 @@ namespace boost { namespace unordered { namespace detail { { std::size_t key_hash = this->hash(k); iterator pos = this->find_node(key_hash, k); - - if (pos.node_) return emplace_return(pos, false); - - // Create the node before rehashing in case it throws an - // exception (need strong safety in such a case). - node_constructor a(this->node_alloc()); - a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - this->reserve_for_insert(this->size_ + 1); - return emplace_return(this->add_node(a, key_hash), true); - } - - emplace_return emplace_impl_with_node(node_constructor& a) - { - key_type const& k = this->get_key(a.value()); - std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); - - if (pos.node_) return emplace_return(pos, false); - - // reserve has basic exception safety if the hash function - // throws, strong otherwise. - this->reserve_for_insert(this->size_ + 1); - return emplace_return(this->add_node(a, key_hash), true); + if (pos.node_) { + return emplace_return(pos, false); + } + else { + return emplace_return( + this->resize_and_add_node( + boost::unordered::detail::func::construct_value_generic( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + key_hash), + true); + } } template @@ -445,9 +373,21 @@ namespace boost { namespace unordered { namespace detail { { // Don't have a key, so construct the node first in order // to be able to lookup the position. - node_constructor a(this->node_alloc()); - a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); - return emplace_impl_with_node(a); + node_tmp b( + boost::unordered::detail::func::construct_value_generic( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + key_type const& k = this->get_key(b.node_->value()); + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); + if (pos.node_) { + return emplace_return(pos, false); + } + else { + return emplace_return( + this->resize_and_add_node(b.release(), key_hash), + true); + } } //////////////////////////////////////////////////////////////////////// @@ -466,9 +406,7 @@ namespace boost { namespace unordered { namespace detail { template void insert_range_impl(key_type const& k, InputIt i, InputIt j) { - node_constructor a(this->node_alloc()); - - insert_range_impl2(a, k, i, j); + insert_range_impl2(k, i, j); while(++i != j) { // Note: can't use get_key as '*i' might not be value_type - it @@ -479,26 +417,25 @@ namespace boost { namespace unordered { namespace detail { // key here. Could be more efficient if '*i' is expensive. Could // be less efficient if copying the full value_type is // expensive. - insert_range_impl2(a, extractor::extract(*i), i, j); + insert_range_impl2(extractor::extract(*i), i, j); } } template - void insert_range_impl2(node_constructor& a, key_type const& k, - InputIt i, InputIt j) + void insert_range_impl2(key_type const& k, InputIt i, InputIt j) { // No side effects in this initial code std::size_t key_hash = this->hash(k); iterator pos = this->find_node(key_hash, k); if (!pos.node_) { - a.construct_with_value2(*i); + node_tmp b( + boost::unordered::detail::func::construct_value(this->node_alloc(), *i), + this->node_alloc()); if(this->size_ + 1 > this->max_load_) this->reserve_for_insert(this->size_ + boost::unordered::detail::insert_size(i, j)); - - // Nothing after this point can throw. - this->add_node(a, key_hash); + this->add_node(b.release(), key_hash); } } @@ -508,8 +445,24 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(this->node_alloc()); do { - a.construct_with_value2(*i); - emplace_impl_with_node(a); + if (!a.node_) { a.create_node(); } + boost::unordered::detail::func::call_construct( + a.alloc_, a.node_->value_ptr(), *i); + node_tmp b(a.release(), a.alloc_); + + key_type const& k = this->get_key(b.node_->value()); + std::size_t key_hash = this->hash(k); + iterator pos = this->find_node(key_hash, k); + + if (pos.node_) { + a.reclaim(b.release()); + } + else { + // reserve has basic exception safety if the hash function + // throws, strong otherwise. + this->reserve_for_insert(this->size_ + 1); + this->add_node(b.release(), key_hash); + } } while(++i != j); } @@ -582,11 +535,39 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////// // fill_buckets - template - void fill_buckets(iterator n, NodeCreator& creator) + void copy_buckets(table const& src) { + this->create_buckets(this->bucket_count_); + + for(iterator n = src.begin(); n.node_; ++n) { + this->add_node( + boost::unordered::detail::func::construct_value( + this->node_alloc(), *n), n.node_->hash_); + } + } + + void move_buckets(table const& src) { + this->create_buckets(this->bucket_count_); + + for(iterator n = src.begin(); n.node_; ++n) { + this->add_node( + boost::unordered::detail::func::construct_value( + this->node_alloc(), boost::move(*n)), n.node_->hash_); + } + } + + void assign_buckets(table const& src) { - for (; n.node_; ++n) { - this->add_node(creator.create(*n), n.node_->hash_); + node_holder holder(*this); + for(iterator n = src.begin(); n.node_; ++n) { + this->add_node(holder.copy_of(*n), n.node_->hash_); + } + } + + void move_assign_buckets(table& src) + { + node_holder holder(*this); + for(iterator n = src.begin(); n.node_; ++n) { + this->add_node(holder.move_copy_of(*n), n.node_->hash_); } } diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 9b180796..3904e56e 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -15,9 +15,7 @@ #endif #include -#include -#include -#include +#include #include #include diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index 853b5d73..c8c06215 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -14,10 +14,7 @@ #pragma once #endif -#include -#include -#include -#include +#include #include #include