From 5989e9227cdf79560ea4e01659590f85f971dd3f Mon Sep 17 00:00:00 2001 From: Daniel James Date: Mon, 14 Apr 2008 15:10:26 +0000 Subject: [PATCH] Add the new allocator constructors, use composition instead of inheritance for the implementation and some small fixes. Merged revisions 43922,43962,43966,43971,43981,43995-43996,44042,44046-44048,44057 via svnmerge from https://svn.boost.org/svn/boost/branches/unordered/trunk ........ r43922 | danieljames | 2008-03-29 14:55:59 +0000 (Sat, 29 Mar 2008) | 1 line Fix some typos in the reference documentation. ........ r43962 | danieljames | 2008-03-31 18:29:59 +0100 (Mon, 31 Mar 2008) | 1 line Add a name variable to the release script, so that I can have different release names in different branches. ........ r43966 | danieljames | 2008-03-31 18:43:16 +0100 (Mon, 31 Mar 2008) | 1 line Fix the image directory for standalone docs. ........ r43971 | danieljames | 2008-03-31 19:17:25 +0100 (Mon, 31 Mar 2008) | 1 line Fix the unordered stylesheet. ........ r43981 | danieljames | 2008-04-01 13:31:26 +0100 (Tue, 01 Apr 2008) | 2 lines Cast the pointer in the Visual C++ 6.5 _Charalloc method. ........ r43995 | danieljames | 2008-04-02 12:50:27 +0100 (Wed, 02 Apr 2008) | 1 line Try using the interprocess containers for testing. Compilation is a bit slower but hopefully I'll run into less cross-platform problems. ........ r43996 | danieljames | 2008-04-02 13:25:49 +0100 (Wed, 02 Apr 2008) | 1 line Revert my experiment with the interprocess containers. It didn't work out. ........ r44042 | danieljames | 2008-04-04 20:38:09 +0100 (Fri, 04 Apr 2008) | 1 line Make hash table data a member of hash table, instead of a base. ........ r44046 | danieljames | 2008-04-05 12:38:05 +0100 (Sat, 05 Apr 2008) | 1 line Remove rvalue_ref from Jamfile.v2 - I didn't mean to check it in. ........ r44047 | danieljames | 2008-04-05 12:39:38 +0100 (Sat, 05 Apr 2008) | 1 line New constructors with allocators. ........ r44048 | danieljames | 2008-04-05 12:58:11 +0100 (Sat, 05 Apr 2008) | 1 line Document the new constructors. ........ r44057 | danieljames | 2008-04-05 17:08:23 +0100 (Sat, 05 Apr 2008) | 1 line Fix some bugs in the exception testing code. ........ [SVN r44417] --- doc/Jamfile.v2 | 4 +- doc/ref.xml | 176 +++++++++++------- .../unordered/detail/hash_table_impl.hpp | 157 +++++++++------- include/boost/unordered_map.hpp | 79 +++++--- include/boost/unordered_set.hpp | 80 +++++--- .../exception/constructor_exception_tests.cpp | 10 +- test/exception/copy_exception_tests.cpp | 16 +- test/helpers/allocator.hpp | 2 +- test/helpers/exception_test.hpp | 7 + test/unordered/Jamfile.v2 | 2 +- test/unordered/constructor_tests.cpp | 11 ++ test/unordered/copy_tests.cpp | 24 +++ 12 files changed, 375 insertions(+), 193 deletions(-) diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 83eb3016..a4512c08 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -5,9 +5,11 @@ xml unordered : unordered.qbk ; boostbook standalone : unordered : + admon.graphics.path=images/ + navig.graphics.path=images/ + html.stylesheet=boostbook.css boost.root=../../../.. boost.libraries=../../../libraries.htm - html.stylesheet=../../../../doc/html/boostbook.css chunk.first.sections=1 chunk.section.depth=2 generate.section.toc.level=2 diff --git a/doc/ref.xml b/doc/ref.xml index c3f6d97f..80480ed5 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -2,20 +2,9 @@ Copyright Daniel James 2006-2008 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) ---> - - - - +-->
- - - - An unordered associative container that stores unique values. + + An unordered associative container that stores unique values. - For the normative reference see chapter 23 of + For the normative reference see chapter 23 of the working draft of the C++ standard [n2461]. Template Parameters @@ -48,7 +38,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Pred A binary function object that implements an equivalence relation on values of type Value. - A binary function object that induces an equivalence relation on values of type Key. + A binary function object that induces an equivalence relation on values of type Key. It takes two arguments of type Key and returns a value of type bool. Alloc @@ -191,6 +181,25 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + + Allocator const& + + + Constructs an empty container, using allocator a. + + + + + unordered_set const& + + + Allocator const& + + + Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + @@ -391,7 +400,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -620,17 +629,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. - - - - An unordered associative container that stores values. The same key can be stored multiple times. + + An unordered associative container that stores values. The same key can be stored multiple times. - For the normative reference see chapter 23 of + For the normative reference see chapter 23 of the working draft of the C++ standard [n2461]. Template Parameters @@ -663,7 +668,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Pred A binary function object that implements an equivalence relation on values of type Value. - A binary function object that induces an equivalence relation on values of type Key. + A binary function object that induces an equivalence relation on values of type Key. It takes two arguments of type Key and returns a value of type bool. Alloc @@ -806,6 +811,25 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + + Allocator const& + + + Constructs an empty container, using allocator a. + + + + + unordered_multiset const& + + + Allocator const& + + + Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + @@ -924,7 +948,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - Inserts a range of elements into the container. + Inserts a range of elements into the container. When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. @@ -1005,7 +1029,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -1234,7 +1258,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -1242,17 +1266,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
- -
- - - - An unordered associative container that associates unique keys with another value. + + An unordered associative container that associates unique keys with another value. - For the normative reference see chapter 23 of + For the normative reference see chapter 23 of the working draft of the C++ standard [n2461]. Template Parameters @@ -1290,7 +1306,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Pred A binary function object that implements an equivalence relation on values of type Key. - A binary function object that induces an equivalence relation on values of type Key. + A binary function object that induces an equivalence relation on values of type Key. It takes two arguments of type Key and returns a value of type bool. Alloc @@ -1302,7 +1318,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Key - std::pair<Key const, Value> + std::pair<Key const, Mapped> Mapped @@ -1436,6 +1452,25 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + + Allocator const& + + + Constructs an empty container, using allocator a. + + + + + unordered_map const& + + + Allocator const& + + + Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + @@ -1636,7 +1671,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -1731,7 +1766,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An exception object of type std::out_of_range if no such element is present. - This is not specified in the draft standard, but that is probably an oversight. The issue has been raised in + This is not specified in the draft standard, but that is probably an oversight. The issue has been raised in comp.std.c++. @@ -1902,17 +1937,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. - - - - An unordered associative container that associates keys with another value. The same key can be stored multiple times. + + An unordered associative container that associates keys with another value. The same key can be stored multiple times. - For the normative reference see chapter 23 of + For the normative reference see chapter 23 of the working draft of the C++ standard [n2461]. Template Parameters @@ -1950,7 +1981,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Pred A binary function object that implements an equivalence relation on values of type Key. - A binary function object that induces an equivalence relation on values of type Key. + A binary function object that induces an equivalence relation on values of type Key. It takes two arguments of type Key and returns a value of type bool. Alloc @@ -1962,7 +1993,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Key - std::pair<Key const, Value> + std::pair<Key const, Mapped> Mapped @@ -2096,6 +2127,25 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + + + Allocator const& + + + Constructs an empty container, using allocator a. + + + + + unordered_multimap const& + + + Allocator const& + + + Constructs an container, copying x's contained elements, hash function, predicate, maximum load factor, but using allocator a. + + @@ -2214,7 +2264,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) void - Inserts a range of elements into the container. + Inserts a range of elements into the container. When inserting a single element, if an exception is thrown by an operation other than a call to hasher the function has no effect. @@ -2295,7 +2345,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of key_equal or hasher. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -2526,7 +2576,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the allocators are equal, doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of Hash or Pred. - For a discussion of the behavior when allocators aren't equal see + For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -2534,4 +2584,4 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
-
+
\ No newline at end of file diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 61a0c153..881eb6d8 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -951,7 +951,6 @@ namespace boost { typename Hash, typename Pred, typename Alloc> class BOOST_UNORDERED_TABLE - : public BOOST_UNORDERED_TABLE_DATA { typedef BOOST_UNORDERED_TABLE_DATA data; @@ -1014,6 +1013,8 @@ namespace boost { public: + data data_; + // Constructors // // In the constructors, if anything throws an exception, @@ -1022,11 +1023,11 @@ namespace boost { BOOST_UNORDERED_TABLE(size_type n, hasher const& hf, key_equal const& eq, value_allocator const& a) - : data(n, a), // throws, cleans itself up - func1_(hf, eq), // throws " " - func2_(hf, eq), // throws " " + : func1_(hf, eq), // throws, cleans itself up + func2_(hf, eq), // throws, cleans itself up func_(&BOOST_UNORDERED_TABLE::func1_), // no throw - mlf_(1.0f) // no throw + mlf_(1.0f), // no throw + data_(n, a) // throws, cleans itself up { calculate_max_load(); // no throw } @@ -1068,31 +1069,49 @@ namespace boost { BOOST_UNORDERED_TABLE(I i, I j, size_type n, hasher const& hf, key_equal const& eq, value_allocator const& a) - : data(initial_size(i, j, n), a), // throws, cleans itself up - func1_(hf, eq), // throws " " - func2_(hf, eq), // throws " " + : func1_(hf, eq), // throws, cleans itself up + func2_(hf, eq), // throws, cleans itself up func_(&BOOST_UNORDERED_TABLE::func1_), // no throw - mlf_(1.0f) // no throw + mlf_(1.0f), // no throw + data_(initial_size(i, j, n), a) // throws, cleans itself up { calculate_max_load(); // no throw // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean up. insert(i, j); } + // Copy Construct BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE const& x) - : data(x, x.min_buckets_for_size(x.size())), // throws - func1_(x.current_functions()), // throws + : func1_(x.current_functions()), // throws func2_(x.current_functions()), // throws func_(&BOOST_UNORDERED_TABLE::func1_), // no throw - mlf_(x.mlf_) // no throw + mlf_(x.mlf_), // no throw + data_(x.data_, x.min_buckets_for_size(x.size())) // throws { calculate_max_load(); // no throw // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean // up. - copy_buckets(x, *this, current_functions()); + copy_buckets(x.data_, data_, current_functions()); + } + + // Copy Construct with allocator + + BOOST_UNORDERED_TABLE(BOOST_UNORDERED_TABLE const& x, + value_allocator const& a) + : func1_(x.current_functions()), // throws + func2_(x.current_functions()), // throws + func_(&BOOST_UNORDERED_TABLE::func1_), // no throw + mlf_(x.mlf_), // no throw + data_(x.min_buckets_for_size(x.size()), a) + { + calculate_max_load(); // no throw + + // This can throw, but BOOST_UNORDERED_TABLE_DATA's destructor will clean + // up. + copy_buckets(x.data_, data_, current_functions()); } // Assign @@ -1106,12 +1125,12 @@ namespace boost { { if(this != &x) { - this->clear(); // no throw + data_.clear(); // no throw func_ = copy_functions(x); // throws, strong mlf_ = x.mlf_; // no throw calculate_max_load(); // no throw reserve(x.size()); // throws - copy_buckets(x, *this, current_functions()); // throws + copy_buckets(x.data_, data_, current_functions()); // throws } return *this; @@ -1138,22 +1157,22 @@ namespace boost { functions_ptr new_func_this = copy_functions(x); // throws functions_ptr new_func_that = x.copy_functions(*this); // throws - if(this->allocators_ == x.allocators_) { - this->data::swap(x); // no throw + if(data_.allocators_ == x.data_.allocators_) { + data_.swap(x.data_); // no throw } else { // Create new buckets in separate HASH_TABLE_DATA objects // which will clean up if anything throws an exception. // (all can throw, but with no effect as these are new objects). - data new_this(*this, x.min_buckets_for_size(x.size_)); - copy_buckets(x, new_this, this->*new_func_this); + data new_this(data_, x.min_buckets_for_size(x.data_.size_)); + copy_buckets(x.data_, new_this, this->*new_func_this); - data new_that(x, min_buckets_for_size(this->size_)); - x.copy_buckets(*this, new_that, x.*new_func_that); + data new_that(x.data_, min_buckets_for_size(data_.size_)); + x.copy_buckets(data_, new_that, x.*new_func_that); // Start updating the data here, no throw from now on. - this->data::swap(new_this); - x.data::swap(new_that); + data_.swap(new_this); + x.data_.swap(new_that); } // We've made it, the rest is no throw. @@ -1196,7 +1215,7 @@ namespace boost { // no throw value_allocator get_allocator() const { - return this->allocators_.value_alloc_; + return data_.allocators_.value_alloc_; } // no throw @@ -1214,13 +1233,13 @@ namespace boost { // no throw size_type size() const { - return this->size_; + return data_.size_; } // no throw bool empty() const { - return this->size_ == 0; + return data_.size_ == 0; } // no throw @@ -1237,27 +1256,27 @@ namespace boost { size_type bucket(key_type const& k) const { // hash_function can throw: - return hash_function()(k) % this->bucket_count_; + return hash_function()(k) % data_.bucket_count_; } // strong safety bucket_ptr get_bucket(key_type const& k) const { - return this->buckets_ + static_cast(bucket(k)); + return data_.buckets_ + static_cast(bucket(k)); } // no throw size_type bucket_count() const { - return this->bucket_count_; + return data_.bucket_count_; } // no throw size_type max_bucket_count() const { // -1 to account for the end marker. - return prev_prime(this->allocators_.bucket_alloc_.max_size() - 1); + return prev_prime(data_.allocators_.bucket_alloc_.max_size() - 1); } private: @@ -1286,7 +1305,7 @@ namespace boost { // From 6.3.1/13: // Only resize when size >= mlf_ * count max_load_ = double_to_size_t(ceil( - (double) mlf_ * this->bucket_count_)); + (double) mlf_ * data_.bucket_count_)); } // basic exception safety @@ -1338,9 +1357,9 @@ namespace boost { // no throw float load_factor() const { - BOOST_ASSERT(this->bucket_count_ != 0); - return static_cast(this->size_) - / static_cast(this->bucket_count_); + BOOST_ASSERT(data_.bucket_count_ != 0); + return static_cast(data_.size_) + / static_cast(data_.bucket_count_); } private: @@ -1393,10 +1412,10 @@ namespace boost { if (n == bucket_count()) // no throw return; - data new_buckets(*this, n); // throws, seperate - move_buckets(*this, new_buckets, hash_function()); + data new_buckets(data_, n); // throws, seperate + move_buckets(data_, new_buckets, hash_function()); // basic/no throw - new_buckets.swap(*this); // no throw + new_buckets.swap(data_); // no throw calculate_max_load(); // no throw } @@ -1471,18 +1490,18 @@ namespace boost { { key_type const& k = extract_key(v); size_type hash_value = hash_function()(k); - bucket_ptr bucket = this->bucket_from_hash(hash_value); + bucket_ptr bucket = data_.bucket_from_hash(hash_value); link_ptr position = find_iterator(bucket, k); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). - node_constructor a(this->allocators_); + node_constructor a(data_.allocators_); a.construct(v); // reserve has basic exception safety if the hash function // throws, strong otherwise. if(reserve(size() + 1)) - bucket = this->bucket_from_hash(hash_value); + bucket = data_.bucket_from_hash(hash_value); // Nothing after the point can throw. @@ -1491,9 +1510,9 @@ namespace boost { // I'm relying on link_ptr not being invalidated by // the rehash here. if(BOOST_UNORDERED_BORLAND_BOOL(position)) - this->link_node(n, position); + data_.link_node(n, position); else - this->link_node_in_bucket(n, bucket); + data_.link_node_in_bucket(n, bucket); return iterator_base(bucket, n); } @@ -1505,7 +1524,7 @@ namespace boost { iterator_base insert(iterator_base const& it, value_type const& v) { // equal can throw, but with no effects - if (it == this->end() || !equal(extract_key(v), *it)) { + if (it == data_.end() || !equal(extract_key(v), *it)) { // Use the standard insert if the iterator doesn't point // to a matching key. return insert(v); @@ -1515,12 +1534,12 @@ namespace boost { // will be inserted at the end of the group. link_ptr start(it.node_); - while(this->prev_in_group(start)->next_ == start) - start = this->prev_in_group(start); + while(data_.prev_in_group(start)->next_ == start) + start = data_.prev_in_group(start); // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). - node_constructor a(this->allocators_); + node_constructor a(data_.allocators_); a.construct(v); // reserve has basic exception safety if the hash function @@ -1531,7 +1550,7 @@ namespace boost { // Nothing after this point can throw link_ptr n = a.release(); - this->link_node(n, start); + data_.link_node(n, start); return iterator_base(base, n); } @@ -1553,7 +1572,7 @@ namespace boost { else { // Only require basic exception safety here reserve_extra(size() + distance); - node_constructor a(this->allocators_); + node_constructor a(data_.allocators_); for (; i != j; ++i) { a.construct(*i); @@ -1563,9 +1582,9 @@ namespace boost { link_ptr position = find_iterator(bucket, k); if(BOOST_UNORDERED_BORLAND_BOOL(position)) - this->link_node(a.release(), position); + data_.link_node(a.release(), position); else - this->link_node_in_bucket(a.release(), bucket); + data_.link_node_in_bucket(a.release(), bucket); } } } @@ -1602,7 +1621,7 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; size_type hash_value = hash_function()(k); - bucket_ptr bucket = this->bucket_from_hash(hash_value); + bucket_ptr bucket = data_.bucket_from_hash(hash_value); link_ptr pos = find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) @@ -1613,18 +1632,18 @@ namespace boost { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). - node_constructor a(this->allocators_); + node_constructor a(data_.allocators_); a.construct(value_type(k, mapped_type())); // reserve has basic exception safety if the hash function // throws, strong otherwise. if(reserve(size() + 1)) - bucket = this->bucket_from_hash(hash_value); + bucket = data_.bucket_from_hash(hash_value); // Nothing after this point can throw. link_ptr n = a.release(); - this->link_node_in_bucket(n, bucket); + data_.link_node_in_bucket(n, bucket); return data::get_value(n); } @@ -1639,7 +1658,7 @@ namespace boost { // No side effects in this initial code key_type const& k = extract_key(v); size_type hash_value = hash_function()(k); - bucket_ptr bucket = this->bucket_from_hash(hash_value); + bucket_ptr bucket = data_.bucket_from_hash(hash_value); link_ptr pos = find_iterator(bucket, k); if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { @@ -1653,18 +1672,18 @@ namespace boost { // Create the node before rehashing in case it throws an // exception (need strong safety in such a case). - node_constructor a(this->allocators_); + node_constructor a(data_.allocators_); a.construct(v); // reserve has basic exception safety if the hash function // throws, strong otherwise. if(reserve(size() + 1)) - bucket = this->bucket_from_hash(hash_value); + bucket = data_.bucket_from_hash(hash_value); // Nothing after this point can throw. link_ptr n = a.release(); - this->link_node_in_bucket(n, bucket); + data_.link_node_in_bucket(n, bucket); return std::pair( iterator_base(bucket, n), true); @@ -1677,7 +1696,7 @@ namespace boost { // strong otherwise iterator_base insert(iterator_base const& it, value_type const& v) { - if(it != this->end() && equal(extract_key(v), *it)) + if(it != data_.end() && equal(extract_key(v), *it)) return it; else return insert(v).first; @@ -1710,12 +1729,12 @@ namespace boost { template void insert(InputIterator i, InputIterator j) { - node_constructor a(this->allocators_); + node_constructor a(data_.allocators_); for (; i != j; ++i) { // No side effects in this initial code size_type hash_value = hash_function()(extract_key(*i)); - bucket_ptr bucket = this->bucket_from_hash(hash_value); + bucket_ptr bucket = data_.bucket_from_hash(hash_value); link_ptr pos = find_iterator(bucket, extract_key(*i)); if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { @@ -1730,11 +1749,11 @@ namespace boost { // throws, strong otherwise. if(size() + 1 >= max_load_) { reserve(size() + insert_size(i, j)); - bucket = this->bucket_from_hash(hash_value); + bucket = data_.bucket_from_hash(hash_value); } // Nothing after this point can throw. - this->link_node_in_bucket(a.release(), bucket); + data_.link_node_in_bucket(a.release(), bucket); } } } @@ -1746,7 +1765,7 @@ namespace boost { // no throw iterator_base erase(iterator_base const& r) { - return this->data::erase(r); + return data_.data::erase(r); } // strong exception safety @@ -1757,13 +1776,13 @@ namespace boost { link_ptr* it = find_for_erase(bucket, k); // No throw. - return *it ? this->erase_group(it, bucket) : 0; + return *it ? data_.erase_group(it, bucket) : 0; } // no throw iterator_base erase(iterator_base const& r1, iterator_base const& r2) { - return this->data::erase(r1, r2); + return data_.data::erase(r1, r2); } // count @@ -1786,7 +1805,7 @@ namespace boost { if (BOOST_UNORDERED_BORLAND_BOOL(it)) return iterator_base(bucket, it); else - return this->end(); + return data_.end(); } value_type& at(key_type const& k) const @@ -1815,7 +1834,7 @@ namespace boost { } else { return std::pair( - this->end(), this->end()); + data_.end(), data_.end()); } } @@ -1837,7 +1856,7 @@ namespace boost { link_ptr find_iterator(bucket_ptr bucket, key_type const& k) const { - link_ptr it = this->begin(bucket); + link_ptr it = data_.begin(bucket); while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) it = data::next_group(it); diff --git a/include/boost/unordered_map.hpp b/include/boost/unordered_map.hpp index 1345bca1..ce800aaf 100644 --- a/include/boost/unordered_map.hpp +++ b/include/boost/unordered_map.hpp @@ -71,6 +71,18 @@ namespace boost { } + // TODO: Should this be explicit? + unordered_map(allocator_type const& a) + : base(boost::unordered_detail::default_initial_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_map(unordered_map const& other, allocator_type const& a) + : base(other.base, a) + { + } + template unordered_map(InputIterator f, InputIterator l) : base(f, l, boost::unordered_detail::default_initial_bucket_count, @@ -124,32 +136,32 @@ namespace boost iterator begin() { - return iterator(base.begin()); + return iterator(base.data_.begin()); } const_iterator begin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } iterator end() { - return iterator(base.end()); + return iterator(base.data_.end()); } const_iterator end() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } const_iterator cbegin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } const_iterator cend() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } // modifiers @@ -188,7 +200,7 @@ namespace boost void clear() { - base.clear(); + base.data_.clear(); } void swap(unordered_map& other) @@ -268,7 +280,7 @@ namespace boost size_type bucket_size(size_type n) const { - return base.bucket_size(n); + return base.data_.bucket_size(n); } size_type bucket(const key_type& k) const @@ -278,32 +290,32 @@ namespace boost local_iterator begin(size_type n) { - return local_iterator(base.begin(n)); + return local_iterator(base.data_.begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } local_iterator end(size_type n) { - return local_iterator(base.end(n)); + return local_iterator(base.data_.end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } const_local_iterator cend(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } // hash policy @@ -384,6 +396,17 @@ namespace boost { } + unordered_multimap(allocator_type const& a) + : base(boost::unordered_detail::default_initial_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_multimap(unordered_multimap const& other, allocator_type const& a) + : base(other.base, a) + { + } + template unordered_multimap(InputIterator f, InputIterator l) : base(f, l, boost::unordered_detail::default_initial_bucket_count, @@ -437,32 +460,32 @@ namespace boost iterator begin() { - return iterator(base.begin()); + return iterator(base.data_.begin()); } const_iterator begin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } iterator end() { - return iterator(base.end()); + return iterator(base.data_.end()); } const_iterator end() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } const_iterator cbegin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } const_iterator cend() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } // modifiers @@ -500,7 +523,7 @@ namespace boost void clear() { - base.clear(); + base.data_.clear(); } void swap(unordered_multimap& other) @@ -565,7 +588,7 @@ namespace boost size_type bucket_size(size_type n) const { - return base.bucket_size(n); + return base.data_.bucket_size(n); } size_type bucket(const key_type& k) const @@ -575,32 +598,32 @@ namespace boost local_iterator begin(size_type n) { - return local_iterator(base.begin(n)); + return local_iterator(base.data_.begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } local_iterator end(size_type n) { - return local_iterator(base.end(n)); + return local_iterator(base.data_.end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } const_local_iterator cend(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } // hash policy diff --git a/include/boost/unordered_set.hpp b/include/boost/unordered_set.hpp index 318d21ee..f331a978 100644 --- a/include/boost/unordered_set.hpp +++ b/include/boost/unordered_set.hpp @@ -69,6 +69,18 @@ namespace boost { } + // TODO: Should this be explicit? + unordered_set(allocator_type const& a) + : base(boost::unordered_detail::default_initial_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_set(unordered_set const& other, allocator_type const& a) + : base(other.base, a) + { + } + template unordered_set(InputIterator f, InputIterator l) : base(f, l, boost::unordered_detail::default_initial_bucket_count, @@ -121,32 +133,32 @@ namespace boost iterator begin() { - return iterator(base.begin()); + return iterator(base.data_.begin()); } const_iterator begin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } iterator end() { - return iterator(base.end()); + return iterator(base.data_.end()); } const_iterator end() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } const_iterator cbegin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } const_iterator cend() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } // modifiers @@ -185,7 +197,7 @@ namespace boost void clear() { - base.clear(); + base.data_.clear(); } void swap(unordered_set& other) @@ -238,7 +250,7 @@ namespace boost size_type bucket_size(size_type n) const { - return base.bucket_size(n); + return base.data_.bucket_size(n); } size_type bucket(const key_type& k) const @@ -248,32 +260,32 @@ namespace boost local_iterator begin(size_type n) { - return local_iterator(base.begin(n)); + return local_iterator(base.data_.begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } local_iterator end(size_type n) { - return local_iterator(base.end(n)); + return local_iterator(base.data_.end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } const_local_iterator cend(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } // hash policy @@ -352,6 +364,18 @@ namespace boost { } + // TODO: Should this be explicit? + unordered_multiset(allocator_type const& a) + : base(boost::unordered_detail::default_initial_bucket_count, + hasher(), key_equal(), a) + { + } + + unordered_multiset(unordered_multiset const& other, allocator_type const& a) + : base(other.base, a) + { + } + template unordered_multiset(InputIterator f, InputIterator l) : base(f, l, boost::unordered_detail::default_initial_bucket_count, @@ -404,32 +428,32 @@ namespace boost iterator begin() { - return iterator(base.begin()); + return iterator(base.data_.begin()); } const_iterator begin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } iterator end() { - return iterator(base.end()); + return iterator(base.data_.end()); } const_iterator end() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } const_iterator cbegin() const { - return const_iterator(base.begin()); + return const_iterator(base.data_.begin()); } const_iterator cend() const { - return const_iterator(base.end()); + return const_iterator(base.data_.end()); } // modifiers @@ -467,7 +491,7 @@ namespace boost void clear() { - base.clear(); + base.data_.clear(); } void swap(unordered_multiset& other) @@ -520,7 +544,7 @@ namespace boost size_type bucket_size(size_type n) const { - return base.bucket_size(n); + return base.data_.bucket_size(n); } size_type bucket(const key_type& k) const @@ -530,32 +554,32 @@ namespace boost local_iterator begin(size_type n) { - return local_iterator(base.begin(n)); + return local_iterator(base.data_.begin(n)); } const_local_iterator begin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } local_iterator end(size_type n) { - return local_iterator(base.end(n)); + return local_iterator(base.data_.end(n)); } const_local_iterator end(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } const_local_iterator cbegin(size_type n) const { - return const_local_iterator(base.begin(n)); + return const_local_iterator(base.data_.begin(n)); } const_local_iterator cend(size_type n) const { - return const_local_iterator(base.end(n)); + return const_local_iterator(base.data_.end(n)); } // hash policy diff --git a/test/exception/constructor_exception_tests.cpp b/test/exception/constructor_exception_tests.cpp index 8ad07008..c28fba37 100644 --- a/test/exception/constructor_exception_tests.cpp +++ b/test/exception/constructor_exception_tests.cpp @@ -57,6 +57,14 @@ struct construct_test5 : public objects, test::exception_base } }; +template +struct construct_test6 : public objects, test::exception_base +{ + void run() const { + T x(allocator); + } +}; + template struct range : public test::exception_base { @@ -123,7 +131,7 @@ struct input_range_construct_test : public range, objects }; RUN_EXCEPTION_TESTS( - (construct_test1)(construct_test2)(construct_test3)(construct_test4)(construct_test5) + (construct_test1)(construct_test2)(construct_test3)(construct_test4)(construct_test5)(construct_test6) (range_construct_test1)(range_construct_test2)(range_construct_test3)(range_construct_test4)(range_construct_test5) (input_range_construct_test), CONTAINER_SEQ) diff --git a/test/exception/copy_exception_tests.cpp b/test/exception/copy_exception_tests.cpp index 44d248c8..e975231c 100644 --- a/test/exception/copy_exception_tests.cpp +++ b/test/exception/copy_exception_tests.cpp @@ -44,6 +44,20 @@ struct copy_test3 : public test::exception_base } }; +template +struct copy_with_allocator_test : public test::exception_base +{ + test::random_values values; + T x; + test::exception::allocator allocator; + + copy_with_allocator_test() : values(100), x(values.begin(), values.end()) {} + + void run() const { + T y(x, allocator); + } +}; + RUN_EXCEPTION_TESTS( - (copy_test1)(copy_test2)(copy_test3), + (copy_test1)(copy_test2)(copy_test3)(copy_with_allocator_test), CONTAINER_SEQ) diff --git a/test/helpers/allocator.hpp b/test/helpers/allocator.hpp index 2345967e..676f24b0 100644 --- a/test/helpers/allocator.hpp +++ b/test/helpers/allocator.hpp @@ -70,7 +70,7 @@ namespace test using namespace std; T* ptr = static_cast(malloc(n * sizeof(char))); if(!ptr) throw std::bad_alloc(); - return ptr; + return (char*) ptr; } #endif }; diff --git a/test/helpers/exception_test.hpp b/test/helpers/exception_test.hpp index d919f04b..13937de6 100644 --- a/test/helpers/exception_test.hpp +++ b/test/helpers/exception_test.hpp @@ -163,6 +163,7 @@ namespace test { test_runner(Test const& t) : test_(t) {} void operator()() const { DISABLE_EXCEPTIONS; + test::scope = ""; BOOST_DEDUCED_TYPENAME Test::data_type x(test_.init()); BOOST_DEDUCED_TYPENAME Test::strong_type strong; strong.store(x); @@ -223,9 +224,15 @@ namespace test { success = true; } catch(test_failure) { + BOOST_ERROR("test_failure caught."); break; } + catch(test_exception) { + continue; + } catch(...) { + BOOST_ERROR("Unexpected exception."); + break; } } while(!success); } diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 63e2c84e..7eff133a 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -9,7 +9,7 @@ project unordered-test/unordered : requirements intel-linux:"-strict_ansi -cxxlib-icc" gcc:-Wsign-promo - msvc:/W4 + #msvc:/W4 ; test-suite unordered diff --git a/test/unordered/constructor_tests.cpp b/test/unordered/constructor_tests.cpp index 36c21e66..8a4bab7c 100644 --- a/test/unordered/constructor_tests.cpp +++ b/test/unordered/constructor_tests.cpp @@ -136,6 +136,17 @@ void constructor_tests1(T*, test::random_generator generator = test::default_gen test::check_container(x, v); test::check_equivalent_keys(x); } + + std::cerr<<"Construct 11\n"; + { + test::random_values v(1000, generator); + T x(al); + BOOST_TEST(x.empty()); + BOOST_TEST(test::equivalent(x.hash_function(), hf)); + BOOST_TEST(test::equivalent(x.key_eq(), eq)); + BOOST_TEST(test::equivalent(x.get_allocator(), al)); + test::check_equivalent_keys(x); + } } template diff --git a/test/unordered/copy_tests.cpp b/test/unordered/copy_tests.cpp index 8607257c..12f8dbf0 100644 --- a/test/unordered/copy_tests.cpp +++ b/test/unordered/copy_tests.cpp @@ -70,6 +70,7 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes BOOST_DEDUCED_TYPENAME T::hasher hf(1); BOOST_DEDUCED_TYPENAME T::key_equal eq(1); BOOST_DEDUCED_TYPENAME T::allocator_type al(1); + BOOST_DEDUCED_TYPENAME T::allocator_type al2(2); { T x(10000, hf, eq, al); @@ -82,6 +83,17 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes test::check_equivalent_keys(y); } + { + T x(1000, hf, eq, al); + T y(x, al2); + BOOST_TEST(y.empty()); + BOOST_TEST(test::equivalent(y.hash_function(), hf)); + BOOST_TEST(test::equivalent(y.key_eq(), eq)); + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); + BOOST_TEST(x.max_load_factor() == y.max_load_factor()); + test::check_equivalent_keys(y); + } + { test::random_values v(1000); @@ -90,6 +102,18 @@ void copy_construct_tests2(T* ptr, test::random_generator const& generator = tes test::unordered_equivalence_tester equivalent(x); equivalent(y); test::check_equivalent_keys(y); + BOOST_TEST(test::equivalent(y.get_allocator(), al)); + } + + { + test::random_values v(500); + + T x(v.begin(), v.end(), 0, hf, eq, al); + T y(x, al2); + test::unordered_equivalence_tester equivalent(x); + equivalent(y); + test::check_equivalent_keys(y); + BOOST_TEST(test::equivalent(y.get_allocator(), al2)); } }