From 609ae6cb4ec742914d8e9f69a1ab5cbd251839fd Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 01/14] Expand out fill_buckets. --- include/boost/unordered/detail/equivalent.hpp | 59 ++++++++++-- include/boost/unordered/detail/table.hpp | 91 +------------------ include/boost/unordered/detail/unique.hpp | 36 +++++++- 3 files changed, 89 insertions(+), 97 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index b7b40f1a..c58108ab 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -628,17 +628,62 @@ 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) { + node_constructor constructor(this->node_alloc()); + 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()); + constructor.construct_with_value2(*n); + iterator pos = this->add_node(constructor, key_hash, iterator()); for (++n; n != group_end; ++n) { - this->add_node(creator.create(*n), key_hash, pos); + constructor.construct_with_value2(*n); + this->add_node(constructor, key_hash, pos); + } + } + } + + void move_buckets(table& src) { + node_constructor constructor(this->node_alloc()); + 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_); + constructor.construct_with_value2(boost::move(*n)); + iterator pos = this->add_node(constructor, key_hash, iterator()); + for (++n; n != group_end; ++n) + { + constructor.construct_with_value2(boost::move(*n)); + this->add_node(constructor, 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/table.hpp b/include/boost/unordered/detail/table.hpp index a337f45b..7a0584f7 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -68,70 +68,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< @@ -391,9 +327,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 +338,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); } } @@ -650,11 +580,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 +605,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 +659,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..ef0ce445 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -582,11 +582,39 @@ namespace boost { namespace unordered { namespace detail { //////////////////////////////////////////////////////////////////////// // fill_buckets - template - void fill_buckets(iterator n, NodeCreator& creator) + void copy_buckets(table const& src) { + node_constructor constructor(this->node_alloc()); + this->create_buckets(this->bucket_count_); + + for(iterator n = src.begin(); n.node_; ++n) { + constructor.construct_with_value2(*n); + this->add_node(constructor, n.node_->hash_); + } + } + + void move_buckets(table& src) { + node_constructor constructor(this->node_alloc()); + this->create_buckets(this->bucket_count_); + + for(iterator n = src.begin(); n.node_; ++n) { + constructor.construct_with_value2(boost::move(*n)); + this->add_node(constructor, 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_); } } From 8017d9e6845d30c064b63d524bddc14af55ad147 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 02/14] Change how node construction works. Split node_constructor into two classes, one for constructing a node without a value, and then another for holding it once the value is constructed. Do the work of constructing values in convenience functions in allocate.hpp (construct_value_generic, construct_value, construct_pair). --- include/boost/unordered/detail/allocate.hpp | 52 +++++ include/boost/unordered/detail/buckets.hpp | 205 +++++++++--------- include/boost/unordered/detail/equivalent.hpp | 60 +++-- include/boost/unordered/detail/table.hpp | 4 +- include/boost/unordered/detail/unique.hpp | 65 ++++-- 5 files changed, 247 insertions(+), 139 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 4c20b168..733d8e4c 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -808,6 +808,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) { @@ -1049,6 +1061,46 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES + // Some nicer construct_value functions, might try to + // improve implementation later. + + template + inline typename AllocAndPointer::node_pointer construct_value_generic(AllocAndPointer& a, BOOST_UNORDERED_EMPLACE_ARGS) { + construct_value_impl(a.alloc_, a.node_->value_ptr(), + BOOST_UNORDERED_EMPLACE_FORWARD); + return a.release(); + } + + template + inline typename AllocAndPointer::node_pointer construct_value(AllocAndPointer& a, BOOST_FWD_REF(U) x) { + boost::unordered::detail::func::call_construct( + a.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 AllocAndPointer::node_pointer construct_pair(AllocAndPointer& a, BOOST_FWD_REF(Key) k) { + boost::unordered::detail::func::call_construct( + a.alloc_, boost::addressof(a.node_->value_ptr()->first), + boost::forward(k)); + boost::unordered::detail::func::call_construct( + a.alloc_, boost::addressof(a.node_->value_ptr()->second)); + return a.release(); + } + + template + inline typename AllocAndPointer::node_pointer construct_pair(AllocAndPointer& a, + BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { + boost::unordered::detail::func::call_construct( + a.alloc_, boost::addressof(a.node_->value_ptr()->first), + boost::forward(k)); + boost::unordered::detail::func::call_construct( + a.alloc_, boost::addressof(a.node_->value_ptr()->second), + boost::forward(m)); + return a.release(); + } }}}} namespace boost { namespace unordered { namespace detail { diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index ac5bd6d8..64a0a8ec 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -324,8 +324,6 @@ namespace boost { namespace unordered { namespace detail { template struct node_constructor { - private: - typedef NodeAlloc node_allocator; typedef boost::unordered::detail::allocator_traits node_allocator_traits; @@ -333,50 +331,20 @@ namespace boost { namespace unordered { namespace detail { 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_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(); - } + void create_node(); // no throw node_pointer release() @@ -387,6 +355,14 @@ namespace boost { namespace unordered { namespace detail { return p; } + void reclaim(node_pointer p) { + BOOST_ASSERT(!node_); + node_ = p; + node_constructed_ = true; + boost::unordered::detail::func::destroy_value_impl(alloc_, + node_->value_ptr()); + } + private: node_constructor(node_constructor const&); node_constructor& operator=(node_constructor const&); @@ -396,11 +372,6 @@ namespace boost { namespace unordered { namespace detail { 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_)); @@ -411,27 +382,66 @@ namespace boost { namespace unordered { namespace detail { } template - void node_constructor::construct() + void node_constructor::create_node() { - if(!node_) { - node_constructed_ = false; - value_constructed_ = false; + BOOST_ASSERT(!node_); + node_constructed_ = false; - node_ = node_allocator_traits::allocate(alloc_, 1); + node_ = node_allocator_traits::allocate(alloc_, 1); - new ((void*) boost::addressof(*node_)) node(); - node_->init(node_); - node_constructed_ = true; + new ((void*) boost::addressof(*node_)) node(); + node_->init(node_); + node_constructed_ = true; + } + + template + struct node_tmp + { + 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; + + public: + + node_allocator& alloc_; + node_pointer node_; + + explicit node_tmp(node_pointer n, node_allocator& a): + alloc_(a), + node_(n) + { } - else { - BOOST_ASSERT(node_constructed_); - if (value_constructed_) - { - boost::unordered::detail::func::destroy_value_impl(alloc_, - node_->value_ptr()); - value_constructed_ = false; - } + ~node_tmp(); + + value_type const& value() const { + BOOST_ASSERT(node_ ); + return node_->value(); + } + + // 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); } } @@ -442,11 +452,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 +464,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 +484,63 @@ 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(); + return boost::unordered::detail::func::construct_value(constructor_, v); } } 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(); + } + return boost::unordered::detail::func::construct_value(constructor_, v); } 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(); + return boost::unordered::detail::func::construct_value( + constructor_, boost::move(v)); } } 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(); + } + return boost::unordered::detail::func::construct_value( + constructor_, boost::move(v)); } iterator begin() const @@ -545,10 +556,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 c58108ab..4d5c0f36 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -195,6 +195,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; @@ -381,7 +382,7 @@ namespace boost { namespace unordered { namespace detail { } inline iterator add_node( - node_constructor& a, + node_tmp& a, std::size_t key_hash, iterator pos) { @@ -432,7 +433,7 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } - iterator emplace_impl(node_constructor& a) + iterator emplace_impl(node_tmp& a) { key_type const& k = this->get_key(a.value()); std::size_t key_hash = this->hash(k); @@ -444,7 +445,7 @@ namespace boost { namespace unordered { namespace detail { return this->add_node(a, key_hash, position); } - void emplace_impl_no_rehash(node_constructor& a) + void emplace_impl_no_rehash(node_tmp& a) { key_type const& k = this->get_key(a.value()); std::size_t key_hash = this->hash(k); @@ -473,9 +474,12 @@ namespace boost { namespace unordered { namespace detail { iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) { node_constructor a(this->node_alloc()); - a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value_generic(a, BOOST_UNORDERED_EMPLACE_FORWARD), + a.alloc_); - return iterator(emplace_impl(a)); + return iterator(emplace_impl(b)); } //////////////////////////////////////////////////////////////////////// @@ -492,8 +496,12 @@ 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); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value(a, *i), + a.alloc_); + + emplace_impl(b); } else { // Only require basic exception safety here @@ -501,8 +509,11 @@ namespace boost { namespace unordered { namespace detail { node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct_with_value2(*i); - emplace_impl_no_rehash(a); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value(a, *i), + a.alloc_); + emplace_impl_no_rehash(b); } } } @@ -513,8 +524,11 @@ namespace boost { namespace unordered { namespace detail { { node_constructor a(this->node_alloc()); for (; i != j; ++i) { - a.construct_with_value2(*i); - emplace_impl(a); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value(a, *i), + a.alloc_); + emplace_impl(b); } } @@ -635,12 +649,16 @@ namespace boost { namespace unordered { namespace detail { for (iterator n = src.begin(); n.node_;) { std::size_t key_hash = n.node_->hash_; iterator group_end(n.node_->group_prev_->next_); - constructor.construct_with_value2(*n); - iterator pos = this->add_node(constructor, key_hash, iterator()); + constructor.create_node(); + iterator pos = this->add_node( + boost::unordered::detail::func::construct_value( + constructor, *n), key_hash, iterator()); for (++n; n != group_end; ++n) { - constructor.construct_with_value2(*n); - this->add_node(constructor, key_hash, pos); + constructor.create_node(); + this->add_node( + boost::unordered::detail::func::construct_value( + constructor, *n), key_hash, pos); } } } @@ -652,12 +670,16 @@ namespace boost { namespace unordered { namespace detail { for (iterator n = src.begin(); n.node_;) { std::size_t key_hash = n.node_->hash_; iterator group_end(n.node_->group_prev_->next_); - constructor.construct_with_value2(boost::move(*n)); - iterator pos = this->add_node(constructor, key_hash, iterator()); + constructor.create_node(); + iterator pos = this->add_node( + boost::unordered::detail::func::construct_value( + constructor, boost::move(*n)), key_hash, iterator()); for (++n; n != group_end; ++n) { - constructor.construct_with_value2(boost::move(*n)); - this->add_node(constructor, key_hash, pos); + constructor.create_node(); + this->add_node( + boost::unordered::detail::func::construct_value( + constructor, boost::move(*n)), key_hash, pos); } } } diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 7a0584f7..00c28c3b 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -111,6 +111,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; @@ -366,7 +368,7 @@ namespace boost { namespace unordered { namespace detail { else if (bucket::extra_node) { node_constructor a(node_alloc()); - a.construct(); + a.create_node(); (constructor.get() + static_cast(new_count))->next_ = diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index ef0ce445..d1012924 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -190,6 +190,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; @@ -308,7 +309,7 @@ namespace boost { namespace unordered { namespace detail { // Emplace/Insert inline iterator add_node( - node_constructor& a, + node_tmp& a, std::size_t key_hash) { return add_node(a.release(), key_hash); @@ -356,13 +357,12 @@ namespace boost { namespace unordered { namespace detail { // 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())); + a.create_node(); + node_tmp b(boost::unordered::detail::func::construct_pair(a, k), + a.alloc_); this->reserve_for_insert(this->size_ + 1); - return *add_node(a, key_hash); + return *add_node(b, key_hash); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -418,26 +418,33 @@ namespace boost { namespace unordered { namespace detail { // 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); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value_generic( + a, BOOST_UNORDERED_EMPLACE_FORWARD), + a.alloc_); // 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); + return emplace_return(this->add_node(b, key_hash), true); } - emplace_return emplace_impl_with_node(node_constructor& a) + emplace_return emplace_impl_with_node(node_constructor& a, node_tmp& b) { - key_type const& k = this->get_key(a.value()); + key_type const& k = this->get_key(b.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); + if (pos.node_) { + a.reclaim(b.release()); + 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); + return emplace_return(this->add_node(b, key_hash), true); } template @@ -446,8 +453,12 @@ 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); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value_generic( + a, BOOST_UNORDERED_EMPLACE_FORWARD), + a.alloc_); + return emplace_impl_with_node(a, b); } //////////////////////////////////////////////////////////////////////// @@ -492,13 +503,16 @@ namespace boost { namespace unordered { namespace detail { iterator pos = this->find_node(key_hash, k); if (!pos.node_) { - a.construct_with_value2(*i); + a.create_node(); + node_tmp b( + boost::unordered::detail::func::construct_value(a, *i), + a.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, key_hash); } } @@ -508,8 +522,11 @@ 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(); } + node_tmp b( + boost::unordered::detail::func::construct_value(a, *i), + a.alloc_); + emplace_impl_with_node(a, b); } while(++i != j); } @@ -587,8 +604,10 @@ namespace boost { namespace unordered { namespace detail { this->create_buckets(this->bucket_count_); for(iterator n = src.begin(); n.node_; ++n) { - constructor.construct_with_value2(*n); - this->add_node(constructor, n.node_->hash_); + constructor.create_node(); + this->add_node( + boost::unordered::detail::func::construct_value( + constructor, *n), n.node_->hash_); } } @@ -597,8 +616,10 @@ namespace boost { namespace unordered { namespace detail { this->create_buckets(this->bucket_count_); for(iterator n = src.begin(); n.node_; ++n) { - constructor.construct_with_value2(boost::move(*n)); - this->add_node(constructor, n.node_->hash_); + constructor.create_node(); + this->add_node( + boost::unordered::detail::func::construct_value( + constructor, boost::move(*n)), n.node_->hash_); } } From 37a69038318e78370e326eea422c2ec1431810a7 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 03/14] Move node construction into allocate.hpp --- include/boost/unordered/detail/allocate.hpp | 135 ++++++++++++++++++++ include/boost/unordered/detail/buckets.hpp | 128 ------------------- 2 files changed, 135 insertions(+), 128 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 733d8e4c..c3b34ce3 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -1061,6 +1061,141 @@ BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::) #endif // BOOST_NO_CXX11_VARIADIC_TEMPLATES +}}}} + +namespace boost { namespace unordered { namespace detail { + + /////////////////////////////////////////////////////////////////// + // + // Node construction + + template + struct node_constructor + { + 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; + + node_allocator& alloc_; + node_pointer node_; + bool node_constructed_; + + node_constructor(node_allocator& n) : + alloc_(n), + node_(), + node_constructed_(false) + { + } + + ~node_constructor(); + + void create_node(); + + // no throw + node_pointer release() + { + BOOST_ASSERT(node_ && node_constructed_); + node_pointer p = node_; + node_ = node_pointer(); + return p; + } + + void reclaim(node_pointer p) { + BOOST_ASSERT(!node_); + node_ = p; + node_constructed_ = true; + boost::unordered::detail::func::destroy_value_impl(alloc_, + node_->value_ptr()); + } + + 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 + { + 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; + + public: + + node_allocator& alloc_; + node_pointer node_; + + explicit node_tmp(node_pointer n, node_allocator& a): + alloc_(a), + node_(n) + { + } + + ~node_tmp(); + + value_type const& value() const { + BOOST_ASSERT(node_ ); + return node_->value(); + } + + // 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. diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 64a0a8ec..24257ea8 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -317,134 +317,6 @@ namespace boost { namespace unordered { namespace iterator_detail { namespace boost { namespace unordered { namespace detail { - /////////////////////////////////////////////////////////////////// - // - // Node construction - - template - struct node_constructor - { - 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; - - node_allocator& alloc_; - node_pointer node_; - bool node_constructed_; - - node_constructor(node_allocator& n) : - alloc_(n), - node_(), - node_constructed_(false) - { - } - - ~node_constructor(); - - void create_node(); - - // no throw - node_pointer release() - { - BOOST_ASSERT(node_ && node_constructed_); - node_pointer p = node_; - node_ = node_pointer(); - return p; - } - - void reclaim(node_pointer p) { - BOOST_ASSERT(!node_); - node_ = p; - node_constructed_ = true; - boost::unordered::detail::func::destroy_value_impl(alloc_, - node_->value_ptr()); - } - - 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 - { - 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; - - public: - - node_allocator& alloc_; - node_pointer node_; - - explicit node_tmp(node_pointer n, node_allocator& a): - alloc_(a), - node_(n) - { - } - - ~node_tmp(); - - value_type const& value() const { - BOOST_ASSERT(node_ ); - return node_->value(); - } - - // 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); - } - } - /////////////////////////////////////////////////////////////////// // // Node Holder From 88612a8be44b96a7f8aef17a92ac8349a04a1c01 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 04/14] Less faffing around with node_constructor. --- include/boost/unordered/detail/allocate.hpp | 45 ++++++--- include/boost/unordered/detail/buckets.hpp | 20 ++-- include/boost/unordered/detail/equivalent.hpp | 45 ++++----- include/boost/unordered/detail/unique.hpp | 92 +++++++++---------- 4 files changed, 103 insertions(+), 99 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index c3b34ce3..710a7a5f 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -1199,40 +1199,55 @@ namespace boost { namespace unordered { namespace detail { namespace func { // Some nicer construct_value functions, might try to // improve implementation later. - template - inline typename AllocAndPointer::node_pointer construct_value_generic(AllocAndPointer& a, BOOST_UNORDERED_EMPLACE_ARGS) { - construct_value_impl(a.alloc_, a.node_->value_ptr(), + 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 AllocAndPointer::node_pointer construct_value(AllocAndPointer& a, BOOST_FWD_REF(U) x) { + 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( - a.alloc_, a.node_->value_ptr(), boost::forward(x)); + 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 AllocAndPointer::node_pointer construct_pair(AllocAndPointer& a, BOOST_FWD_REF(Key) k) { + 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( - a.alloc_, boost::addressof(a.node_->value_ptr()->first), + alloc, boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); boost::unordered::detail::func::call_construct( - a.alloc_, boost::addressof(a.node_->value_ptr()->second)); + alloc, boost::addressof(a.node_->value_ptr()->second)); return a.release(); } - template - inline typename AllocAndPointer::node_pointer construct_pair(AllocAndPointer& a, - BOOST_FWD_REF(Key) k, BOOST_FWD_REF(Mapped) m) { + 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( - a.alloc_, boost::addressof(a.node_->value_ptr()->first), + alloc, boost::addressof(a.node_->value_ptr()->first), boost::forward(k)); boost::unordered::detail::func::call_construct( - a.alloc_, boost::addressof(a.node_->value_ptr()->second), + alloc, boost::addressof(a.node_->value_ptr()->second), boost::forward(m)); return a.release(); } diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 24257ea8..d7cc170b 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -374,7 +374,9 @@ namespace boost { namespace unordered { namespace detail { } else { constructor_.create_node(); - return boost::unordered::detail::func::construct_value(constructor_, v); + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), v); + return constructor_.release(); } } @@ -386,7 +388,9 @@ namespace boost { namespace unordered { namespace detail { else { constructor_.create_node(); } - return boost::unordered::detail::func::construct_value(constructor_, v); + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), v); + return constructor_.release(); } template @@ -398,8 +402,10 @@ namespace boost { namespace unordered { namespace detail { } else { constructor_.create_node(); - return boost::unordered::detail::func::construct_value( - constructor_, boost::move(v)); + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), + boost::move(v)); + return constructor_.release(); } } @@ -411,8 +417,10 @@ namespace boost { namespace unordered { namespace detail { else { constructor_.create_node(); } - return boost::unordered::detail::func::construct_value( - constructor_, boost::move(v)); + boost::unordered::detail::func::call_construct( + constructor_.alloc_, constructor_.node_->value_ptr(), + boost::move(v)); + return constructor_.release(); } iterator begin() const diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 4d5c0f36..ea8d34d9 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -473,11 +473,10 @@ namespace boost { namespace unordered { namespace detail { template iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) { - node_constructor a(this->node_alloc()); - a.create_node(); node_tmp b( - boost::unordered::detail::func::construct_value_generic(a, BOOST_UNORDERED_EMPLACE_FORWARD), - a.alloc_); + boost::unordered::detail::func::construct_value_generic( + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); return iterator(emplace_impl(b)); } @@ -495,24 +494,21 @@ namespace boost { namespace unordered { namespace detail { std::size_t distance = std::distance(i, j); if(distance == 1) { - node_constructor a(this->node_alloc()); - a.create_node(); node_tmp b( - boost::unordered::detail::func::construct_value(a, *i), - a.alloc_); - + boost::unordered::detail::func::construct_value( + this->node_alloc(), *i), + this->node_alloc()); emplace_impl(b); } 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.create_node(); node_tmp b( - boost::unordered::detail::func::construct_value(a, *i), - a.alloc_); + boost::unordered::detail::func::construct_value( + this->node_alloc(), *i), + this->node_alloc()); emplace_impl_no_rehash(b); } } @@ -522,12 +518,11 @@ 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.create_node(); node_tmp b( - boost::unordered::detail::func::construct_value(a, *i), - a.alloc_); + boost::unordered::detail::func::construct_value( + this->node_alloc(), *i), + this->node_alloc()); emplace_impl(b); } } @@ -643,43 +638,37 @@ namespace boost { namespace unordered { namespace detail { // fill_buckets void copy_buckets(table const& src) { - node_constructor constructor(this->node_alloc()); 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_); - constructor.create_node(); iterator pos = this->add_node( boost::unordered::detail::func::construct_value( - constructor, *n), key_hash, iterator()); + this->node_alloc(), *n), key_hash, iterator()); for (++n; n != group_end; ++n) { - constructor.create_node(); this->add_node( boost::unordered::detail::func::construct_value( - constructor, *n), key_hash, pos); + this->node_alloc(), *n), key_hash, pos); } } } - void move_buckets(table& src) { - node_constructor constructor(this->node_alloc()); + 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_); - constructor.create_node(); iterator pos = this->add_node( boost::unordered::detail::func::construct_value( - constructor, boost::move(*n)), key_hash, iterator()); + this->node_alloc(), boost::move(*n)), key_hash, iterator()); for (++n; n != group_end; ++n) { - constructor.create_node(); this->add_node( boost::unordered::detail::func::construct_value( - constructor, boost::move(*n)), key_hash, pos); + this->node_alloc(), boost::move(*n)), key_hash, pos); } } } diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index d1012924..1ec71aef 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -356,10 +356,9 @@ namespace boost { namespace unordered { namespace detail { // 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.create_node(); - node_tmp b(boost::unordered::detail::func::construct_pair(a, k), - a.alloc_); + node_tmp b( + boost::unordered::detail::func::construct_pair(this->node_alloc(), k), + this->node_alloc()); this->reserve_for_insert(this->size_ + 1); return *add_node(b, key_hash); @@ -417,12 +416,10 @@ namespace boost { namespace unordered { namespace detail { // 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.create_node(); node_tmp b( boost::unordered::detail::func::construct_value_generic( - a, BOOST_UNORDERED_EMPLACE_FORWARD), - a.alloc_); + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); // reserve has basic exception safety if the hash function // throws, strong otherwise. @@ -430,35 +427,25 @@ namespace boost { namespace unordered { namespace detail { return emplace_return(this->add_node(b, key_hash), true); } - emplace_return emplace_impl_with_node(node_constructor& a, node_tmp& b) - { - key_type const& k = this->get_key(b.value()); - std::size_t key_hash = this->hash(k); - iterator pos = this->find_node(key_hash, k); - - if (pos.node_) { - a.reclaim(b.release()); - 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(b, key_hash), true); - } - template emplace_return emplace_impl(no_key, BOOST_UNORDERED_EMPLACE_ARGS) { // 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.create_node(); node_tmp b( boost::unordered::detail::func::construct_value_generic( - a, BOOST_UNORDERED_EMPLACE_FORWARD), - a.alloc_); - return emplace_impl_with_node(a, b); + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), + this->node_alloc()); + key_type const& k = this->get_key(b.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(b, key_hash), true); } //////////////////////////////////////////////////////////////////////// @@ -477,9 +464,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 @@ -490,23 +475,21 @@ 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.create_node(); node_tmp b( - boost::unordered::detail::func::construct_value(a, *i), - a.alloc_); + 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)); @@ -523,10 +506,23 @@ namespace boost { namespace unordered { namespace detail { do { if (!a.node_) { a.create_node(); } - node_tmp b( - boost::unordered::detail::func::construct_value(a, *i), - a.alloc_); - emplace_impl_with_node(a, b); + 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.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, key_hash); + } } while(++i != j); } @@ -600,26 +596,22 @@ namespace boost { namespace unordered { namespace detail { // fill_buckets void copy_buckets(table const& src) { - node_constructor constructor(this->node_alloc()); this->create_buckets(this->bucket_count_); for(iterator n = src.begin(); n.node_; ++n) { - constructor.create_node(); this->add_node( boost::unordered::detail::func::construct_value( - constructor, *n), n.node_->hash_); + this->node_alloc(), *n), n.node_->hash_); } } - void move_buckets(table& src) { - node_constructor constructor(this->node_alloc()); + void move_buckets(table const& src) { this->create_buckets(this->bucket_count_); for(iterator n = src.begin(); n.node_; ++n) { - constructor.create_node(); this->add_node( boost::unordered::detail::func::construct_value( - constructor, boost::move(*n)), n.node_->hash_); + this->node_alloc(), boost::move(*n)), n.node_->hash_); } } From 078c562b6cf153001427470fcd5b74b48169e9e4 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 05/14] Pull some common code into a function. --- include/boost/unordered/detail/unique.hpp | 32 +++++++++-------------- 1 file changed, 12 insertions(+), 20 deletions(-) diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 1ec71aef..80f21cbb 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -347,21 +347,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, 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_tmp b( + return *this->resize_and_add_node( boost::unordered::detail::func::construct_pair(this->node_alloc(), k), - this->node_alloc()); - - this->reserve_for_insert(this->size_ + 1); - return *add_node(b, key_hash); + key_hash); } #if defined(BOOST_NO_CXX11_RVALUE_REFERENCES) @@ -411,20 +411,12 @@ 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_tmp b( + pos = this->resize_and_add_node( boost::unordered::detail::func::construct_value_generic( this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - this->node_alloc()); - - // 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(b, key_hash), true); + key_hash); + return emplace_return(pos, true); } template From 5490bcfe95b6b7d3b5000575aac8e34808924ab1 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 06/14] Remove node_tmp overload of add_node. --- include/boost/unordered/detail/equivalent.hpp | 13 +++---------- include/boost/unordered/detail/unique.hpp | 15 ++++----------- 2 files changed, 7 insertions(+), 21 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index ea8d34d9..fdd18895 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -381,14 +381,6 @@ namespace boost { namespace unordered { namespace detail { pos->group_prev_ = n; } - inline iterator add_node( - node_tmp& 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, @@ -442,14 +434,15 @@ namespace boost { namespace unordered { namespace detail { // 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_tmp& a) { key_type const& k = this->get_key(a.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) diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 80f21cbb..73852793 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -308,13 +308,6 @@ namespace boost { namespace unordered { namespace detail { // Emplace/Insert - inline iterator add_node( - node_tmp& 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) @@ -351,7 +344,7 @@ namespace boost { namespace unordered { namespace detail { { node_tmp b(n, this->node_alloc()); this->reserve_for_insert(this->size_ + 1); - return this->add_node(b, key_hash); + return this->add_node(b.release(), key_hash); } value_type& operator[](key_type const& k) @@ -437,7 +430,7 @@ namespace boost { namespace unordered { namespace detail { // 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(b, key_hash), true); + return emplace_return(this->add_node(b.release(), key_hash), true); } //////////////////////////////////////////////////////////////////////// @@ -487,7 +480,7 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::insert_size(i, j)); // Nothing after this point can throw. - this->add_node(b, key_hash); + this->add_node(b.release(), key_hash); } } @@ -513,7 +506,7 @@ namespace boost { namespace unordered { namespace detail { // reserve has basic exception safety if the hash function // throws, strong otherwise. this->reserve_for_insert(this->size_ + 1); - this->add_node(b, key_hash); + this->add_node(b.release(), key_hash); } } while(++i != j); } From 3fe46a1769e55301c18c54bbafce9605263ca159 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 07/14] Cleaner emplace_impl in equivalent. --- include/boost/unordered/detail/equivalent.hpp | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index fdd18895..2099ed9b 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -425,8 +425,10 @@ namespace boost { namespace unordered { namespace detail { return iterator(n); } - iterator emplace_impl(node_tmp& a) + iterator emplace_impl(node_pointer n) { + node_tmp a(n, this->node_alloc()); + key_type const& k = this->get_key(a.value()); std::size_t key_hash = this->hash(k); iterator position = this->find_node(key_hash, k); @@ -437,8 +439,9 @@ namespace boost { namespace unordered { namespace detail { return this->add_node(a.release(), key_hash, position); } - void emplace_impl_no_rehash(node_tmp& a) + void emplace_impl_no_rehash(node_pointer n) { + node_tmp a(n, this->node_alloc()); key_type const& k = this->get_key(a.value()); std::size_t key_hash = this->hash(k); iterator position = this->find_node(key_hash, k); @@ -466,12 +469,9 @@ namespace boost { namespace unordered { namespace detail { template iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS) { - node_tmp b( + return iterator(emplace_impl( boost::unordered::detail::func::construct_value_generic( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - this->node_alloc()); - - return iterator(emplace_impl(b)); + this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD))); } //////////////////////////////////////////////////////////////////////// @@ -487,22 +487,18 @@ namespace boost { namespace unordered { namespace detail { std::size_t distance = std::distance(i, j); if(distance == 1) { - node_tmp b( + emplace_impl( boost::unordered::detail::func::construct_value( - this->node_alloc(), *i), - this->node_alloc()); - emplace_impl(b); + this->node_alloc(), *i)); } else { // Only require basic exception safety here this->reserve_for_insert(this->size_ + distance); for (; i != j; ++i) { - node_tmp b( + emplace_impl_no_rehash( boost::unordered::detail::func::construct_value( - this->node_alloc(), *i), - this->node_alloc()); - emplace_impl_no_rehash(b); + this->node_alloc(), *i)); } } } @@ -512,11 +508,9 @@ namespace boost { namespace unordered { namespace detail { boost::unordered::detail::disable_if_forward::type = 0) { for (; i != j; ++i) { - node_tmp b( + emplace_impl( boost::unordered::detail::func::construct_value( - this->node_alloc(), *i), - this->node_alloc()); - emplace_impl(b); + this->node_alloc(), *i)); } } From 6029d1cfd05c990c690ab296b56bd232d0c74e4c Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 08/14] Trim down node_tmp code. --- include/boost/unordered/detail/allocate.hpp | 16 ++-------------- include/boost/unordered/detail/equivalent.hpp | 8 ++------ include/boost/unordered/detail/unique.hpp | 10 ++-------- 3 files changed, 6 insertions(+), 28 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 710a7a5f..da9da16a 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -1145,21 +1145,14 @@ namespace boost { namespace unordered { namespace detail { template struct node_tmp { - 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; - public: - - node_allocator& alloc_; + NodeAlloc& alloc_; node_pointer node_; - explicit node_tmp(node_pointer n, node_allocator& a): + explicit node_tmp(node_pointer n, NodeAlloc& a): alloc_(a), node_(n) { @@ -1167,11 +1160,6 @@ namespace boost { namespace unordered { namespace detail { ~node_tmp(); - value_type const& value() const { - BOOST_ASSERT(node_ ); - return node_->value(); - } - // no throw node_pointer release() { diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 2099ed9b..7e7c757c 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -428,13 +428,9 @@ namespace boost { namespace unordered { namespace detail { iterator emplace_impl(node_pointer n) { node_tmp a(n, this->node_alloc()); - - key_type const& k = this->get_key(a.value()); + 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.release(), key_hash, position); } @@ -442,7 +438,7 @@ namespace boost { namespace unordered { namespace detail { void emplace_impl_no_rehash(node_pointer n) { node_tmp a(n, this->node_alloc()); - key_type const& k = this->get_key(a.value()); + 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); this->add_node(a.release(), key_hash, position); diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 73852793..aabee950 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -421,14 +421,10 @@ namespace boost { namespace unordered { namespace detail { 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.value()); + 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); } - - // 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(b.release(), key_hash), true); } @@ -478,8 +474,6 @@ namespace boost { namespace unordered { namespace detail { 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(b.release(), key_hash); } } @@ -495,7 +489,7 @@ namespace boost { namespace unordered { namespace detail { a.alloc_, a.node_->value_ptr(), *i); node_tmp b(a.release(), a.alloc_); - key_type const& k = this->get_key(b.value()); + 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); From 5a8df0ebe4afcd984940da2fb0b379e932457451 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 09/14] Hopefully a bit more readable. --- include/boost/unordered/detail/unique.hpp | 28 +++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index aabee950..b08a602c 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -404,12 +404,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); - pos = this->resize_and_add_node( - boost::unordered::detail::func::construct_value_generic( - this->node_alloc(), BOOST_UNORDERED_EMPLACE_FORWARD), - key_hash); - return emplace_return(pos, 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 @@ -424,9 +429,14 @@ namespace boost { namespace unordered { namespace detail { 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); } - this->reserve_for_insert(this->size_ + 1); - return emplace_return(this->add_node(b.release(), key_hash), true); + if (pos.node_) { + return emplace_return(pos, false); + } + else { + return emplace_return( + this->resize_and_add_node(b.release(), key_hash), + true); + } } //////////////////////////////////////////////////////////////////////// From ce4b8402993eb21dc0dce5b4f71c8e5de0a6e130 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 10/14] Map/set details types in individual headers. --- include/boost/unordered/detail/equivalent.hpp | 49 --------------- include/boost/unordered/detail/map.hpp | 62 +++++++++++++++++++ include/boost/unordered/detail/set.hpp | 58 +++++++++++++++++ include/boost/unordered/detail/unique.hpp | 48 -------------- include/boost/unordered/unordered_map.hpp | 4 +- include/boost/unordered/unordered_set.hpp | 5 +- 6 files changed, 122 insertions(+), 104 deletions(-) create mode 100644 include/boost/unordered/detail/map.hpp create mode 100644 include/boost/unordered/detail/set.hpp diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 7e7c757c..df3953fb 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -130,55 +130,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 { diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp new file mode 100644 index 00000000..27ad3f47 --- /dev/null +++ b/include/boost/unordered/detail/map.hpp @@ -0,0 +1,62 @@ + +// 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 +#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..861ddcf0 --- /dev/null +++ b/include/boost/unordered/detail/set.hpp @@ -0,0 +1,58 @@ + +// 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 +#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/unique.hpp b/include/boost/unordered/detail/unique.hpp index b08a602c..1a3342bc 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -126,54 +126,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 { 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 From 09717ffca49aedd95f4ca8a4a388db7046d15178 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 11/14] Remove a few unnecessary internal includes. --- include/boost/unordered/detail/equivalent.hpp | 1 - include/boost/unordered/detail/map.hpp | 1 - include/boost/unordered/detail/set.hpp | 1 - include/boost/unordered/detail/table.hpp | 1 - include/boost/unordered/detail/unique.hpp | 1 - 5 files changed, 5 deletions(-) diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index df3953fb..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 { diff --git a/include/boost/unordered/detail/map.hpp b/include/boost/unordered/detail/map.hpp index 27ad3f47..22f8e633 100644 --- a/include/boost/unordered/detail/map.hpp +++ b/include/boost/unordered/detail/map.hpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace boost { namespace unordered { namespace detail { template diff --git a/include/boost/unordered/detail/set.hpp b/include/boost/unordered/detail/set.hpp index 861ddcf0..3ed9dde0 100644 --- a/include/boost/unordered/detail/set.hpp +++ b/include/boost/unordered/detail/set.hpp @@ -6,7 +6,6 @@ #include #include #include -#include namespace boost { namespace unordered { namespace detail { template diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 00c28c3b..3f6d5167 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -13,7 +13,6 @@ #endif #include -#include #include #include #include diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 1a3342bc..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 From ad353c8e3df6fc6ffd791747bdd825462a35a03d Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 12/14] Move some of the includes up into allocate.hpp --- include/boost/unordered/detail/allocate.hpp | 9 +++++++++ include/boost/unordered/detail/buckets.hpp | 8 -------- include/boost/unordered/detail/table.hpp | 3 --- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index da9da16a..5e826718 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -14,6 +14,7 @@ #pragma once #endif +// Some of these includes are required for other detail headers. #include #include #include @@ -25,12 +26,20 @@ #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 diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index d7cc170b..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 { diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 3f6d5167..de7baa57 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -13,9 +13,6 @@ #endif #include -#include -#include -#include #if defined(BOOST_MSVC) #pragma warning(push) From 93a33ba15f56f42e5b3cb7c4ce6d96371c319933 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 13/14] Remove a couple of unneeded includes. --- include/boost/unordered/detail/allocate.hpp | 2 -- 1 file changed, 2 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index 5e826718..d56bcaa0 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include From e92f7d86c1599dde290ac5c70f8ca44bbcd0c96f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 14 Aug 2016 20:55:40 +0100 Subject: [PATCH 14/14] Remove array_constructor. I was using SFINAE for everything because some old compilers had issues. But that's hopefully in the distant past now. --- include/boost/unordered/detail/allocate.hpp | 71 +-------------------- include/boost/unordered/detail/table.hpp | 65 ++++++++++++------- 2 files changed, 43 insertions(+), 93 deletions(-) diff --git a/include/boost/unordered/detail/allocate.hpp b/include/boost/unordered/detail/allocate.hpp index d56bcaa0..a83edad2 100644 --- a/include/boost/unordered/detail/allocate.hpp +++ b/include/boost/unordered/detail/allocate.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -1248,76 +1249,6 @@ namespace boost { namespace unordered { namespace detail { namespace func { } }}}} -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. - - template - struct array_constructor - { - typedef boost::unordered::detail::allocator_traits traits; - typedef typename traits::pointer pointer; - - Allocator& alloc_; - pointer ptr_; - pointer constructed_; - std::size_t length_; - - array_constructor(Allocator& a) - : alloc_(a), ptr_(), constructed_(), length_(0) - { - constructed_ = pointer(); - ptr_ = pointer(); - } - - ~array_constructor() { - if (ptr_) { - for(pointer p = ptr_; p != constructed_; ++p) { - boost::unordered::detail::func::destroy( - boost::addressof(*p)); - } - - traits::deallocate(alloc_, ptr_, length_); - } - } - - template - void construct(V const& v, std::size_t l) - { - 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(); - return p; - } - - private: - - array_constructor(array_constructor const&); - array_constructor& operator=(array_constructor const&); - }; -}}} - #if defined(BOOST_MSVC) #pragma warning(pop) #endif diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index de7baa57..ab4000b4 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -345,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.create_node(); + 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(); }