diff --git a/doc/Jamfile.v2 b/doc/Jamfile.v2 index 95911f47..5468b827 100644 --- a/doc/Jamfile.v2 +++ b/doc/Jamfile.v2 @@ -1,17 +1,15 @@ +project boost/doc ; +import boostbook : boostbook ; -# Copyright 2005 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) +boostbook doc : src/boost.xml + : -using quickbook ; + ## Build the various generated docs (Doxygen and QuickBook)... -xml unordered : unordered.qbk ; -boostbook standalone : unordered : - 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 - toc.section.depth=1 - toc.max.depth=1 ; + ../libs/unordered/doc//unordered + ../libs/unordered/doc//unordered + ../libs/functional/hash/doc//hash + ../libs/functional/hash/doc//hash + + boost.libraries=../../libs/libraries.htm + ; diff --git a/doc/buckets.qbk b/doc/buckets.qbk index 57cabdc0..e906643a 100644 --- a/doc/buckets.qbk +++ b/doc/buckets.qbk @@ -20,17 +20,16 @@ value of type `std::size_t`. `std::size_t` has a much greater range of values then the number of buckets, so that container applies another transformation to that value to choose a bucket to place the element in. -If at a later date the container wants to find an element in the container it -just has to apply the same process to the element's key to discover which -bucket it is in. If the hash function has worked well the elements will be -evenly distributed amongst the buckets so it will only have to examine a small -number of elements. +Retreiving the elements for a given key is simple. The same process is applied +to the key to find the correct bucket. Then the key is compared with the +elements in the bucket to find any elements that match. If the hash +function has worked well the elements will be evenly distributed amongst the +buckets so only a small number of elements will need to be examined. You can see in the diagram that `A` & `D` have been placed in the same bucket. -This means that when looking for these elements, of another element that would -be placed in the same bucket, up to 2 comparison have to be made, making -searching slower. This is known as a collision. To keep things fast we try to -keep these to a minimum. +When looking for elements in this bucket up to 2 comparisons are made, making +the search slower. This is known as a collision. To keep things fast we try to +keep collisions to a minimum. [table Methods for Accessing Buckets [[Method] [Description]] @@ -57,6 +56,8 @@ keep these to a minimum. local_iterator end(size_type n); const_local_iterator begin(size_type n) const; const_local_iterator end(size_type n) const; + const_local_iterator cbegin(size_type n) const; + const_local_iterator cend(size_type n) const; ``] [Return begin and end iterators for bucket `n`.] ] @@ -65,42 +66,31 @@ keep these to a minimum. [h2 Controlling the number of buckets] As more elements are added to an unordered associative container, the number -of elements in the buckets will increase causing performance to get worse. To -combat this the containers increase the bucket count as elements are inserted. +of elements in the buckets will increase causing performance to degrade. +To combat this the containers increase the bucket count as elements are inserted. +You can also tell the container to change the bucket count (if required) by +calling `rehash`. -The standard gives you two methods to influence the bucket count. First you can -specify the minimum number of buckets in the constructor, and later, by calling -`rehash`. +The standard leaves a lot of freedom to the implementor to decide how the +number of buckets are chosen, but it does make some requirements based on the +container's 'load factor', the average number of elements per bucket. +Containers also have a 'maximum load factor' which they should try to keep the +load factor below. -The other method is the `max_load_factor` member function. The 'load factor' -is the average number of elements per bucket, `max_load_factor` can be used -to give a /hint/ of a value that the load factor should be kept below. The -draft standard doesn't actually require the container to pay much attention -to this value. The only time the load factor is /required/ to be less than the -maximum is following a call to `rehash`. But most implementations will probably -try to keep the number of elements below the max load factor, and set the -maximum load factor something the same or near to your hint - unless your hint -is unreasonably small. +You can't control the bucket count directly but there are two ways to +influence it: -It is not specified anywhere how member functions other than `rehash` affect -the bucket count, although `insert` is only allowed to invalidate iterators -when the insertion causes the load factor to reach the maximum. Which will -typically mean that insert will only change the number of buckets when an -insert causes this. +* Specify the minimum number of buckets when constructing a container or + when calling `rehash`. +* Suggest a maximum load factor by calling `max_load_factor`. -In a similar manner to using `reserve` for `vector`s, it can be a good idea -to call `rehash` before inserting a large number of elements. This will get -the expensive rehashing out of the way and let you store iterators, safe in -the knowledge that they won't be invalidated. If you are inserting `n` -elements into container `x`, you could first call: - - x.rehash((x.size() + n) / x.max_load_factor() + 1); - -[blurb Note: `rehash`'s argument is the number of buckets, not the number of -elements, which is why the new size is divided by the maximum load factor. The -+ 1 guarantees there is no invalidation; without it, reallocation could occur -if the number of bucket exactly divides the target size, since the container is -allowed to rehash when the load factor is equal to the maximum load factor.] +`max_load_factor` doesn't let you set the maximum load factor yourself, it just +lets you give a /hint/. And even then, the draft standard doesn't actually +require the container to pay much attention to this value. The only time the +load factor is /required/ to be less than the maximum is following a call to +`rehash`. But most implementations will try to keep the number of elements +below the max load factor, and set the maximum load factor to be the same as +or close to the hint - unless your hint is unreasonably small or large. [table Methods for Controlling Bucket Size [[Method] [Description]] @@ -125,4 +115,24 @@ allowed to rehash when the load factor is equal to the maximum load factor.] ] +It is not specified how member functions other than `rehash` affect +the bucket count, although `insert` is only allowed to invalidate iterators +when the insertion causes the load factor to be greater than or equal to the +maximum load factor. For most implementations this means that insert will only +change the number of buckets when this happens. + +In a similar manner to using `reserve` for `vector`s, it can be a good idea +to call `rehash` before inserting a large number of elements. This will get +the expensive rehashing out of the way and let you store iterators, safe in +the knowledge that they won't be invalidated. If you are inserting `n` +elements into container `x`, you could first call: + + x.rehash((x.size() + n) / x.max_load_factor() + 1); + +[blurb Note: `rehash`'s argument is the minimum number of buckets, not the +number of elements, which is why the new size is divided by the maximum load factor. The +`+ 1` guarantees there is no invalidation; without it, reallocation could occur +if the number of bucket exactly divides the target size, since the container is +allowed to rehash when the load factor is equal to the maximum load factor.] + [endsect] diff --git a/doc/intro.qbk b/doc/intro.qbk index 5bdd2fbd..bb9fa305 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -28,11 +28,12 @@ with some care, can be avoided. Also, the existing containers require a 'less than' comparison object to order their elements. For some data types this is impossible to implement -or isn't practical. For a hash table you need an equality function +or isn't practical. In contrast, a hash table only needs an equality function and a hash function for the key. -So the __tr1__ introduced the unordered associative containers, which are -implemented using hash tables, and they have now been added to the __draft__. +With this in mind, the __tr1__ introduced the unordered associative containers, +which are implemented using hash tables, and they have now been added to the +__draft__. This library supplies an almost complete implementation of the specification in the __draft__, (it doesn't support `emplace` yet, see the [link @@ -110,6 +111,7 @@ can be in any order. For example, it might be: three,3 missing,0 -There are other differences, which will be detailed later. +There are other differences, which are listed in the +[link unordered.comparison Comparison with Associative Containers] section. [endsect] diff --git a/doc/ref.xml b/doc/ref.xml index 01a8d2b1..bdecfd8d 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -1718,7 +1718,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) A reference to x.second where x is the (unique) element whose key is equivalent to k. - An exception object of type out_of_range if no such element is present. + 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 diff --git a/doc/src/boost.xml b/doc/src/boost.xml index 457d5047..b0a7afcd 100644 --- a/doc/src/boost.xml +++ b/doc/src/boost.xml @@ -5,5 +5,5 @@ The Boost C++ Unordered Containers Library Documentation - + diff --git a/include/boost/unordered/detail/hash_table.hpp b/include/boost/unordered/detail/hash_table.hpp index 355afedf..9f9e4e49 100644 --- a/include/boost/unordered/detail/hash_table.hpp +++ b/include/boost/unordered/detail/hash_table.hpp @@ -33,15 +33,15 @@ #include #if BOOST_WORKAROUND(__BORLANDC__, <= 0x0551) -#define BOOST_HASH_BORLAND_BOOL(x) (bool)(x) +#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x) #else -#define BOOST_HASH_BORLAND_BOOL(x) x +#define BOOST_UNORDERED_BORLAND_BOOL(x) x #endif #if BOOST_WORKAROUND(BOOST_MSVC, < 1300) -#define BOOST_HASH_MSVC_RESET_PTR(x) unordered_detail::reset(x) +#define BOOST_UNORDERED_MSVC_RESET_PTR(x) unordered_detail::reset(x) #else -#define BOOST_HASH_MSVC_RESET_PTR(x) +#define BOOST_UNORDERED_MSVC_RESET_PTR(x) #endif namespace boost { @@ -112,13 +112,13 @@ namespace boost { } } -#define BOOST_UNORDERED_HASH_EQUIVALENT 1 +#define BOOST_UNORDERED_EQUIVALENT_KEYS 1 #include -#undef BOOST_UNORDERED_HASH_EQUIVALENT +#undef BOOST_UNORDERED_EQUIVALENT_KEYS -#define BOOST_UNORDERED_HASH_EQUIVALENT 0 +#define BOOST_UNORDERED_EQUIVALENT_KEYS 0 #include -#undef BOOST_UNORDERED_HASH_EQUIVALENT +#undef BOOST_UNORDERED_EQUIVALENT_KEYS namespace boost { namespace unordered_detail { @@ -179,7 +179,7 @@ namespace boost { } // namespace boost::unordered_detail } // namespace boost -#undef BOOST_HASH_BORLAND_BOOL -#undef BOOST_HASH_MSVC_RESET_PTR +#undef BOOST_UNORDERED_BORLAND_BOOL +#undef BOOST_UNORDERED_MSVC_RESET_PTR #endif // BOOST_UNORDERED_DETAIL_HASH_TABLE_HPP_INCLUDED diff --git a/include/boost/unordered/detail/hash_table_impl.hpp b/include/boost/unordered/detail/hash_table_impl.hpp index 00002cd0..958581a2 100644 --- a/include/boost/unordered/detail/hash_table_impl.hpp +++ b/include/boost/unordered/detail/hash_table_impl.hpp @@ -4,7 +4,7 @@ // 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) -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS #define BOOST_UNORDERED_TABLE hash_table_equivalent_keys #define BOOST_UNORDERED_TABLE_DATA hash_table_data_equivalent_keys #define BOOST_UNORDERED_ITERATOR hash_iterator_equivalent_keys @@ -32,10 +32,13 @@ namespace boost { class BOOST_UNORDERED_TABLE_DATA { public: + typedef BOOST_UNORDERED_TABLE_DATA data; + struct node_base; struct node; struct bucket; typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; typedef Alloc value_allocator; @@ -64,7 +67,7 @@ namespace boost { // It's a sort of strict typedef. struct link_ptr { - link_ptr() : ptr_() { BOOST_HASH_MSVC_RESET_PTR(ptr_); } + link_ptr() : ptr_() { BOOST_UNORDERED_MSVC_RESET_PTR(ptr_); } explicit link_ptr(bucket_ptr p) : ptr_(p) {} bucket_reference operator*() const { return *ptr_; } bucket* operator->() const { return &*ptr_; } @@ -88,7 +91,7 @@ namespace boost { bucket() : next_() { - BOOST_HASH_MSVC_RESET_PTR(next_); + BOOST_UNORDERED_MSVC_RESET_PTR(next_); } bucket(bucket const& x) : next_(x.next_) @@ -109,11 +112,11 @@ namespace boost { struct node_base : bucket { -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS public: node_base() : group_prev_() { - BOOST_HASH_MSVC_RESET_PTR(group_prev_); + BOOST_UNORDERED_MSVC_RESET_PTR(group_prev_); } link_ptr group_prev_; @@ -180,7 +183,7 @@ namespace boost { : allocators_(a), node_(), value_constructed_(false), node_base_constructed_(false) { - BOOST_HASH_MSVC_RESET_PTR(node_); + BOOST_UNORDERED_MSVC_RESET_PTR(node_); } ~node_constructor() @@ -237,27 +240,17 @@ namespace boost { // Methods for navigating groups of elements with equal keys. -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS static inline link_ptr& prev_in_group(link_ptr n) { return static_cast(*n).group_prev_; } - // pre: Must be pointing to the first node in a group. - static inline link_ptr last_in_group(link_ptr n) { - BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(n) && n != prev_in_group(n)->next_); - return prev_in_group(n); - } - // pre: Must be pointing to the first node in a group. static inline link_ptr& next_group(link_ptr n) { - BOOST_ASSERT(BOOST_HASH_BORLAND_BOOL(n) && n != prev_in_group(n)->next_); + BOOST_ASSERT(BOOST_UNORDERED_BORLAND_BOOL(n) && n != prev_in_group(n)->next_); return prev_in_group(n)->next_; } #else - static inline link_ptr last_in_group(link_ptr n) { - return n; - } - static inline link_ptr& next_group(link_ptr n) { BOOST_ASSERT(n); return n->next_; @@ -285,8 +278,8 @@ namespace boost { iterator_base() : bucket_(), node_() { - BOOST_HASH_MSVC_RESET_PTR(bucket_); - BOOST_HASH_MSVC_RESET_PTR(node_); + BOOST_UNORDERED_MSVC_RESET_PTR(bucket_); + BOOST_UNORDERED_MSVC_RESET_PTR(node_); } explicit iterator_base(bucket_ptr b) @@ -320,6 +313,16 @@ namespace boost { node_ = bucket_->next_; } } + + void incrementGroup() + { + node_ = data::next_group(node_); + + while (!node_) { + ++bucket_; + node_ = bucket_->next_; + } + } }; // Member Variables @@ -345,7 +348,7 @@ namespace boost { // Creates an extra bucket to act as a sentinel. constructor.construct(bucket(), bucket_count_ + 1); - cached_begin_bucket_ = constructor.get() + bucket_count_; + cached_begin_bucket_ = constructor.get() + static_cast(bucket_count_); // Set up the sentinel. cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_); @@ -368,7 +371,7 @@ namespace boost { // Creates an extra bucket to act as a sentinel. constructor.construct(bucket(), bucket_count_ + 1); - cached_begin_bucket_ = constructor.get() + bucket_count_; + cached_begin_bucket_ = constructor.get() + static_cast(bucket_count_); // Set up the sentinel cached_begin_bucket_->next_ = link_ptr(cached_begin_bucket_); @@ -383,15 +386,16 @@ namespace boost { { if(buckets_) { bucket_ptr begin = cached_begin_bucket_; - bucket_ptr end = buckets_ + bucket_count_; + bucket_ptr end = buckets_end(); while(begin != end) { clear_bucket(begin); ++begin; } // Destroy an extra bucket for the sentinels. - for(size_type i2 = 0; i2 < bucket_count_ + 1; ++i2) - allocators_.bucket_alloc_.destroy(buckets_ + i2); + ++end; + for(begin = buckets_; begin != end; ++begin) + allocators_.bucket_alloc_.destroy(begin); allocators_.bucket_alloc_.deallocate(buckets_, bucket_count_ + 1); } @@ -413,18 +417,24 @@ namespace boost { std::swap(size_, other.size_); } - // Return the bucket index for a hashed value. + // Return the bucket for a hashed value. // // no throw - size_type index_from_hash(size_type hashed) const + bucket_ptr bucket_from_hash(size_type hashed) const { - return hashed % bucket_count_; + return buckets_ + static_cast(hashed % bucket_count_); } // Begin & End // // no throw + bucket_ptr buckets_end() const + { + return buckets_ + static_cast(bucket_count_); + } + + iterator_base begin() const { return size_ @@ -434,7 +444,7 @@ namespace boost { iterator_base end() const { - return iterator_base(buckets_ + bucket_count_); + return iterator_base(buckets_end()); } link_ptr begin(size_type n) const @@ -455,17 +465,17 @@ namespace boost { // Bucket Size // no throw - size_type node_count(link_ptr it) const + static inline size_type node_count(link_ptr it) { size_type count = 0; - while(BOOST_HASH_BORLAND_BOOL(it)) { + while(BOOST_UNORDERED_BORLAND_BOOL(it)) { ++count; it = it->next_; } return count; } - size_type node_count(link_ptr it1, link_ptr it2) const + static inline size_type node_count(link_ptr it1, link_ptr it2) { size_type count = 0; while(it1 != it2) { @@ -480,19 +490,13 @@ namespace boost { return node_count(begin(n)); } -#if BOOST_UNORDERED_HASH_EQUIVALENT - static size_type group_count(link_ptr it) +#if BOOST_UNORDERED_EQUIVALENT_KEYS + static inline size_type group_count(link_ptr it) { - size_type count = 0; - link_ptr first = it; - do { - ++count; - it = prev_in_group(it); - } while (it != first); // throws, strong - return count; + return node_count(it, next_group(it)); } #else - static size_type group_count(link_ptr) + static inline size_type group_count(link_ptr) { return 1; } @@ -504,7 +508,7 @@ namespace boost { // // no throw -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS static link_ptr* get_for_erase(iterator_base r) { link_ptr n = r.node_; @@ -538,7 +542,7 @@ namespace boost { // // no throw -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS void link_node(link_ptr n, link_ptr pos) { node& node_ref = get_node(n); @@ -584,7 +588,7 @@ namespace boost { } #endif -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS void unlink_node(iterator_base it) { link_ptr* pos = get_for_erase(it); @@ -595,7 +599,7 @@ namespace boost { // The deleted node is the sole node in the group, so // no need to unlink it from a group. } - else if(BOOST_HASH_BORLAND_BOOL(next) && prev_in_group(next) == *pos) + else if(BOOST_UNORDERED_BORLAND_BOOL(next) && prev_in_group(next) == *pos) { // The deleted node is not at the end of the group, so // change the link from the next node. @@ -619,8 +623,7 @@ namespace boost { { size_type count = group_count(*pos); size_ -= count; - link_ptr last = last_in_group(*pos); - *pos = last->next_; + *pos = next_group(*pos); return count; } #else @@ -668,11 +671,11 @@ namespace boost { size_ -= node_count(ptr, end.node_); } -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS // Break a ciruclar list into two, with split as the beginning // of the second group (if split is at the beginning then don't // split). - link_ptr split_group(link_ptr split) + static inline link_ptr split_group(link_ptr split) { // If split is at the beginning of the group then there's // nothing to split. @@ -692,23 +695,23 @@ namespace boost { return start; } - void split_group(link_ptr split1, link_ptr split2) + static inline void split_group(link_ptr split1, link_ptr split2) { link_ptr begin1 = split_group(split1); link_ptr begin2 = split_group(split2); - if(BOOST_HASH_BORLAND_BOOL(begin1) && split1 == begin2) { + if(BOOST_UNORDERED_BORLAND_BOOL(begin1) && split1 == begin2) { link_ptr end1 = prev_in_group(begin1); prev_in_group(begin1) = prev_in_group(begin2); prev_in_group(begin2) = end1; } } #else - void split_group(link_ptr) + static inline void split_group(link_ptr) { } - void split_group(link_ptr, link_ptr) + static inline void split_group(link_ptr, link_ptr) { } #endif @@ -737,7 +740,7 @@ namespace boost { return iterator_base(base, n); } -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS iterator_base create_node(value_type const& v, iterator_base position) { // throws, strong exception-safety: @@ -755,7 +758,7 @@ namespace boost { link_ptr n = construct_node(v); // Rest is no throw - if(BOOST_HASH_BORLAND_BOOL(position)) + if(BOOST_UNORDERED_BORLAND_BOOL(position)) link_node(n, position); else link_node_in_bucket(n, base); @@ -764,7 +767,7 @@ namespace boost { } #endif -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS void copy_group(link_ptr it, bucket_ptr dst) { link_ptr end = next_group(it); @@ -804,7 +807,7 @@ namespace boost { } } -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS void delete_group(link_ptr first_node) { delete_nodes(first_node, prev_in_group(first_node)->next_); @@ -832,7 +835,7 @@ namespace boost { void clear() { bucket_ptr begin = cached_begin_bucket_; - bucket_ptr end = buckets_ + bucket_count_; + bucket_ptr end = buckets_end(); size_ = 0; cached_begin_bucket_ = end; @@ -880,7 +883,8 @@ namespace boost { unlink_nodes(r1); delete_to_bucket_end(r1.node_); - for(bucket_ptr i = r1.bucket_ + 1; i != r2.bucket_; ++i) { + bucket_ptr i = r1.bucket_; + for(++i; i != r2.bucket_; ++i) { size_ -= node_count(i->next_); clear_bucket(i); } @@ -917,7 +921,7 @@ namespace boost { while (cached_begin_bucket_->empty()) ++cached_begin_bucket_; } else { - cached_begin_bucket_ = buckets_ + bucket_count_; + cached_begin_bucket_ = buckets_end(); } } } @@ -929,7 +933,7 @@ namespace boost { void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2) { BOOST_ASSERT(!(b1 < cached_begin_bucket_) && !(b2 < b1)); - BOOST_ASSERT(b2 == buckets_ + bucket_count_ || !b2->empty()); + BOOST_ASSERT(b2 == buckets_end() || !b2->empty()); if(b1 == cached_begin_bucket_ && b1->empty()) cached_begin_bucket_ = b2; @@ -985,6 +989,7 @@ namespace boost { typedef Pred key_equal; typedef ValueType value_type; typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; // iterators @@ -1248,13 +1253,14 @@ namespace boost { size_type bucket(key_type const& k) const { // hash_function can throw: - return this->index_from_hash(hash_function()(k)); + return hash_function()(k) % this->bucket_count_; } + // strong safety bucket_ptr get_bucket(key_type const& k) const { - return this->buckets_ + bucket(k); + return this->buckets_ + static_cast(bucket(k)); } // no throw @@ -1416,7 +1422,7 @@ namespace boost { BOOST_ASSERT(dst.size_ == 0); //BOOST_ASSERT(src.allocators_.node_alloc_ == dst.allocators_.node_alloc_); - bucket_ptr end = src.buckets_ + src.bucket_count_; + bucket_ptr end = src.buckets_end(); for(; src.cached_begin_bucket_ != end; ++src.cached_begin_bucket_) { @@ -1426,8 +1432,7 @@ namespace boost { // src_bucket to dst. // This next line throws iff the hash function throws. - bucket_ptr dst_bucket = dst.buckets_ + - dst.index_from_hash( + bucket_ptr dst_bucket = dst.bucket_from_hash( hf(extract_key(data::get_value(src_bucket->next_)))); link_ptr n = src_bucket->next_; @@ -1444,17 +1449,17 @@ namespace boost { { BOOST_ASSERT(dst.size_ == 0); // no throw: - bucket_ptr end = src.buckets_ + src.bucket_count_; + bucket_ptr end = src.buckets_end(); hasher const& hf = f.hash_function(); // no throw: for(bucket_ptr i = src.cached_begin_bucket_; i != end; ++i) { // no throw: for(link_ptr it = src.begin(i); - BOOST_HASH_BORLAND_BOOL(it); it = data::next_group(it)) { + BOOST_UNORDERED_BORLAND_BOOL(it); it = data::next_group(it)) { // hash function can throw. - bucket_ptr dst_bucket = dst.buckets_ + - dst.index_from_hash(hf(extract_key(data::get_value(it)))); + bucket_ptr dst_bucket = dst.bucket_from_hash( + hf(extract_key(data::get_value(it)))); // throws, strong dst.copy_group(it, dst_bucket); } @@ -1468,7 +1473,7 @@ namespace boost { // basic exception safety, if hash function throws // strong otherwise. -#if BOOST_UNORDERED_HASH_EQUIVALENT +#if BOOST_UNORDERED_EQUIVALENT_KEYS // Insert (equivalent key containers) @@ -1478,8 +1483,7 @@ namespace boost { { key_type const& k = extract_key(v); size_type hash_value = hash_function()(k); - bucket_ptr bucket = this->buckets_ - + this->index_from_hash(hash_value); + bucket_ptr bucket = this->bucket_from_hash(hash_value); link_ptr position = find_iterator(bucket, k); // Create the node before rehashing in case it throws an @@ -1490,7 +1494,7 @@ namespace boost { // reserve has basic exception safety if the hash function // throws, strong otherwise. if(reserve(size() + 1)) - bucket = this->buckets_ + this->index_from_hash(hash_value); + bucket = this->bucket_from_hash(hash_value); // Nothing after the point can throw. @@ -1498,7 +1502,7 @@ namespace boost { // I'm relying on link_ptr not being invalidated by // the rehash here. - if(BOOST_HASH_BORLAND_BOOL(position)) + if(BOOST_UNORDERED_BORLAND_BOOL(position)) this->link_node(n, position); else this->link_node_in_bucket(n, bucket); @@ -1570,7 +1574,7 @@ namespace boost { bucket_ptr bucket = get_bucket(k); link_ptr position = find_iterator(bucket, k); - if(BOOST_HASH_BORLAND_BOOL(position)) + if(BOOST_UNORDERED_BORLAND_BOOL(position)) this->link_node(a.release(), position); else this->link_node_in_bucket(a.release(), bucket); @@ -1610,10 +1614,10 @@ namespace boost { typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; size_type hash_value = hash_function()(k); - bucket_ptr bucket = this->buckets_ + this->index_from_hash(hash_value); + bucket_ptr bucket = this->bucket_from_hash(hash_value); link_ptr pos = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(pos)) + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) return data::get_value(pos); else { @@ -1626,8 +1630,8 @@ namespace boost { // reserve has basic exception safety if the hash function // throws, strong otherwise. - if (reserve(size() + 1)) - bucket = this->buckets_ + this->index_from_hash(hash_value); + if(reserve(size() + 1)) + bucket = this->bucket_from_hash(hash_value); // Nothing after this point can throw. @@ -1647,10 +1651,10 @@ 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->buckets_ + this->index_from_hash(hash_value); + bucket_ptr bucket = this->bucket_from_hash(hash_value); link_ptr pos = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(pos)) { + if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Found an existing key, return it (no throw). return std::pair( iterator_base(bucket, pos), false); @@ -1667,7 +1671,7 @@ namespace boost { // reserve has basic exception safety if the hash function // throws, strong otherwise. if(reserve(size() + 1)) - bucket = this->buckets_ + this->index_from_hash(hash_value); + bucket = this->bucket_from_hash(hash_value); // Nothing after this point can throw. @@ -1723,11 +1727,10 @@ namespace boost { for (; i != j; ++i) { // No side effects in this initial code size_type hash_value = hash_function()(extract_key(*i)); - bucket_ptr bucket = this->buckets_ - + this->index_from_hash(hash_value); + bucket_ptr bucket = this->bucket_from_hash(hash_value); link_ptr pos = find_iterator(bucket, extract_key(*i)); - if (!BOOST_HASH_BORLAND_BOOL(pos)) { + if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) { // Doesn't already exist, add to bucket. // Side effects only in this block. @@ -1740,7 +1743,7 @@ namespace boost { // throws, strong otherwise. if(size() + 1 >= max_load_) { reserve(size() + insert_size(i, j)); - bucket = this->buckets_ + this->index_from_hash(hash_value); + bucket = this->bucket_from_hash(hash_value); } // Nothing after this point can throw. @@ -1782,7 +1785,7 @@ namespace boost { size_type count(key_type const& k) const { link_ptr it = find_iterator(k); // throws, strong - return BOOST_HASH_BORLAND_BOOL(it) ? data::group_count(it) : 0; + return BOOST_UNORDERED_BORLAND_BOOL(it) ? data::group_count(it) : 0; } // find @@ -1793,7 +1796,7 @@ namespace boost { bucket_ptr bucket = get_bucket(k); link_ptr it = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(it)) + if (BOOST_UNORDERED_BORLAND_BOOL(it)) return iterator_base(bucket, it); else return this->end(); @@ -1804,7 +1807,7 @@ namespace boost { bucket_ptr bucket = get_bucket(k); link_ptr it = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(it)) + if (BOOST_UNORDERED_BORLAND_BOOL(it)) return data::get_value(it); else throw std::out_of_range("Unable to find key in unordered_map."); @@ -1817,10 +1820,10 @@ namespace boost { { bucket_ptr bucket = get_bucket(k); link_ptr it = find_iterator(bucket, k); - if (BOOST_HASH_BORLAND_BOOL(it)) { + if (BOOST_UNORDERED_BORLAND_BOOL(it)) { iterator_base first(iterator_base(bucket, it)); - iterator_base second(iterator_base(bucket, this->last_in_group(it))); - second.increment(); + iterator_base second(first); + second.incrementGroup(); return std::pair(first, second); } else { @@ -1848,7 +1851,7 @@ namespace boost { key_type const& k) const { link_ptr it = this->begin(bucket); - while (BOOST_HASH_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) + while (BOOST_UNORDERED_BORLAND_BOOL(it) && !equal(k, data::get_value(it))) it = data::next_group(it); return it; @@ -1858,7 +1861,7 @@ namespace boost { link_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const { link_ptr* it = &bucket->next_; - while(BOOST_HASH_BORLAND_BOOL(*it) && !equal(k, data::get_value(*it))) + while(BOOST_UNORDERED_BORLAND_BOOL(*it) && !equal(k, data::get_value(*it))) it = &data::next_group(*it); return it; @@ -1899,7 +1902,7 @@ namespace boost { public: BOOST_UNORDERED_LOCAL_ITERATOR() : ptr_() { - BOOST_HASH_MSVC_RESET_PTR(ptr_); + BOOST_UNORDERED_MSVC_RESET_PTR(ptr_); } explicit BOOST_UNORDERED_LOCAL_ITERATOR(ptr x) : ptr_(x) {} BOOST_DEDUCED_TYPENAME allocator_reference::type operator*() const @@ -1934,7 +1937,7 @@ namespace boost { public: BOOST_UNORDERED_CONST_LOCAL_ITERATOR() : ptr_() { - BOOST_HASH_MSVC_RESET_PTR(ptr_); + BOOST_UNORDERED_MSVC_RESET_PTR(ptr_); } explicit BOOST_UNORDERED_CONST_LOCAL_ITERATOR(ptr x) : ptr_(x) {} BOOST_UNORDERED_CONST_LOCAL_ITERATOR(local_iterator x) : ptr_(x.ptr_) {} diff --git a/release.sh b/release.sh index 5cacfc71..68e33a3a 100755 --- a/release.sh +++ b/release.sh @@ -16,6 +16,7 @@ mkdir $UNORDERED_DST/doc/html/images/ cp $BOOST_ROOT/doc/html/*.css $UNORDERED_DST/doc/html/ cp $BOOST_ROOT/doc/html/images/*.png $UNORDERED_DST/doc/html/images/ +rm -r $UNORDERED_DST/libs/functional rm -r $UNORDERED_DST/bin.v2 rm $UNORDERED_DST/release.sh diff --git a/test/container/Jamfile.v2 b/test/container/Jamfile.v2 index b9a378d4..7d050bd7 100644 --- a/test/container/Jamfile.v2 +++ b/test/container/Jamfile.v2 @@ -8,6 +8,8 @@ import testing ; project unordered-test/container : requirements intel-linux:"-strict_ansi -cxxlib-icc" + gcc:-Wsign-promo + msvc:/W4 ; test-suite container-tests diff --git a/test/exception/Jamfile.v2 b/test/exception/Jamfile.v2 index 0ec42869..7cb28a5e 100644 --- a/test/exception/Jamfile.v2 +++ b/test/exception/Jamfile.v2 @@ -10,6 +10,7 @@ alias framework : /boost/test//boost_unit_test_framework ; project unordered-test/exception-tests : requirements intel-linux:"-strict_ansi -cxxlib-icc" + gcc:-Wsign-promo ; test-suite unordered-tests diff --git a/test/helpers/generators.hpp b/test/helpers/generators.hpp index 4322d5be..bdc7ad2c 100644 --- a/test/helpers/generators.hpp +++ b/test/helpers/generators.hpp @@ -58,7 +58,7 @@ namespace test inline char generate(char const*) { using namespace std; - return (rand() >> 1) % (128-32) + 32; + return static_cast((rand() >> 1) % (128-32) + 32); } inline signed char generate(signed char const*) diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 29b2a47c..5390ec46 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -8,6 +8,8 @@ import testing ; project unordered-test/unordered : requirements intel-linux:"-strict_ansi -cxxlib-icc" + gcc:-Wsign-promo + msvc:/W4 ; test-suite unordered-tests diff --git a/test/unordered/compile_tests.cpp b/test/unordered/compile_tests.cpp index 616b7423..331bdad8 100644 --- a/test/unordered/compile_tests.cpp +++ b/test/unordered/compile_tests.cpp @@ -59,7 +59,7 @@ void unordered_equivalent_test(X& r, T const& t) } template -void unordered_map_functions(X&, Key const& k, T const& t) +void unordered_map_functions(X&, Key const& k, T const&) { typedef typename X::mapped_type mapped_type;