From 5867994b8cb8e244af38d71d6ab381dda9f86b19 Mon Sep 17 00:00:00 2001 From: Daniel James Date: Sun, 4 Sep 2011 19:37:45 +0000 Subject: [PATCH] Unordered: Merge from trunk - Remove use of BOOST_DEDUCED_TYPENAME and BOOST_UNORDERED_PAIR_CAST, it's unlikely that the compilers which require them will be able to cope with the new version of unordered. - Use the old equality algorithm if BOOST_UNORDERED_DEPRECATED_EQUALITY is defined. - Use SFINAE to control which overloads of `construct_impl` are available. Fixes problems with differing overload resolution on different compilers. - Support for piecewise pair construction. - Only support the old variadic pair construction when BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT is defined (also fixed some bugs). - Avoid instantiating BOOST_RV_REF for non-classes. - Support optional allocator member functions for compilers with SFINAE expressions and Visual C++ 9.0/10.0 - Follow boost macro naming conventions. - Improved portability for `allocator_traits` emulation. Current compiler support: - Full support for GCC 4.4+, Visual C++ 9.0+, Clang. - All other compilers odn't support optional allocator members. - No other errors for GCC 3.4.6+, Visual C++ 8.0, Intel, Pathscale. - Visual Age has a compile error if `select_on_container_copy_construction` isn't `const` (it should ignore it). - `select_on_container_copy_construction` detection doesn't work on Sun. - `unnecessary_copy_tests` is failling for vacpp on AIX, but not on linux. - Warnings causing failures for Visual C++ with STLport and WM5. [SVN r74234] --- doc/buckets.qbk | 2 +- doc/changes.qbk | 3 + doc/comparison.qbk | 4 +- doc/compliance.qbk | 89 +++-- doc/hash_equality.qbk | 5 +- doc/intro.qbk | 19 +- doc/rationale.qbk | 6 + doc/ref.php | 81 +++-- doc/ref.xml | 324 ++++++++++-------- doc/unordered.qbk | 2 +- .../unordered/detail/allocator_helpers.hpp | 216 ++++++++---- include/boost/unordered/detail/buckets.hpp | 320 +++++++++++------ include/boost/unordered/detail/equivalent.hpp | 74 ++-- .../boost/unordered/detail/extract_key.hpp | 67 +++- include/boost/unordered/detail/fwd.hpp | 3 + include/boost/unordered/detail/node.hpp | 24 +- include/boost/unordered/detail/table.hpp | 96 +++--- include/boost/unordered/detail/unique.hpp | 51 ++- include/boost/unordered/detail/util.hpp | 73 ++-- include/boost/unordered/unordered_map.hpp | 187 +++++----- include/boost/unordered/unordered_set.hpp | 170 ++++----- test/unordered/Jamfile.v2 | 5 + test/unordered/compile_set.cpp | 4 +- test/unordered/equality_deprecated.cpp | 173 ++++++++++ test/unordered/insert_tests.cpp | 43 ++- test/unordered/minimal_allocator.cpp | 89 +++++ test/unordered/unnecessary_copy_tests.cpp | 54 ++- 27 files changed, 1465 insertions(+), 719 deletions(-) create mode 100644 test/unordered/equality_deprecated.cpp create mode 100644 test/unordered/minimal_allocator.cpp diff --git a/doc/buckets.qbk b/doc/buckets.qbk index 1303708f..ab68aebc 100644 --- a/doc/buckets.qbk +++ b/doc/buckets.qbk @@ -112,7 +112,7 @@ load factor is /required/ to be less than the maximum is following a call to 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 +[table:bucket_size Methods for Controlling Bucket Size [[Method] [Description]] [ diff --git a/doc/changes.qbk b/doc/changes.qbk index 58a16854..a10f2b70 100644 --- a/doc/changes.qbk +++ b/doc/changes.qbk @@ -151,4 +151,7 @@ in some breaking changes: the allocator has a member structure `propagate_on_container_swap`, such that `propagate_on_container_swap::value` is true. +* Allocator's `construct` and `destroy` functions are called with raw + pointers, rather than the allocator's `pointer` type. + [endsect] diff --git a/doc/comparison.qbk b/doc/comparison.qbk index 3cea831e..0924fe5c 100644 --- a/doc/comparison.qbk +++ b/doc/comparison.qbk @@ -4,7 +4,7 @@ [section:comparison Comparison with Associative Containers] -[table Interface differences. +[table:interface_differences Interface differences. [[Associative Containers] [Unordered Associative Containers]] [ @@ -88,7 +88,7 @@ ] ] -[table Complexity Guarantees +[table:complexity_guarantees Complexity Guarantees [[Operation] [Associative Containers] [Unordered Associative Containers]] [ [Construction of empty container] diff --git a/doc/compliance.qbk b/doc/compliance.qbk index 759d9bde..322483fd 100644 --- a/doc/compliance.qbk +++ b/doc/compliance.qbk @@ -4,25 +4,42 @@ [section:compliance C++11 Compliance] -/TODO/: Look into C++11's `std::pair`. - [section:allocator_compliance Use of allocators] -* Objects are not constructed using the allocator. The node containing them - is constructed using the allocator's `construct` function, but then the - object is constructed in a buffer in that node by calling the constructor - directly. -* Similarly the object is destructed by calling its destructor directly, and - then the allocator's `destroy` method is used to destruct the node. -* For most compilers `select_on_container_copy` is only detected for an - exact signature match in the allocator itself - not in a base. There is full - detection for g++ 4.4 or laster, Visual C++ 2008 or later, Clang and maybe - other compilers which support SFINAE for expressions. -* `pointer_traits` aren't used. Instead, pointer types are obtained from - rebound allocators. -* /TODO/: Any other defficiences of `allocator_traits` emulation. -* Pointers of base types are used to store the location of a derived type. - (/TODO/: I'm not sure if that isn't compliant). +C++11 introduced a new, mostly backwards compatible, allocator system. +This uses a traits class, `allocator_traits` to handle the allocator +adding extra functionality, and making some methods and types optional. +At the time of writing there isn't a stable release of a standard library +with `allocator_traits` (libc++ has `allocator_traits` but it hasn't been +released yet) so a partial implementation is always used. + +A full implementation of `allocator_traits` requires sophisticated +member function detection which requires support for SFINAE expressions, +or something close. This is available on GCC from version 4.4, Clang and +Visual C++ 2008 (with a little hacking) or later. + +On these compilers, the `construct`, `destroy` and `max_size` member functions +are optional, as per C++11. On other compilers they are still required. + +`propagate_on_container_copy_assignment`, +`propagate_on_container_move_assignment` and +`propagate_on_container_swap` are supported on most compilers +(/TODO/: which ones don't support them?). +`select_on_container_copy_construction` is also supported, but on +compilers without full member function detection it must have exactly +the right function signature, and can't be declared in a base class +in order for it to be detected. + +The use of the allocator's construct and destruct methods might be a bit +surprising. +Nodes are constructed and destructed using the allocator, but the objects +contained in the node are stored in aligned space within the node +and constructed and destructed by calling the constructor and destructor +directly. So `construct` and `destroy` are called for the node, but not for +the object. + +`pointer_traits` aren't used. Instead, pointer types are obtained from +rebound allocators. [endsect] @@ -35,19 +52,43 @@ use Boost.Move. * Non-copyable objects can be stored in the containers, but without support for rvalue references the container will not be movable. -* The number of arguments used in emplace is limited to /TODO/. +* The number of arguments used in `emplace` is limited to /TODO/. * Argument forwarding is not perfect. -* /TODO/: Constructor call for pairs. [endsect] -[section:other Other] +[section:pairs Pairs] -* When swapping, `Pred` and `Hash` are not currently swapped by calling - `swap`, their copy constructors are used. -* As a consequence when swapping an exception may be throw from their - copy constructor. +Since the containers use `std::pair` they're limited to the version +from the current standard library. But since C++11 `std::pair`'s +`piecewise_construct` based constructor is very useful, `emplace` +emulates it with a `piecewise_construct` in the `boost::unordered` +namespace. So for example, the following will work: + boost::unordered_multimap x; + + x.emplace( + boost::unordered::piecewise_construct, + boost::make_tuple("key"), boost::make_tuple(1, 2)); + +Older drafts of the standard also supported variadic constructors +for `std::pair`, where the first argument would be used for the +first part of the pair, and the remaining for the second part. +For the same example: + + x.emplace("key", 1, 2); + +This is emulated in Boost.Unordered, but will be deprecated soon. +While it is a lot more compact, it lead to ambiguities so it was +removed. + +[endsect] + +[section:swap Swapping] + +When swapping, `Pred` and `Hash` are not currently swapped by calling +`swap`, their copy constructors are used. As a consequence when swapping +an exception may be throw from their copy constructor. [endsect] diff --git a/doc/hash_equality.qbk b/doc/hash_equality.qbk index db1b0616..c13fcc48 100644 --- a/doc/hash_equality.qbk +++ b/doc/hash_equality.qbk @@ -67,9 +67,10 @@ so that the hash function doesn't need to be explicitly given: See the [link hash.custom Boost.Hash documentation] for more detail on how to do this. Remember that it relies on extensions to the draft standard - so it -won't work on other implementations of the unordered associative containers. +won't work for other implementations of the unordered associative containers, +you'll need to explicitly use Boost.Hash. -[table Methods for accessing the hash and equality functions. +[table:access_methods Methods for accessing the hash and equality functions. [[Method] [Description]] [ diff --git a/doc/intro.qbk b/doc/intro.qbk index ea06bfb7..257b959a 100644 --- a/doc/intro.qbk +++ b/doc/intro.qbk @@ -2,15 +2,6 @@ / 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) ] -[def __tr1__ - [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1836.pdf - C++ Standard Library Technical Report]] -[def __boost-tr1__ - [@http://www.boost.org/doc/html/boost_tr1.html - Boost.TR1]] -[def __draft__ - [@http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2960.pdf - Working Draft of the C++ Standard]] [def __hash-table__ [@http://en.wikipedia.org/wiki/Hash_table hash table]] [def __hash-function__ [@http://en.wikipedia.org/wiki/Hash_function @@ -31,12 +22,10 @@ to order their elements. For some data types this is impossible to implement or isn't practical. In contrast, a hash table only needs an equality function and a hash function for the key. -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__. +With this in mind, unordered associative containers were added to the C++ +standard. This is an implementation of the containers described in C++11, +with some [link unordered.compliance deviations from the standard] in +order to work with non-C++11 compilers and libraries. `unordered_set` and `unordered_multiset` are defined in the header <[headerref boost/unordered_set.hpp]> diff --git a/doc/rationale.qbk b/doc/rationale.qbk index 6662f13e..19e8945c 100644 --- a/doc/rationale.qbk +++ b/doc/rationale.qbk @@ -92,6 +92,8 @@ So, this implementation uses a prime number for the hash table size. [h2 Equality operators] +/TODO/: This is out of date. + `operator==` and `operator!=` are not included in the standard, but I've added them as I think they could be useful and can be implemented fairly efficiently. They are specified differently to the other standard @@ -115,6 +117,8 @@ that their order can be considered part of the container's value. [h3 C++0x allocators] +/TODO/: This is out of date. + Recent drafts have included an overhaul of the allocators, but this was dependent on concepts which are no longer in the standard. [@http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2946.pdf n2946] @@ -124,6 +128,8 @@ a little to accomodate non-C++0x compilers. [h3 Swapping containers with unequal allocators] +/TODO/: This is out of date. + It isn't clear how to swap containers when their allocators aren't equal. This is [@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#431 diff --git a/doc/ref.php b/doc/ref.php index 66f4d930..531d53d2 100644 --- a/doc/ref.php +++ b/doc/ref.php @@ -60,10 +60,6 @@ EOL; - Based on chapter 23 of - the working draft of the C++ standard [n2960]. - But without the updated rules for allocators. - Template Parameters @@ -236,6 +232,9 @@ EOL; The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + If Allocator::select_on_container_copy_construction + exists and has the right signature, the allocator will be + constructed from its result. value_type is copy constructible @@ -249,12 +248,18 @@ EOL; The move constructor. - This is emulated on compilers without rvalue references. + This is implemented using Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). + + + On compilers without rvalue reference support the + emulation does not support moving without calling + boost::move if value_type is + not copyable. So, for example, you can't return the + container from a function. @@ -289,14 +294,12 @@ EOL; & The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + If Alloc::propagate_on_container_copy_assignment + exists and Alloc::propagate_on_container_copy_assignment::value + is true, the allocator is overwritten, if not the + copied elements are created using the existing + allocator. - - - On compilers without rvalue references, there is a single assignment - operator with the signature operator=() - in order to emulate move semantics. - - value_type is copy constructible @@ -308,18 +311,21 @@ EOL; & The move assignment operator. + If Alloc::propagate_on_container_move_assignment + exists and Alloc::propagate_on_container_move_assignment::value + is true, the allocator is overwritten, if not the + moved elements are created using the existing + allocator. - On compilers without rvalue references, there is a single assignment - operator with the signature operator=() - in order to emulate move semantics. + On compilers without rvalue references, this is emulated using + Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). @@ -406,6 +412,10 @@ EOL; If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -444,6 +454,10 @@ EOL; If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -541,15 +555,13 @@ EOL; Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. - When the number of elements is a lot smaller than the number of buckets - this function can be very inefficient as it has to search through empty - buckets for the next element, in order to return the iterator. - The method quick_erase is faster, but has yet - to be standardized. + In older versions this could be inefficient because it had to search + through several buckets to find the position of the returned iterator. + The data structure has been changed so that this is no longer the case, + and the alternative erase methods have been deprecated. @@ -601,13 +613,10 @@ EOL; - This method is faster than erase as - it doesn't have to find the next element in the container - - a potentially costly operation. - - - As it hasn't been standardized, it's likely that this may - change in the future. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -625,10 +634,10 @@ EOL; - This method is now deprecated, use - quick_return instead. Although be - warned that as that isn't standardized yet, it could also - change. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -653,6 +662,7 @@ EOL; 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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -952,6 +962,7 @@ EOL; bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -975,6 +986,7 @@ EOL; bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -1006,6 +1018,7 @@ EOL; 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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. diff --git a/doc/ref.xml b/doc/ref.xml index 7825de2f..14ca58db 100644 --- a/doc/ref.xml +++ b/doc/ref.xml @@ -23,10 +23,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that stores unique values. - Based on chapter 23 of - the working draft of the C++ standard [n2960]. - But without the updated rules for allocators. - Template Parameters @@ -181,6 +177,9 @@ 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. + If Allocator::select_on_container_copy_construction + exists and has the right signature, the allocator will be + constructed from its result. value_type is copy constructible @@ -194,12 +193,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The move constructor. - This is emulated on compilers without rvalue references. + This is implemented using Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). + + + On compilers without rvalue reference support the + emulation does not support moving without calling + boost::move if value_type is + not copyable. So, for example, you can't return the + container from a function. @@ -234,14 +239,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_set& The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + If Alloc::propagate_on_container_copy_assignment + exists and Alloc::propagate_on_container_copy_assignment::value + is true, the allocator is overwritten, if not the + copied elements are created using the existing + allocator. - - - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_set) - in order to emulate move semantics. - - value_type is copy constructible @@ -253,18 +256,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_set& The move assignment operator. + If Alloc::propagate_on_container_move_assignment + exists and Alloc::propagate_on_container_move_assignment::value + is true, the allocator is overwritten, if not the + moved elements are created using the existing + allocator. - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_set) - in order to emulate move semantics. + On compilers without rvalue references, this is emulated using + Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). @@ -344,6 +350,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -375,6 +385,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -457,15 +471,13 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. - When the number of elements is a lot smaller than the number of buckets - this function can be very inefficient as it has to search through empty - buckets for the next element, in order to return the iterator. - The method quick_erase is faster, but has yet - to be standardized. + In older versions this could be inefficient because it had to search + through several buckets to find the position of the returned iterator. + The data structure has been changed so that this is no longer the case, + and the alternative erase methods have been deprecated. @@ -517,13 +529,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is faster than erase as - it doesn't have to find the next element in the container - - a potentially costly operation. - - - As it hasn't been standardized, it's likely that this may - change in the future. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -541,10 +550,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is now deprecated, use - quick_return instead. Although be - warned that as that isn't standardized yet, it could also - change. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -569,6 +578,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -832,6 +842,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -856,6 +867,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -888,6 +900,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -912,10 +925,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that stores values. The same key can be stored multiple times. - Based on chapter 23 of - the working draft of the C++ standard [n2960]. - But without the updated rules for allocators. - Template Parameters @@ -1070,6 +1079,9 @@ 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. + If Allocator::select_on_container_copy_construction + exists and has the right signature, the allocator will be + constructed from its result. value_type is copy constructible @@ -1083,12 +1095,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The move constructor. - This is emulated on compilers without rvalue references. + This is implemented using Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). + + + On compilers without rvalue reference support the + emulation does not support moving without calling + boost::move if value_type is + not copyable. So, for example, you can't return the + container from a function. @@ -1123,14 +1141,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_multiset& The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + If Alloc::propagate_on_container_copy_assignment + exists and Alloc::propagate_on_container_copy_assignment::value + is true, the allocator is overwritten, if not the + copied elements are created using the existing + allocator. - - - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_multiset) - in order to emulate move semantics. - - value_type is copy constructible @@ -1142,18 +1158,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_multiset& The move assignment operator. + If Alloc::propagate_on_container_move_assignment + exists and Alloc::propagate_on_container_move_assignment::value + is true, the allocator is overwritten, if not the + moved elements are created using the existing + allocator. - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_multiset) - in order to emulate move semantics. + On compilers without rvalue references, this is emulated using + Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). @@ -1232,6 +1251,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -1263,6 +1286,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -1344,15 +1371,13 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. - When the number of elements is a lot smaller than the number of buckets - this function can be very inefficient as it has to search through empty - buckets for the next element, in order to return the iterator. - The method quick_erase is faster, but has yet - to be standardized. + In older versions this could be inefficient because it had to search + through several buckets to find the position of the returned iterator. + The data structure has been changed so that this is no longer the case, + and the alternative erase methods have been deprecated. @@ -1404,13 +1429,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is faster than erase as - it doesn't have to find the next element in the container - - a potentially costly operation. - - - As it hasn't been standardized, it's likely that this may - change in the future. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -1428,10 +1450,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is now deprecated, use - quick_return instead. Although be - warned that as that isn't standardized yet, it could also - change. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -1456,6 +1478,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -1719,6 +1742,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -1743,6 +1767,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -1775,6 +1800,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -1805,10 +1831,6 @@ 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. - Based on chapter 23 of - the working draft of the C++ standard [n2960]. - But without the updated rules for allocators. - Template Parameters @@ -1969,6 +1991,9 @@ 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. + If Allocator::select_on_container_copy_construction + exists and has the right signature, the allocator will be + constructed from its result. value_type is copy constructible @@ -1982,12 +2007,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The move constructor. - This is emulated on compilers without rvalue references. + This is implemented using Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). + + + On compilers without rvalue reference support the + emulation does not support moving without calling + boost::move if value_type is + not copyable. So, for example, you can't return the + container from a function. @@ -2022,14 +2053,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_map& The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + If Alloc::propagate_on_container_copy_assignment + exists and Alloc::propagate_on_container_copy_assignment::value + is true, the allocator is overwritten, if not the + copied elements are created using the existing + allocator. - - - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_map) - in order to emulate move semantics. - - value_type is copy constructible @@ -2041,18 +2070,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_map& The move assignment operator. + If Alloc::propagate_on_container_move_assignment + exists and Alloc::propagate_on_container_move_assignment::value + is true, the allocator is overwritten, if not the + moved elements are created using the existing + allocator. - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_map) - in order to emulate move semantics. + On compilers without rvalue references, this is emulated using + Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). @@ -2132,6 +2164,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -2163,6 +2199,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -2245,15 +2285,13 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. - When the number of elements is a lot smaller than the number of buckets - this function can be very inefficient as it has to search through empty - buckets for the next element, in order to return the iterator. - The method quick_erase is faster, but has yet - to be standardized. + In older versions this could be inefficient because it had to search + through several buckets to find the position of the returned iterator. + The data structure has been changed so that this is no longer the case, + and the alternative erase methods have been deprecated. @@ -2305,13 +2343,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is faster than erase as - it doesn't have to find the next element in the container - - a potentially costly operation. - - - As it hasn't been standardized, it's likely that this may - change in the future. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -2329,10 +2364,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is now deprecated, use - quick_return instead. Although be - warned that as that isn't standardized yet, it could also - change. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -2357,6 +2392,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -2657,6 +2693,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -2683,6 +2720,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -2717,6 +2755,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -2743,10 +2782,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) An unordered associative container that associates keys with another value. The same key can be stored multiple times. - Based on chapter 23 of - the working draft of the C++ standard [n2960]. - But without the updated rules for allocators. - Template Parameters @@ -2907,6 +2942,9 @@ 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. + If Allocator::select_on_container_copy_construction + exists and has the right signature, the allocator will be + constructed from its result. value_type is copy constructible @@ -2920,12 +2958,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) The move constructor. - This is emulated on compilers without rvalue references. + This is implemented using Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). + + + On compilers without rvalue reference support the + emulation does not support moving without calling + boost::move if value_type is + not copyable. So, for example, you can't return the + container from a function. @@ -2960,14 +3004,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_multimap& The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + If Alloc::propagate_on_container_copy_assignment + exists and Alloc::propagate_on_container_copy_assignment::value + is true, the allocator is overwritten, if not the + copied elements are created using the existing + allocator. - - - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_multimap) - in order to emulate move semantics. - - value_type is copy constructible @@ -2979,18 +3021,21 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) unordered_multimap& The move assignment operator. + If Alloc::propagate_on_container_move_assignment + exists and Alloc::propagate_on_container_move_assignment::value + is true, the allocator is overwritten, if not the + moved elements are created using the existing + allocator. - On compilers without rvalue references, there is a single assignment - operator with the signature operator=(unordered_multimap) - in order to emulate move semantics. + On compilers without rvalue references, this is emulated using + Boost.Move. value_type is move constructible. - (TODO: This is not actually required in this implementation). @@ -3069,6 +3114,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -3100,6 +3149,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to 10 arguments, with no support for rvalue references or move semantics. + Since existing `std::pair` implementations don't support + std::piecewise_construct this emulates it, + but using boost::unordered::piecewise_construct. + @@ -3181,15 +3234,13 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) Only throws an exception if it is thrown by hasher or key_equal. - In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. - When the number of elements is a lot smaller than the number of buckets - this function can be very inefficient as it has to search through empty - buckets for the next element, in order to return the iterator. - The method quick_erase is faster, but has yet - to be standardized. + In older versions this could be inefficient because it had to search + through several buckets to find the position of the returned iterator. + The data structure has been changed so that this is no longer the case, + and the alternative erase methods have been deprecated. @@ -3241,13 +3292,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is faster than erase as - it doesn't have to find the next element in the container - - a potentially costly operation. - - - As it hasn't been standardized, it's likely that this may - change in the future. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -3265,10 +3313,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - This method is now deprecated, use - quick_return instead. Although be - warned that as that isn't standardized yet, it could also - change. + This method was implemented because returning an iterator to + the next element from erase was expensive, but + the container has been redesigned so that is no longer the + case. So this method is now deprecated. @@ -3293,6 +3341,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. @@ -3558,6 +3607,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -3584,6 +3634,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) bool + TODO: Documentation outdated. This is a boost extension. Behavior is undefined if the two containers don't have equivalent equality predicates. @@ -3618,6 +3669,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. + TODO: Update swap documentation, no longer correct. For a discussion of the behavior when allocators aren't equal see the implementation details. diff --git a/doc/unordered.qbk b/doc/unordered.qbk index 431518ed..a12aaa62 100644 --- a/doc/unordered.qbk +++ b/doc/unordered.qbk @@ -3,7 +3,7 @@ / file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ] [library Boost.Unordered - [quickbook 1.4] + [quickbook 1.5] [authors [James, Daniel]] [copyright 2003 2004 Jeremy B. Maitin-Shepard] [copyright 2005 2006 2007 2008 Daniel James] diff --git a/include/boost/unordered/detail/allocator_helpers.hpp b/include/boost/unordered/detail/allocator_helpers.hpp index c3c080b2..d299f5d9 100644 --- a/include/boost/unordered/detail/allocator_helpers.hpp +++ b/include/boost/unordered/detail/allocator_helpers.hpp @@ -19,6 +19,8 @@ #include #include #include +#include +#include #if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \ && !defined(__BORLANDC__) @@ -76,13 +78,12 @@ namespace boost { namespace unordered { namespace detail { template struct rebind_wrap { - typedef BOOST_DEDUCED_TYPENAME - Alloc::BOOST_NESTED_TEMPLATE rebind::other + typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind::other type; }; # endif - template T& make(); + template typename boost::add_lvalue_reference::type make(); struct choice9 { typedef char (&type)[9]; }; struct choice8 : choice9 { typedef char (&type)[8]; }; struct choice7 : choice8 { typedef char (&type)[7]; }; @@ -94,13 +95,14 @@ namespace boost { namespace unordered { namespace detail { struct choice1 : choice2 { typedef char (&type)[1]; }; choice1 choose(); - #define BOOST_DEFAULT_TYPE_TMPLT(tname) \ +#if defined(BOOST_MSVC) && BOOST_MSVC <= 1400 + + #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ template \ struct default_type_ ## tname { \ \ template \ - static choice1::type test(choice1, \ - BOOST_DEDUCED_TYPENAME X::tname* = 0); \ + static choice1::type test(choice1, typename X::tname* = 0); \ \ template \ static choice2::type test(choice2, void* = 0); \ @@ -109,24 +111,50 @@ namespace boost { namespace unordered { namespace detail { \ enum { value = (1 == sizeof(test(choose()))) }; \ \ - typedef BOOST_DEDUCED_TYPENAME \ - boost::detail::if_true:: \ + typedef typename boost::detail::if_true:: \ BOOST_NESTED_TEMPLATE then \ ::type::tname type; \ } - #define BOOST_DEFAULT_TYPE(T,tname, arg) \ - BOOST_DEDUCED_TYPENAME default_type_ ## tname::type +#else - BOOST_DEFAULT_TYPE_TMPLT(pointer); - BOOST_DEFAULT_TYPE_TMPLT(const_pointer); - BOOST_DEFAULT_TYPE_TMPLT(void_pointer); - BOOST_DEFAULT_TYPE_TMPLT(const_void_pointer); - BOOST_DEFAULT_TYPE_TMPLT(difference_type); - BOOST_DEFAULT_TYPE_TMPLT(size_type); - BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment); - BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment); - BOOST_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); + template + struct sfinae : T2 {}; + + #define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \ + template \ + struct default_type_ ## tname { \ + \ + template \ + static typename sfinae::type \ + test(choice1); \ + \ + template \ + static choice2::type test(choice2); \ + \ + struct DefaultWrap { typedef Default tname; }; \ + \ + enum { value = (1 == sizeof(test(choose()))) }; \ + \ + typedef typename boost::detail::if_true:: \ + BOOST_NESTED_TEMPLATE then \ + ::type::tname type; \ + } + +#endif + + #define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \ + typename default_type_ ## tname::type + + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment); + BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap); #if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500) @@ -146,14 +174,40 @@ namespace boost { namespace unordered { namespace detail { static BOOST_PP_CAT(choice, result)::type test( \ BOOST_PP_CAT(choice, count)) +#define BOOST_UNORDERED_HAS_EXPRESSION(name, expression) \ + struct BOOST_PP_CAT(has_, name) \ + { \ + BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, expression); \ + BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \ + \ + enum { value = sizeof(test(choose())) == sizeof(choice1::type) };\ + } + template - struct has_select_on_container_copy_construction - { - BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, make().select_on_container_copy_construction()); - BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); - - enum { value = sizeof(test(choose())) == sizeof(choice1::type) }; - }; + BOOST_UNORDERED_HAS_EXPRESSION( + select_on_container_copy_construction, + make().select_on_container_copy_construction() + ); + + // Only supporting the basic copy constructor for now. + + template + BOOST_UNORDERED_HAS_EXPRESSION( + construct, + make().construct(make(), make()) + ); + + template + BOOST_UNORDERED_HAS_EXPRESSION( + destroy, + make().destroy(make()) + ); + + template + BOOST_UNORDERED_HAS_EXPRESSION( + max_size, + make().max_size() + ); #else @@ -165,32 +219,43 @@ namespace boost { namespace unordered { namespace detail { \ template \ struct BOOST_PP_CAT(test, count) { \ - typedef void* type; \ + typedef BOOST_PP_CAT(choice, result) type; \ }; \ \ - template static BOOST_PP_CAT(choice, result)::type \ - test(BOOST_PP_CAT(choice, count), \ - typename BOOST_PP_CAT(test, count)< \ - &U::name>::type = 0) + template static typename \ + BOOST_PP_CAT(test, count)<&U::name>::type \ + test(BOOST_PP_CAT(choice, count)) #define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \ template static BOOST_PP_CAT(choice, result)::type \ - test(BOOST_PP_CAT(choice, count), void* = 0) + test(BOOST_PP_CAT(choice, count)) template struct has_select_on_container_copy_construction { - BOOST_UNORDERED_CHECK_MEMBER(1, 1, select_on_container_copy_construction, T (T::*)() const); + BOOST_UNORDERED_CHECK_MEMBER(1, 1, + select_on_container_copy_construction, + T (T::*)() const); BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); enum { value = sizeof(test(choose())) == sizeof(choice1::type) }; }; + // Detection isn't reliable enough, so just assume that we have these + // functions. + + template + struct has_construct : true_type {}; + template + struct has_destroy : true_type {}; + template + struct has_max_size : true_type {}; + #endif template - inline BOOST_DEDUCED_TYPENAME boost::enable_if< + inline typename boost::enable_if< has_select_on_container_copy_construction, Alloc >::type call_select_on_container_copy_construction(const Alloc& rhs) { @@ -198,48 +263,62 @@ namespace boost { namespace unordered { namespace detail { } template - inline BOOST_DEDUCED_TYPENAME boost::disable_if< + inline typename boost::disable_if< has_select_on_container_copy_construction, Alloc >::type call_select_on_container_copy_construction(const Alloc& rhs) { return rhs; } + template + SizeType call_max_size(const Alloc& a, + typename boost::enable_if, void*>::type = 0) + { + return a.max_size(); + } + + template + SizeType call_max_size(const Alloc&, + typename boost::disable_if, void*>::type = 0) + { + return std::numeric_limits::max(); + } + template struct allocator_traits { typedef Alloc allocator_type; typedef typename Alloc::value_type value_type; - typedef BOOST_DEFAULT_TYPE(Alloc, pointer, value_type*) + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*) pointer; // For now always use the allocator's const_pointer. - //typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer, - // BOOST_DEDUCED_TYPENAME pointer_traits:: + //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, + // typename pointer_traits:: // BOOST_NESTED_TEMPLATE rebind::other) // const_pointer; - typedef BOOST_DEFAULT_TYPE(Alloc, const_pointer, value_type const*) - const_pointer; + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer, + value_type const*) const_pointer; // I'm not using void pointers for now. - //typedef BOOST_DEFAULT_TYPE(Alloc, void_pointer, + //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer, // BOOST_NESTED_TEMPLATE pointer_traits:: // BOOST_NESTED_TEMPLATE rebind::other) // void_pointer; - //typedef BOOST_DEFAULT_TYPE(Alloc, const_void_pointer, - // BOOST_DEDUCED_TYPENAME pointer_traits:: + //typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer, + // typename pointer_traits:: // BOOST_NESTED_TEMPLATE rebind::other) // const_void_pointer; - typedef BOOST_DEFAULT_TYPE(Alloc, difference_type, std::ptrdiff_t) - difference_type; + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type, + std::ptrdiff_t) difference_type; - typedef BOOST_DEFAULT_TYPE(Alloc, size_type, std::size_t) + typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, size_type, std::size_t) size_type; // TODO: rebind_alloc and rebind_traits @@ -249,32 +328,49 @@ namespace boost { namespace unordered { namespace detail { // I never use this, so I'll just comment it out for now. // - //static pointer allocate(Alloc& a, size_type n, const_void_pointer hint) + //static pointer allocate(Alloc& a, size_type n, + // const_void_pointer hint) // { return DEFAULT_FUNC(allocate, pointer)(a, n, hint); } static void deallocate(Alloc& a, pointer p, size_type n) { a.deallocate(p, n); } - // Only support the basic copy constructor + public: - // template - // static void construct(Alloc& a, T* p, Args&&... args) { - // DEFAULT_FUNC(construct,void)(a, p, std::forward(args)...); - // } + // Only supporting the basic copy constructor for now. template - static void construct(Alloc& a, T* p, T const& x) { + static void construct(Alloc& a, T* p, T const& x, typename + boost::enable_if, void*>::type = 0) + { a.construct(p, x); } template - static void destroy(Alloc& a, T* p) { - // DEFAULT_FUNC(destroy,void)(a, p); + static void construct(Alloc&, T* p, T const& x, typename + boost::disable_if, void*>::type = 0) + { + new ((void*) p) T(x); + } + + template + static void destroy(Alloc& a, T* p, typename + boost::enable_if, void*>::type = 0) + { a.destroy(p); } + template + static void destroy(Alloc&, T* p, typename + boost::disable_if, void*>::type = 0) + { + p->~T(); + } + static size_type max_size(const Alloc& a) - { return a.max_size(); } + { + return boost::unordered::detail::call_max_size(a); + } // Allocator propagation on construction @@ -286,13 +382,13 @@ namespace boost { namespace unordered { namespace detail { // Allocator propagation on assignment and swap. // Return true if lhs is modified. - typedef BOOST_DEFAULT_TYPE( + typedef BOOST_UNORDERED_DEFAULT_TYPE( Alloc, propagate_on_container_copy_assignment, false_type) propagate_on_container_copy_assignment; - typedef BOOST_DEFAULT_TYPE( + typedef BOOST_UNORDERED_DEFAULT_TYPE( Alloc,propagate_on_container_move_assignment, false_type) propagate_on_container_move_assignment; - typedef BOOST_DEFAULT_TYPE( + typedef BOOST_UNORDERED_DEFAULT_TYPE( Alloc,propagate_on_container_swap,false_type) propagate_on_container_swap; }; @@ -307,7 +403,7 @@ namespace boost { namespace unordered { namespace detail { template struct allocator_array_constructor { - typedef BOOST_DEDUCED_TYPENAME allocator_traits::pointer + typedef typename allocator_traits::pointer pointer; Allocator& alloc_; diff --git a/include/boost/unordered/detail/buckets.hpp b/include/boost/unordered/detail/buckets.hpp index 4fb1f503..fdb30b70 100644 --- a/include/boost/unordered/detail/buckets.hpp +++ b/include/boost/unordered/detail/buckets.hpp @@ -41,7 +41,7 @@ namespace boost { namespace unordered { namespace detail { public: // Types - typedef BOOST_DEDUCED_TYPENAME ::boost::detail::if_true:: + typedef typename ::boost::detail::if_true:: BOOST_NESTED_TEMPLATE then< ::boost::unordered::detail::ungrouped_node, ::boost::unordered::detail::grouped_node @@ -49,16 +49,15 @@ namespace boost { namespace unordered { namespace detail { typedef A value_allocator; typedef ::boost::unordered::detail::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME allocator_traits::value_type value_type; + typedef typename allocator_traits::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator - bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME allocator_traits::pointer bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; + typedef typename bucket::bucket_allocator bucket_allocator; + typedef typename allocator_traits::pointer bucket_ptr; + typedef typename bucket::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME rebind_wrap::type + typedef typename rebind_wrap::type node_allocator; - typedef BOOST_DEDUCED_TYPENAME allocator_traits::pointer real_node_ptr; + typedef typename allocator_traits::pointer real_node_ptr; // Members @@ -423,7 +422,7 @@ namespace boost { namespace unordered { namespace detail { functions& operator=(functions const&); typedef compressed_pair function_pair; - typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< + typedef typename ::boost::aligned_storage< sizeof(function_pair), ::boost::alignment_of::value>::type aligned_function; @@ -515,28 +514,130 @@ namespace boost { namespace unordered { namespace detail { }; //////////////////////////////////////////////////////////////////////////// - // Node Constructors + // + // Value Construction - template - struct emulated_pair_constructor - { - enum { value = false }; - }; - - template - struct emulated_pair_constructor, void> - { - enum { value = true }; - }; - - template - struct emulated_pair_constructor, Value> - { +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \ + template \ + void construct_from_tuple(T* ptr, namespace_::tuple<>) \ + { \ + new ((void*) ptr) T(); \ + } \ + \ + BOOST_PP_REPEAT_FROM_TO(1, n, \ + BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_) + +#define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \ + template\ + void construct_from_tuple(T* ptr, \ + namespace_::tuple const& x) \ + { \ + new ((void*) ptr) T( \ + BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \ + ); \ + } + +#define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \ + namespace_::get(x) + +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost) + +#if !defined(BOOST_NO_0X_HDR_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std) +#elif defined(BOOST_HAS_TR1_TUPLE) +BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::tr1) +#endif + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct emulation1 { static choice1::type check(choice1, std::pair const&); static choice2::type check(choice2, A const&); - - enum { value = sizeof(check(choose(), make())) - 1 }; + + enum { value = sizeof(check(choose(), make())) == sizeof(choice2::type) }; }; +#endif + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct check3_base { + static choice1::type check(choice1, boost::unordered::piecewise_construct_t); + static choice2::type check(choice2, A const&); + static choice3::type check(choice3, ...); + }; +#else + template + struct check3_base { + static choice1::type check(choice1, boost::unordered::piecewise_construct_t); + static choice3::type check(choice3, ...); + }; +#endif + + template + struct piecewise3 { + enum { value = + sizeof(check3_base::check(choose(), make())) == + sizeof(choice1::type) }; + }; + + template + struct emulation3 { + enum { value = + sizeof(check3_base::check(choose(), make())) == + sizeof(choice2::type) }; + }; + + template + struct normal3 { + enum { value = + sizeof(check3_base::check(choose(), make())) == + sizeof(choice3::type) }; + }; + + template + struct pair_construct1 {}; + template + struct normal_construct1 { typedef void type; }; + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct pair_construct1, Arg1> + : enable_if, void> {}; + + template + struct normal_construct1, Arg1> + : disable_if, void> {}; +#endif + + template + struct piecewise_construct3 {}; + template + struct piecewise_construct3, Arg1> + : enable_if, void> {}; + + template + struct pair_construct3 {}; + template + struct pair_construct3, Arg1> + : enable_if, void> {}; + + template + struct normal_construct3 { typedef void type; }; + template + struct normal_construct3, Arg1> + : enable_if, void> {}; + + template + struct pair_construct_n {}; + template + struct normal_construct_n { typedef void type; }; + +#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + template + struct pair_construct_n > { typedef void type; }; + template + struct normal_construct_n > {}; +#endif template inline void construct_impl(void* address) @@ -544,110 +645,135 @@ namespace boost { namespace unordered { namespace detail { new(address) T(); } -#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) - template - inline void construct_impl( - typename boost::disable_if, - void*>::type address, - Arg1&& a1) + inline typename normal_construct1::type + construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1) { - new(address) T(std::forward(a1)); + new(address) T( + boost::forward(arg1) + ); } template - inline void construct_impl( - typename boost::enable_if, - void*>::type address, - Arg1&& a1) + inline typename pair_construct1::type + construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1) { - new(address) T(std::forward(a1), typename T::second_type()); - } + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(arg1)); + new((void*)(&static_cast(address)->second)) + typename T::second_type(); + } template - inline void construct_impl(void* address, Arg1&& a1, Arg2&& a2) + inline void construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2) { - new(address) T(std::forward(a1), std::forward(a2)); + new(address) T( + boost::forward(arg1), + boost::forward(arg2)); } - template - inline typename boost::disable_if, void>::type - construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Args&&... args) + template + inline typename piecewise_construct3::type + construct_impl(void* address, BOOST_FWD_REF(Arg1), + BOOST_FWD_REF(Arg2) arg2, BOOST_FWD_REF(Arg3) arg3) { - new(address) T(std::forward(arg1), std::forward(arg2), + construct_from_tuple(&static_cast(address)->first, arg2); + construct_from_tuple(&static_cast(address)->second, arg3); + } + + template + inline typename pair_construct3::type + construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2, BOOST_FWD_REF(Arg3) arg3) + { + new((void*)(&static_cast(address)->first)) + typename T::first_type( + boost::forward(arg1)); + new((void*)(&static_cast(address)->second)) + typename T::second_type( + boost::forward(arg2), + boost::forward(arg3)); + } + + template + inline typename normal_construct3::type + construct_impl(void* address, BOOST_FWD_REF(Arg1) arg1, + BOOST_FWD_REF(Arg2) arg2, BOOST_FWD_REF(Arg3) arg3) + { + new(address) T( + boost::forward(arg1), + boost::forward(arg2), + boost::forward(arg3)); + } + +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + + template + inline typename normal_construct_n::type + construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, + Arg4&& arg4, Args&&... args) + { + new(address) T( + std::forward(arg1), + std::forward(arg2), + std::forward(arg3), + std::forward(arg4), std::forward(args)...); } - template - inline typename boost::enable_if, void>::type - construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Args&&... args) + template + inline typename pair_construct_n::type + construct_impl(void* address, Arg1&& arg1, Arg2&& arg2, Arg3&& arg3, + Arg4&& arg4, Args&&... args) { - new(address) T(std::forward(arg1), - typename T::second_type( - std::forward(arg2), std::forward(args)...)); + new((void*)(&static_cast(address)->first)) + typename T::first_type( + std::forward(arg1)); + new((void*)(&static_cast(address)->second)) + typename T::second_type( + std::forward(arg2), + std::forward(arg3), + std::forward(arg4), + std::forward(args)...); } #else - template - inline BOOST_DEDUCED_TYPENAME boost::disable_if, void>::type - construct_impl(void* address, BOOST_FWD_REF(Arg1) a1) - { - new(address) T(boost::forward(a1)); - } - - template - inline BOOST_DEDUCED_TYPENAME boost::enable_if, void>::type - construct_impl(void* address, BOOST_FWD_REF(Arg1) a1) - { - new(address) T( - boost::forward(a1), - BOOST_DEDUCED_TYPENAME T::second_type() - ); - } - - template - inline void construct_impl(void* address, - BOOST_FWD_REF(Arg1) a1, BOOST_FWD_REF(Arg2) a2) - { - new(address) T(boost::forward(a1), boost::forward(a2)); - } - #define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \ template < \ class T, \ BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \ > \ - inline void construct_impl( \ - BOOST_DEDUCED_TYPENAME \ - boost::disable_if, void*>::type \ - address, \ - BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \ - ) \ + inline typename normal_construct_n::type \ + construct_impl(void* address, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ new(address) T( \ BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ } - BOOST_PP_REPEAT_FROM_TO(3, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_CONSTRUCT_IMPL, _) #define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \ template \ - inline void construct_impl( \ - BOOST_DEDUCED_TYPENAME \ - boost::enable_if, void*>::type \ - address, \ - Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ + inline typename pair_construct_n::type \ + construct_impl(void* address, BOOST_FWD_REF(Key) key, \ + BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \ { \ - new(address) T(k, \ - BOOST_DEDUCED_TYPENAME \ - T::second_type(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \ + new((void*)(&static_cast(address)->first)) \ + typename T::first_type( \ + boost::forward(key)); \ + new((void*)(&static_cast(address)->second)) \ + typename T::second_type( \ + BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \ } - BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT, + BOOST_PP_REPEAT_FROM_TO(3, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _) #undef BOOST_UNORDERED_CONSTRUCT_IMPL @@ -661,10 +787,10 @@ namespace boost { namespace unordered { namespace detail { class node_constructor { typedef ::boost::unordered::detail::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; + typedef typename buckets::node node; + typedef typename buckets::real_node_ptr real_node_ptr; + typedef typename buckets::value_type value_type; + typedef typename buckets::node_allocator node_allocator; buckets& buckets_; real_node_ptr node_; @@ -731,7 +857,7 @@ namespace boost { namespace unordered { namespace detail { } // no throw - BOOST_DEDUCED_TYPENAME buckets::node_ptr release() + typename buckets::node_ptr release() { real_node_ptr p = node_; node_ = real_node_ptr(); diff --git a/include/boost/unordered/detail/equivalent.hpp b/include/boost/unordered/detail/equivalent.hpp index 66183a67..423029d7 100644 --- a/include/boost/unordered/detail/equivalent.hpp +++ b/include/boost/unordered/detail/equivalent.hpp @@ -15,19 +15,19 @@ namespace boost { namespace unordered { namespace detail { class equivalent_table : public T::table_base { public: - typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; - typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; - typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME T::table_base table_base; - typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator; + typedef typename T::hasher hasher; + typedef typename T::key_equal key_equal; + typedef typename T::value_allocator value_allocator; + typedef typename T::key_type key_type; + typedef typename T::value_type value_type; + typedef typename T::table_base table_base; + typedef typename T::node_constructor node_constructor; + typedef typename T::node_allocator node_allocator; - typedef BOOST_DEDUCED_TYPENAME T::node node; - typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; + typedef typename T::node node; + typedef typename T::node_ptr node_ptr; + typedef typename T::bucket_ptr bucket_ptr; + typedef typename T::extractor extractor; // Constructors @@ -67,7 +67,9 @@ namespace boost { namespace unordered { namespace detail { return true; } - + +#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) + static bool group_equals(node_ptr n1, node_ptr end1, node_ptr n2, node_ptr end2) { @@ -108,7 +110,28 @@ namespace boost { namespace unordered { namespace detail { return true; } - + +#else + + static bool group_equals(node_ptr n1, node_ptr end1, + node_ptr n2, node_ptr end2) + { + for(;;) + { + if(!extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; + + n1 = n1->next_; + n2 = n2->next_; + + if (n1 == end1) return n2 == end2; + if (n2 == end2) return false; + } + } + +#endif + static bool find(node_ptr n, node_ptr end, value_type const& v) { for(;n != end; n = n->next_) @@ -203,6 +226,14 @@ namespace boost { namespace unordered { namespace detail { this->find_node(bucket_index, hash, k)); } +#if defined(BOOST_NO_RVALUE_REFERENCES) + node_ptr emplace(please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return this->begin(); + } +#endif + #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template @@ -273,19 +304,18 @@ namespace boost { namespace unordered { namespace detail { template void insert_range(I i, I j) { - BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal::type - iterator_traversal_tag; - insert_for_range(i, j, iterator_traversal_tag); + insert_for_range(i, j, + BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal::type()); } }; template struct multiset : public types< - BOOST_DEDUCED_TYPENAME allocator_traits::value_type, - BOOST_DEDUCED_TYPENAME allocator_traits::value_type, + typename allocator_traits::value_type, + typename allocator_traits::value_type, H, P, A, - set_extractor::value_type>, + set_extractor::value_type>, false> { typedef equivalent_table > impl; @@ -294,9 +324,9 @@ namespace boost { namespace unordered { namespace detail { template struct multimap : public types< - K, BOOST_DEDUCED_TYPENAME allocator_traits::value_type, + K, typename allocator_traits::value_type, H, P, A, - map_extractor::value_type>, + map_extractor::value_type>, false> { typedef equivalent_table > impl; diff --git a/include/boost/unordered/detail/extract_key.hpp b/include/boost/unordered/detail/extract_key.hpp index 9f3d605d..dc9e70f8 100644 --- a/include/boost/unordered/detail/extract_key.hpp +++ b/include/boost/unordered/detail/extract_key.hpp @@ -27,6 +27,18 @@ namespace detail { template no_key(T const&) {} }; + template + struct is_key { + template + static choice1::type test(T2 const&); + static choice2::type test(Key const&); + + enum { value = sizeof(test(make())) == sizeof(choice2::type) }; + + typedef typename boost::detail::if_true:: + BOOST_NESTED_TEMPLATE then::type type; + }; + template struct set_extractor { @@ -64,8 +76,8 @@ namespace detail { return no_key(); } - template - static no_key extract(Arg const&, Arg const&) + template + static no_key extract(Arg1 const&, Arg2 const&) { return no_key(); } @@ -81,7 +93,7 @@ namespace detail { struct map_extractor { typedef ValueType value_type; - typedef BOOST_DEDUCED_TYPENAME ::boost::remove_const::type key_type; + typedef typename ::boost::remove_const::type key_type; static key_type const& extract(value_type const& v) { @@ -127,6 +139,7 @@ namespace detail { return no_key(); } #else + template static key_type const& extract(key_type const& k, Arg1 const&) { @@ -151,6 +164,54 @@ namespace detail { } #endif +#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + template \ + static no_key extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple<> const&, T2&&) \ + { \ + return no_key(); \ + } \ + \ + template \ + static typename is_key::type \ + extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple const& k, T2&&) \ + { \ + return typename is_key::type( \ + namespace_::get<0>(k)); \ + } + +#else + +#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \ + static no_key extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple<> const&) \ + { \ + return no_key(); \ + } \ + \ + template \ + static typename is_key::type \ + extract(boost::unordered::piecewise_construct_t, \ + namespace_::tuple const& k) \ + { \ + return typename is_key::type( \ + namespace_::get<0>(k)); \ + } + +#endif + +BOOST_UNORDERED_KEY_FROM_TUPLE(boost) + +#if !defined(BOOST_NO_0X_HDR_TUPLE) +BOOST_UNORDERED_KEY_FROM_TUPLE(std) +#elif defined(BOOST_HAS_TR1_TUPLE) +BOOST_UNORDERED_KEY_FROM_TUPLE(std::tr1) +#endif + + static bool compare_mapped(value_type const& x, value_type const& y) { return x.second == y.second; diff --git a/include/boost/unordered/detail/fwd.hpp b/include/boost/unordered/detail/fwd.hpp index 8185e4f5..395b4057 100644 --- a/include/boost/unordered/detail/fwd.hpp +++ b/include/boost/unordered/detail/fwd.hpp @@ -44,6 +44,9 @@ namespace unordered class P = std::equal_to, class A = std::allocator > class unordered_multiset; + + struct piecewise_construct_t {}; + const piecewise_construct_t piecewise_construct = piecewise_construct_t(); } } diff --git a/include/boost/unordered/detail/node.hpp b/include/boost/unordered/detail/node.hpp index 060cfd30..ab2adb3f 100644 --- a/include/boost/unordered/detail/node.hpp +++ b/include/boost/unordered/detail/node.hpp @@ -59,11 +59,9 @@ namespace boost { namespace unordered { namespace detail { { bucket& operator=(bucket const&); public: - typedef BOOST_DEDUCED_TYPENAME - ::boost::unordered::detail::rebind_wrap::type + typedef typename ::boost::unordered::detail::rebind_wrap::type bucket_allocator; - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::pointer bucket_ptr; + typedef typename allocator_traits::pointer bucket_ptr; typedef bucket_ptr node_ptr; node_ptr next_; @@ -77,7 +75,7 @@ namespace boost { namespace unordered { namespace detail { struct value_base { typedef ValueType value_type; - BOOST_DEDUCED_TYPENAME ::boost::aligned_storage< + typename ::boost::aligned_storage< sizeof(value_type), ::boost::alignment_of::value>::type data_; @@ -107,12 +105,12 @@ namespace boost { namespace unordered { namespace detail { template struct ungrouped_node : ::boost::unordered::detail::bucket, - value_base::value_type> + value_base::value_type> { typedef ::boost::unordered::detail::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME allocator_traits::value_type value_type; + typedef typename bucket::bucket_ptr bucket_ptr; + typedef typename bucket::node_ptr node_ptr; + typedef typename allocator_traits::value_type value_type; std::size_t hash_; @@ -182,12 +180,12 @@ namespace boost { namespace unordered { namespace detail { template struct grouped_node : ::boost::unordered::detail::bucket, - value_base::value_type> + value_base::value_type> { typedef ::boost::unordered::detail::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME allocator_traits::value_type value_type; + typedef typename bucket::bucket_ptr bucket_ptr; + typedef typename bucket::node_ptr node_ptr; + typedef typename allocator_traits::value_type value_type; std::size_t hash_; node_ptr group_prev_; diff --git a/include/boost/unordered/detail/table.hpp b/include/boost/unordered/detail/table.hpp index 7f3fa6bb..9780d918 100644 --- a/include/boost/unordered/detail/table.hpp +++ b/include/boost/unordered/detail/table.hpp @@ -23,22 +23,22 @@ namespace boost { namespace unordered { namespace detail { table(table const&); table& operator=(table const&); public: - typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; - typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; - typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME T::functions functions; - typedef BOOST_DEDUCED_TYPENAME T::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; - typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; + typedef typename T::hasher hasher; + typedef typename T::key_equal key_equal; + typedef typename T::value_allocator value_allocator; + typedef typename T::key_type key_type; + typedef typename T::value_type value_type; + typedef typename T::functions functions; + typedef typename T::buckets buckets; + typedef typename T::extractor extractor; + typedef typename T::node_constructor node_constructor; - typedef BOOST_DEDUCED_TYPENAME T::node node; - typedef BOOST_DEDUCED_TYPENAME T::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator; - typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair; + typedef typename T::node node; + typedef typename T::bucket bucket; + typedef typename T::node_ptr node_ptr; + typedef typename T::bucket_ptr bucket_ptr; + typedef typename T::node_allocator node_allocator; + typedef typename T::iterator_pair iterator_pair; // Members @@ -485,11 +485,11 @@ namespace boost { namespace unordered { namespace detail { typedef ::boost::unordered::detail::buckets buckets; typedef ::boost::unordered::detail::functions functions; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::bucket bucket; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator; + typedef typename buckets::node node; + typedef typename buckets::bucket bucket; + typedef typename buckets::node_ptr node_ptr; + typedef typename buckets::bucket_ptr bucket_ptr; + typedef typename buckets::node_allocator node_allocator; typedef std::pair iterator_pair; }; @@ -514,18 +514,18 @@ namespace boost { namespace unordered { namespace iterator_detail { class l_iterator : public ::boost::iterator < std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type, + typename boost::unordered::detail::allocator_traits::value_type, std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::pointer, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type&> + typename boost::unordered::detail::allocator_traits::pointer, + typename boost::unordered::detail::allocator_traits::value_type&> { public: - typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type value_type; + typedef typename boost::unordered::detail::allocator_traits::value_type value_type; private: typedef ::boost::unordered::detail::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef typename buckets::node_ptr node_ptr; + typedef typename buckets::node node; typedef cl_iterator const_local_iterator; friend class cl_iterator; @@ -538,7 +538,7 @@ namespace boost { namespace unordered { namespace iterator_detail { l_iterator() : ptr_() {} l_iterator(node_ptr x, std::size_t b, std::size_t c) : ptr_(x), bucket_(b), bucket_count_(c) {} - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type& operator*() const { + typename boost::unordered::detail::allocator_traits::value_type& operator*() const { return node::get_value(ptr_); } value_type* operator->() const { @@ -575,18 +575,18 @@ namespace boost { namespace unordered { namespace iterator_detail { class cl_iterator : public ::boost::iterator < std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type, + typename boost::unordered::detail::allocator_traits::value_type, std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::const_pointer, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type const& > + typename boost::unordered::detail::allocator_traits::const_pointer, + typename boost::unordered::detail::allocator_traits::value_type const& > { public: - typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type value_type; + typedef typename boost::unordered::detail::allocator_traits::value_type value_type; private: typedef ::boost::unordered::detail::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; + typedef typename buckets::node_ptr node_ptr; + typedef typename buckets::node node; typedef l_iterator local_iterator; friend class l_iterator; @@ -602,7 +602,7 @@ namespace boost { namespace unordered { namespace iterator_detail { cl_iterator(local_iterator x) : ptr_(x.ptr_), bucket_(x.bucket_), bucket_count_(x.bucket_count_) {} - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type const& + typename boost::unordered::detail::allocator_traits::value_type const& operator*() const { return node::get_value(ptr_); } @@ -640,18 +640,18 @@ namespace boost { namespace unordered { namespace iterator_detail { class iterator : public ::boost::iterator < std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type, + typename boost::unordered::detail::allocator_traits::value_type, std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::pointer, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type& > + typename boost::unordered::detail::allocator_traits::pointer, + typename boost::unordered::detail::allocator_traits::value_type& > { public: - typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type value_type; + typedef typename boost::unordered::detail::allocator_traits::value_type value_type; private: typedef ::boost::unordered::detail::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef typename buckets::node node; + typedef typename buckets::node_ptr node_ptr; typedef c_iterator const_iterator; friend class c_iterator; node_ptr node_; @@ -660,7 +660,7 @@ namespace boost { namespace unordered { namespace iterator_detail { iterator() : node_() {} explicit iterator(node_ptr const& x) : node_(x) {} - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type& operator*() const { + typename boost::unordered::detail::allocator_traits::value_type& operator*() const { return node::get_value(node_); } value_type* operator->() const { @@ -690,18 +690,18 @@ namespace boost { namespace unordered { namespace iterator_detail { class c_iterator : public ::boost::iterator < std::forward_iterator_tag, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type, + typename boost::unordered::detail::allocator_traits::value_type, std::ptrdiff_t, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::const_pointer, - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type const& > + typename boost::unordered::detail::allocator_traits::const_pointer, + typename boost::unordered::detail::allocator_traits::value_type const& > { public: - typedef BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type value_type; + typedef typename boost::unordered::detail::allocator_traits::value_type value_type; private: typedef ::boost::unordered::detail::buckets buckets; - typedef BOOST_DEDUCED_TYPENAME buckets::node node; - typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr; + typedef typename buckets::node node; + typedef typename buckets::node_ptr node_ptr; typedef ::boost::unordered::iterator_detail::iterator iterator; friend class ::boost::unordered::iterator_detail::iterator; @@ -726,7 +726,7 @@ namespace boost { namespace unordered { namespace iterator_detail { c_iterator() : node_() {} explicit c_iterator(node_ptr const& x) : node_(x) {} c_iterator(iterator const& x) : node_(x.node_) {} - BOOST_DEDUCED_TYPENAME boost::unordered::detail::allocator_traits::value_type const& operator*() const { + typename boost::unordered::detail::allocator_traits::value_type const& operator*() const { return node::get_value(node_); } value_type const* operator->() const { diff --git a/include/boost/unordered/detail/unique.hpp b/include/boost/unordered/detail/unique.hpp index 38dcba9c..e0deb5f4 100644 --- a/include/boost/unordered/detail/unique.hpp +++ b/include/boost/unordered/detail/unique.hpp @@ -15,19 +15,19 @@ namespace boost { namespace unordered { namespace detail { class unique_table : public T::table_base { public: - typedef BOOST_DEDUCED_TYPENAME T::hasher hasher; - typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal; - typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator; - typedef BOOST_DEDUCED_TYPENAME T::key_type key_type; - typedef BOOST_DEDUCED_TYPENAME T::value_type value_type; - typedef BOOST_DEDUCED_TYPENAME T::table_base table_base; - typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor; - typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator; + typedef typename T::hasher hasher; + typedef typename T::key_equal key_equal; + typedef typename T::value_allocator value_allocator; + typedef typename T::key_type key_type; + typedef typename T::value_type value_type; + typedef typename T::table_base table_base; + typedef typename T::node_constructor node_constructor; + typedef typename T::node_allocator node_allocator; - typedef BOOST_DEDUCED_TYPENAME T::node node; - typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr; - typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr; - typedef BOOST_DEDUCED_TYPENAME T::extractor extractor; + typedef typename T::node node; + typedef typename T::node_ptr node_ptr; + typedef typename T::bucket_ptr bucket_ptr; + typedef typename T::extractor extractor; typedef std::pair emplace_return; @@ -60,8 +60,15 @@ namespace boost { namespace unordered { namespace detail { n1; n1 = n1->next_) { node_ptr n2 = other.find_matching_node(n1); + +#if !defined(BOOST_UNORDERED_DEPRECATED_EQUALITY) if(!n2 || node::get_value(n1) != node::get_value(n2)) return false; +#else + if(!n2 || !extractor::compare_mapped( + node::get_value(n1), node::get_value(n2))) + return false; +#endif } return true; @@ -111,7 +118,7 @@ namespace boost { namespace unordered { namespace detail { value_type& operator[](key_type const& k) { - typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type; + typedef typename value_type::second_type mapped_type; std::size_t hash = this->hash_function()(k); std::size_t bucket_index = hash % this->bucket_count_; @@ -189,6 +196,14 @@ namespace boost { namespace unordered { namespace detail { } +#if defined(BOOST_NO_RVALUE_REFERENCES) + emplace_return emplace(please_ignore_this_overload const&) + { + BOOST_ASSERT(false); + return emplace_return(this->begin(), false); + } +#endif + #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template @@ -392,10 +407,10 @@ namespace boost { namespace unordered { namespace detail { template struct set : public types< - BOOST_DEDUCED_TYPENAME allocator_traits::value_type, - BOOST_DEDUCED_TYPENAME allocator_traits::value_type, + typename allocator_traits::value_type, + typename allocator_traits::value_type, H, P, A, - set_extractor::value_type>, + set_extractor::value_type>, true> { typedef ::boost::unordered::detail::unique_table > impl; @@ -404,9 +419,9 @@ namespace boost { namespace unordered { namespace detail { template struct map : public types< - K, BOOST_DEDUCED_TYPENAME allocator_traits::value_type, + K, typename allocator_traits::value_type, H, P, A, - map_extractor::value_type>, + map_extractor::value_type>, true> { typedef ::boost::unordered::detail::unique_table > impl; diff --git a/include/boost/unordered/detail/util.hpp b/include/boost/unordered/detail/util.hpp index d944a415..22b5b539 100644 --- a/include/boost/unordered/detail/util.hpp +++ b/include/boost/unordered/detail/util.hpp @@ -23,13 +23,23 @@ #include #include #include +#if defined(BOOST_NO_RVALUE_REFERENCES) +#include +#endif #include -#include -#include -#include -#include #include #include +#include +#include +#include +#include +#include +#include +#include +#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE) +#include +#endif +#include // Template parameters: // @@ -121,6 +131,36 @@ namespace boost { namespace unordered { namespace detail { #if defined(BOOST_MSVC) #pragma warning(pop) +#endif + +#if !defined(BOOST_NO_RVALUE_REFERENCES) + +#define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T) + +#else + + struct please_ignore_this_overload { + typedef please_ignore_this_overload type; + }; + + template + struct rv_ref_impl { + typedef BOOST_RV_REF(T) type; + }; + + template + struct rv_ref : + boost::detail::if_true< + boost::is_class::value + >::BOOST_NESTED_TEMPLATE then < + rv_ref_impl, + please_ignore_this_overload + >::type + {}; + +#define BOOST_UNORDERED_RV_REF(T) \ + typename ::boost::unordered::detail::rv_ref::type + #endif //////////////////////////////////////////////////////////////////////////// @@ -197,22 +237,6 @@ namespace boost { namespace unordered { namespace detail { return *bound; } - //////////////////////////////////////////////////////////////////////////// - // pair_cast - because some libraries don't have the full pair constructors. - -#if 0 - template - inline std::pair pair_cast(std::pair const& x) - { - return std::pair(Dst1(x.first), Dst2(x.second)); - } - -#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \ - ::boost::unordered::detail::pair_cast(Argument) -#else -#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \ - Argument -#endif //////////////////////////////////////////////////////////////////////////// // insert_size/initial_size @@ -242,9 +266,8 @@ namespace boost { namespace unordered { namespace detail { template inline std::size_t insert_size(I i, I j) { - BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal::type - iterator_traversal_tag; - return insert_size(i, j, iterator_traversal_tag); + return insert_size(i, j, + typename ::boost::iterator_traversal::type()); } template @@ -295,8 +318,8 @@ namespace boost { namespace unordered { namespace detail { : private generate_base::type, private generate_base::type { - typedef BOOST_DEDUCED_TYPENAME generate_base::type base1; - typedef BOOST_DEDUCED_TYPENAME generate_base::type base2; + typedef typename generate_base::type base1; + typedef typename generate_base::type base2; typedef T1 first_type; typedef T2 second_type; diff --git a/include/boost/unordered/unordered_map.hpp b/include/boost/unordered/unordered_map.hpp index 389f434f..aa261e88 100644 --- a/include/boost/unordered/unordered_map.hpp +++ b/include/boost/unordered/unordered_map.hpp @@ -52,24 +52,21 @@ namespace unordered private: #endif - typedef BOOST_DEDUCED_TYPENAME - ::boost::unordered::detail::rebind_wrap< + typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; typedef ::boost::unordered::detail::allocator_traits allocator_traits; typedef ::boost::unordered::detail::map types; - typedef BOOST_DEDUCED_TYPENAME types::impl table; + typedef typename types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; + typedef typename types::node_ptr node_ptr; public: - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; typedef value_type& reference; typedef value_type const& const_reference; @@ -135,9 +132,7 @@ namespace unordered unordered_map(unordered_map const&); -#if BOOST_UNORDERED_USE_RV_REF - unordered_map& operator=( - BOOST_RV_REF(unordered_map) x) + unordered_map& operator=(BOOST_RV_REF(unordered_map) x) { table_.move_assign(x.table_); return *this; @@ -147,7 +142,6 @@ namespace unordered : table_(other.table_, ::boost::unordered::detail::move_tag()) { } -#endif #if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_map(unordered_map&&, allocator_type const&); @@ -260,11 +254,10 @@ namespace unordered #endif std::pair insert(value_type const&); - iterator insert(const_iterator, value_type const&); -#if BOOST_UNORDERED_USE_RV_REF std::pair insert(BOOST_RV_REF(value_type)); + iterator insert(const_iterator, value_type const&); iterator insert(const_iterator, BOOST_RV_REF(value_type)); -#endif + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -403,8 +396,7 @@ namespace unordered private: #endif - typedef BOOST_DEDUCED_TYPENAME - ::boost::unordered::detail::rebind_wrap< + typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; typedef ::boost::unordered::detail::allocator_traits @@ -412,16 +404,14 @@ namespace unordered typedef ::boost::unordered::detail::multimap types; - typedef BOOST_DEDUCED_TYPENAME types::impl table; + typedef typename types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; + typedef typename types::node_ptr node_ptr; public: - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; typedef value_type& reference; typedef value_type const& const_reference; @@ -487,9 +477,7 @@ namespace unordered unordered_multimap(unordered_multimap const&); -#if BOOST_UNORDERED_USE_RV_REF - unordered_multimap& operator=( - BOOST_RV_REF(unordered_multimap) x) + unordered_multimap& operator=(BOOST_RV_REF(unordered_multimap) x) { table_.move_assign(x.table_); return *this; @@ -499,7 +487,6 @@ namespace unordered : table_(other.table_, ::boost::unordered::detail::move_tag()) { } -#endif #if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_multimap(unordered_multimap&&, allocator_type const&); @@ -612,11 +599,10 @@ namespace unordered #endif iterator insert(value_type const&); - iterator insert(const_iterator, value_type const&); -#if BOOST_UNORDERED_USE_RV_REF iterator insert(BOOST_RV_REF(value_type)); + iterator insert(const_iterator, value_type const&); iterator insert(const_iterator, BOOST_RV_REF(value_type)); -#endif + template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -851,16 +837,15 @@ namespace unordered #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_map::emplace(Args&&... args) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(std::forward(args)...)); + return table_.emplace(std::forward(args)...); } template template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::emplace_hint(const_iterator, Args&&... args) { return iterator(table_.emplace(std::forward(args)...).first); @@ -869,18 +854,17 @@ namespace unordered #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_map::emplace( boost::unordered::detail::empty_emplace, value_type v ) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(boost::move(v))); + return table_.emplace(boost::move(v)); } template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::emplace_hint(const_iterator, boost::unordered::detail::empty_emplace, value_type v @@ -895,23 +879,18 @@ namespace unordered template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - std::pair< \ - BOOST_DEDUCED_TYPENAME unordered_map::iterator, \ - bool> \ + std::pair::iterator, bool> \ unordered_map::emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ { \ - return \ - BOOST_UNORDERED_PAIR_CAST(iterator, bool, \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + return table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ } \ \ template \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - BOOST_DEDUCED_TYPENAME unordered_map::iterator \ + typename unordered_map::iterator \ unordered_map::emplace_hint( \ const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ @@ -929,38 +908,34 @@ namespace unordered #endif template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_map::insert(value_type const& obj) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(obj)); + return table_.emplace(obj); } template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::insert(const_iterator, value_type const& obj) { return iterator(table_.emplace(obj).first); } -#if BOOST_UNORDERED_USE_RV_REF template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_map::insert(BOOST_RV_REF(value_type) obj) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(boost::move(obj))); + return table_.emplace(boost::move(obj)); } template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::insert(const_iterator, BOOST_RV_REF(value_type) obj) { return iterator(table_.emplace(boost::move(obj)).first); } -#endif template template @@ -979,21 +954,21 @@ namespace unordered #endif template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::erase(const_iterator position) { return iterator(table_.erase(position.node_)); } template - BOOST_DEDUCED_TYPENAME unordered_map::size_type + typename unordered_map::size_type unordered_map::erase(const key_type& k) { return table_.erase_key(k); } template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::erase( const_iterator first, const_iterator last) { @@ -1015,35 +990,35 @@ namespace unordered // observers template - BOOST_DEDUCED_TYPENAME unordered_map::hasher + typename unordered_map::hasher unordered_map::hash_function() const { return table_.hash_function(); } template - BOOST_DEDUCED_TYPENAME unordered_map::key_equal + typename unordered_map::key_equal unordered_map::key_eq() const { return table_.key_eq(); } template - BOOST_DEDUCED_TYPENAME unordered_map::mapped_type& + typename unordered_map::mapped_type& unordered_map::operator[](const key_type &k) { return table_[k].second; } template - BOOST_DEDUCED_TYPENAME unordered_map::mapped_type& + typename unordered_map::mapped_type& unordered_map::at(const key_type& k) { return table_.at(k).second; } template - BOOST_DEDUCED_TYPENAME unordered_map::mapped_type const& + typename unordered_map::mapped_type const& unordered_map::at(const key_type& k) const { return table_.at(k).second; @@ -1052,14 +1027,14 @@ namespace unordered // lookup template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::find(const key_type& k) { return iterator(table_.find_node(k)); } template - BOOST_DEDUCED_TYPENAME unordered_map::const_iterator + typename unordered_map::const_iterator unordered_map::find(const key_type& k) const { return const_iterator(table_.find_node(k)); @@ -1068,7 +1043,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_map::iterator + typename unordered_map::iterator unordered_map::find( CompatibleKey const& k, CompatibleHash const& hash, @@ -1080,7 +1055,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_map::const_iterator + typename unordered_map::const_iterator unordered_map::find( CompatibleKey const& k, CompatibleHash const& hash, @@ -1090,7 +1065,7 @@ namespace unordered } template - BOOST_DEDUCED_TYPENAME unordered_map::size_type + typename unordered_map::size_type unordered_map::count(const key_type& k) const { return table_.count(k); @@ -1098,26 +1073,24 @@ namespace unordered template std::pair< - BOOST_DEDUCED_TYPENAME unordered_map::iterator, - BOOST_DEDUCED_TYPENAME unordered_map::iterator> + typename unordered_map::iterator, + typename unordered_map::iterator> unordered_map::equal_range(const key_type& k) { - return BOOST_UNORDERED_PAIR_CAST(iterator, iterator, - table_.equal_range(k)); + return table_.equal_range(k); } template std::pair< - BOOST_DEDUCED_TYPENAME unordered_map::const_iterator, - BOOST_DEDUCED_TYPENAME unordered_map::const_iterator> + typename unordered_map::const_iterator, + typename unordered_map::const_iterator> unordered_map::equal_range(const key_type& k) const { - return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, - table_.equal_range(k)); + return table_.equal_range(k); } template - BOOST_DEDUCED_TYPENAME unordered_map::size_type + typename unordered_map::size_type unordered_map::bucket_size(size_type n) const { return table_.bucket_size(n); @@ -1293,7 +1266,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::emplace(Args&&... args) { return iterator(table_.emplace(std::forward(args)...)); @@ -1301,7 +1274,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::emplace_hint( const_iterator, Args&&... args) { @@ -1312,7 +1285,7 @@ namespace unordered #if !BOOST_WORKAROUND(__SUNPRO_CC, BOOST_TESTED_AT(0x5100)) template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::emplace( boost::unordered::detail::empty_emplace, value_type v @@ -1322,7 +1295,7 @@ namespace unordered } template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::emplace_hint(const_iterator, boost::unordered::detail::empty_emplace, value_type v @@ -1337,7 +1310,7 @@ namespace unordered template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator \ + typename unordered_multimap::iterator \ unordered_multimap::emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ { \ @@ -1349,7 +1322,7 @@ namespace unordered template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator \ + typename unordered_multimap::iterator \ unordered_multimap::emplace_hint( \ const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ @@ -1366,36 +1339,34 @@ namespace unordered #endif template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::insert(value_type const& obj) { return iterator(table_.emplace(obj)); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::insert( const_iterator, value_type const& obj) { return iterator(table_.emplace(obj)); } -#if BOOST_UNORDERED_USE_RV_REF template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::insert(BOOST_RV_REF(value_type) obj) { return iterator(table_.emplace(boost::move(obj))); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::insert( const_iterator, BOOST_RV_REF(value_type) obj) { return iterator(table_.emplace(boost::move(obj))); } -#endif template template @@ -1414,21 +1385,21 @@ namespace unordered #endif template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::erase(const_iterator position) { return iterator(table_.erase(position.node_)); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + typename unordered_multimap::size_type unordered_multimap::erase(const key_type& k) { return table_.erase_key(k); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::erase( const_iterator first, const_iterator last) { @@ -1450,14 +1421,14 @@ namespace unordered // observers template - BOOST_DEDUCED_TYPENAME unordered_multimap::hasher + typename unordered_multimap::hasher unordered_multimap::hash_function() const { return table_.hash_function(); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::key_equal + typename unordered_multimap::key_equal unordered_multimap::key_eq() const { return table_.key_eq(); @@ -1466,14 +1437,14 @@ namespace unordered // lookup template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::find(const key_type& k) { return iterator(table_.find_node(k)); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator + typename unordered_multimap::const_iterator unordered_multimap::find(const key_type& k) const { return const_iterator(table_.find_node(k)); @@ -1482,7 +1453,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator + typename unordered_multimap::iterator unordered_multimap::find( CompatibleKey const& k, CompatibleHash const& hash, @@ -1494,7 +1465,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator + typename unordered_multimap::const_iterator unordered_multimap::find( CompatibleKey const& k, CompatibleHash const& hash, @@ -1504,7 +1475,7 @@ namespace unordered } template - BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + typename unordered_multimap::size_type unordered_multimap::count(const key_type& k) const { return table_.count(k); @@ -1512,26 +1483,24 @@ namespace unordered template std::pair< - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator, - BOOST_DEDUCED_TYPENAME unordered_multimap::iterator> + typename unordered_multimap::iterator, + typename unordered_multimap::iterator> unordered_multimap::equal_range(const key_type& k) { - return BOOST_UNORDERED_PAIR_CAST(iterator, iterator, - table_.equal_range(k)); + return table_.equal_range(k); } template std::pair< - BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator, - BOOST_DEDUCED_TYPENAME unordered_multimap::const_iterator> + typename unordered_multimap::const_iterator, + typename unordered_multimap::const_iterator> unordered_multimap::equal_range(const key_type& k) const { - return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, - table_.equal_range(k)); + return table_.equal_range(k); } template - BOOST_DEDUCED_TYPENAME unordered_multimap::size_type + typename unordered_multimap::size_type unordered_multimap::bucket_size(size_type n) const { return table_.bucket_size(n); diff --git a/include/boost/unordered/unordered_set.hpp b/include/boost/unordered/unordered_set.hpp index a42cca30..1d1b346d 100644 --- a/include/boost/unordered/unordered_set.hpp +++ b/include/boost/unordered/unordered_set.hpp @@ -52,8 +52,7 @@ namespace unordered private: #endif - typedef BOOST_DEDUCED_TYPENAME - ::boost::unordered::detail::rebind_wrap< + typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; typedef ::boost::unordered::detail::allocator_traits @@ -61,16 +60,14 @@ namespace unordered typedef ::boost::unordered::detail::set types; - typedef BOOST_DEDUCED_TYPENAME types::impl table; + typedef typename types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; + typedef typename types::node_ptr node_ptr; public: - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; typedef value_type& reference; typedef value_type const& const_reference; @@ -134,9 +131,7 @@ namespace unordered unordered_set(unordered_set const&); -#if BOOST_UNORDERED_USE_RV_REF - unordered_set& operator=( - BOOST_RV_REF(unordered_set) x) + unordered_set& operator=(BOOST_RV_REF(unordered_set) x) { table_.move_assign(x.table_); return *this; @@ -146,7 +141,6 @@ namespace unordered : table_(other.table_, ::boost::unordered::detail::move_tag()) { } -#endif #if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_set(unordered_set&&, allocator_type const&); @@ -257,11 +251,9 @@ namespace unordered #endif std::pair insert(value_type const&); + std::pair insert(BOOST_UNORDERED_RV_REF(value_type)); iterator insert(const_iterator, value_type const&); -#if BOOST_UNORDERED_USE_RV_REF - std::pair insert(BOOST_RV_REF(value_type)); - iterator insert(const_iterator, BOOST_RV_REF(value_type)); -#endif + iterator insert(const_iterator, BOOST_UNORDERED_RV_REF(value_type)); template void insert(InputIt, InputIt); #if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST) @@ -384,8 +376,7 @@ namespace unordered private: #endif - typedef BOOST_DEDUCED_TYPENAME - ::boost::unordered::detail::rebind_wrap< + typedef typename ::boost::unordered::detail::rebind_wrap< allocator_type, value_type>::type value_allocator; typedef ::boost::unordered::detail::allocator_traits @@ -393,16 +384,14 @@ namespace unordered typedef ::boost::unordered::detail::multiset types; - typedef BOOST_DEDUCED_TYPENAME types::impl table; + typedef typename types::impl table; - typedef BOOST_DEDUCED_TYPENAME types::node_ptr node_ptr; + typedef typename types::node_ptr node_ptr; public: - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::pointer pointer; - typedef BOOST_DEDUCED_TYPENAME - allocator_traits::const_pointer const_pointer; + typedef typename allocator_traits::pointer pointer; + typedef typename allocator_traits::const_pointer const_pointer; typedef value_type& reference; typedef value_type const& const_reference; @@ -466,9 +455,7 @@ namespace unordered unordered_multiset(unordered_multiset const&); -#if BOOST_UNORDERED_USE_RV_REF - unordered_multiset& operator=( - BOOST_RV_REF(unordered_multiset) x) + unordered_multiset& operator=(BOOST_RV_REF(unordered_multiset) x) { table_.move_assign(x.table_); return *this; @@ -478,7 +465,6 @@ namespace unordered : table_(other.table_, ::boost::unordered::detail::move_tag()) { } -#endif #if !defined(BOOST_NO_RVALUE_REFERENCES) unordered_multiset(unordered_multiset&&, allocator_type const&); @@ -589,11 +575,10 @@ namespace unordered #endif iterator insert(value_type const&); + iterator insert(BOOST_UNORDERED_RV_REF(value_type)); iterator insert(const_iterator, value_type const&); -#if BOOST_UNORDERED_USE_RV_REF - iterator insert(BOOST_RV_REF(value_type)); - iterator insert(const_iterator, BOOST_RV_REF(value_type)); -#endif + iterator insert(const_iterator, BOOST_UNORDERED_RV_REF(value_type)); + template void insert(InputIt, InputIt); @@ -818,16 +803,15 @@ namespace unordered #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) template template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_set::emplace(Args&&... args) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(std::forward(args)...)); + return table_.emplace(std::forward(args)...); } template template - BOOST_DEDUCED_TYPENAME unordered_set::iterator + typename unordered_set::iterator unordered_set::emplace_hint(const_iterator, Args&&... args) { return iterator(table_.emplace(std::forward(args)...).first); @@ -835,18 +819,17 @@ namespace unordered #else template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_set::emplace( boost::unordered::detail::empty_emplace, value_type v ) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(boost::move(v))); + return table_.emplace(boost::move(v)); } template - BOOST_DEDUCED_TYPENAME unordered_set::iterator + typename unordered_set::iterator unordered_set::emplace_hint(const_iterator, boost::unordered::detail::empty_emplace, value_type v @@ -860,23 +843,18 @@ namespace unordered template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - std::pair< \ - BOOST_DEDUCED_TYPENAME unordered_set::iterator, \ - bool> \ + std::pair::iterator, bool> \ unordered_set::emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ { \ - return \ - BOOST_UNORDERED_PAIR_CAST(iterator, bool, \ - table_.emplace( \ - BOOST_UNORDERED_CALL_PARAMS(z, n))); \ + return table_.emplace(BOOST_UNORDERED_CALL_PARAMS(z, n)); \ } \ \ template \ template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - BOOST_DEDUCED_TYPENAME unordered_set::iterator \ + typename unordered_set::iterator \ unordered_set::emplace_hint( \ const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n) \ @@ -894,38 +872,34 @@ namespace unordered #endif template - std::pair::iterator, bool> + std::pair::iterator, bool> unordered_set::insert(value_type const& obj) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(obj)); + return table_.emplace(obj); } template - BOOST_DEDUCED_TYPENAME unordered_set::iterator + typename unordered_set::iterator unordered_set::insert(const_iterator, value_type const& obj) { return iterator(table_.emplace(obj).first); } -#if BOOST_UNORDERED_USE_RV_REF template - std::pair::iterator, bool> - unordered_set::insert(BOOST_RV_REF(value_type) obj) + std::pair::iterator, bool> + unordered_set::insert(BOOST_UNORDERED_RV_REF(value_type) obj) { - return BOOST_UNORDERED_PAIR_CAST(iterator, bool, - table_.emplace(boost::move(obj))); + return table_.emplace(boost::move(obj)); } template - BOOST_DEDUCED_TYPENAME unordered_set::iterator + typename unordered_set::iterator unordered_set::insert(const_iterator, - BOOST_RV_REF(value_type) obj) + BOOST_UNORDERED_RV_REF(value_type) obj) { return iterator(table_.emplace(boost::move(obj)).first); } -#endif template template @@ -943,21 +917,21 @@ namespace unordered #endif template - BOOST_DEDUCED_TYPENAME unordered_set::iterator + typename unordered_set::iterator unordered_set::erase(const_iterator position) { return iterator(table_.erase(position.node_)); } template - BOOST_DEDUCED_TYPENAME unordered_set::size_type + typename unordered_set::size_type unordered_set::erase(const key_type& k) { return table_.erase_key(k); } template - BOOST_DEDUCED_TYPENAME unordered_set::iterator + typename unordered_set::iterator unordered_set::erase(const_iterator first, const_iterator last) { return iterator(table_.erase_range(first.node_, last.node_)); @@ -978,14 +952,14 @@ namespace unordered // observers template - BOOST_DEDUCED_TYPENAME unordered_set::hasher + typename unordered_set::hasher unordered_set::hash_function() const { return table_.hash_function(); } template - BOOST_DEDUCED_TYPENAME unordered_set::key_equal + typename unordered_set::key_equal unordered_set::key_eq() const { return table_.key_eq(); @@ -994,7 +968,7 @@ namespace unordered // lookup template - BOOST_DEDUCED_TYPENAME unordered_set::const_iterator + typename unordered_set::const_iterator unordered_set::find(const key_type& k) const { return const_iterator(table_.find_node(k)); @@ -1003,7 +977,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_set::const_iterator + typename unordered_set::const_iterator unordered_set::find( CompatibleKey const& k, CompatibleHash const& hash, @@ -1013,7 +987,7 @@ namespace unordered } template - BOOST_DEDUCED_TYPENAME unordered_set::size_type + typename unordered_set::size_type unordered_set::count(const key_type& k) const { return table_.count(k); @@ -1021,16 +995,15 @@ namespace unordered template std::pair< - BOOST_DEDUCED_TYPENAME unordered_set::const_iterator, - BOOST_DEDUCED_TYPENAME unordered_set::const_iterator> + typename unordered_set::const_iterator, + typename unordered_set::const_iterator> unordered_set::equal_range(const key_type& k) const { - return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, - table_.equal_range(k)); + return table_.equal_range(k); } template - BOOST_DEDUCED_TYPENAME unordered_set::size_type + typename unordered_set::size_type unordered_set::bucket_size(size_type n) const { return table_.bucket_size(n); @@ -1206,7 +1179,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::emplace(Args&&... args) { return iterator(table_.emplace(std::forward(args)...)); @@ -1214,7 +1187,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::emplace_hint( const_iterator, Args&&... args) { @@ -1224,7 +1197,7 @@ namespace unordered #else template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::emplace( boost::unordered::detail::empty_emplace, value_type v @@ -1234,7 +1207,7 @@ namespace unordered } template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::emplace_hint(const_iterator, boost::unordered::detail::empty_emplace, value_type v @@ -1248,7 +1221,7 @@ namespace unordered template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator \ + typename unordered_multiset::iterator \ unordered_multiset::emplace( \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ { \ @@ -1260,7 +1233,7 @@ namespace unordered template < \ BOOST_UNORDERED_TEMPLATE_ARGS(z, n) \ > \ - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator \ + typename unordered_multiset::iterator \ unordered_multiset::emplace_hint( \ const_iterator, \ BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \ @@ -1277,36 +1250,34 @@ namespace unordered #endif template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::insert(value_type const& obj) { return iterator(table_.emplace(obj)); } template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::insert(const_iterator, value_type const& obj) { return iterator(table_.emplace(obj)); } -#if BOOST_UNORDERED_USE_RV_REF template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator - unordered_multiset::insert(BOOST_RV_REF(value_type) obj) + typename unordered_multiset::iterator + unordered_multiset::insert(BOOST_UNORDERED_RV_REF(value_type) obj) { return iterator(table_.emplace(boost::move(obj))); } template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::insert(const_iterator, - BOOST_RV_REF(value_type) obj) + BOOST_UNORDERED_RV_REF(value_type) obj) { return iterator(table_.emplace(boost::move(obj))); } -#endif template template @@ -1324,21 +1295,21 @@ namespace unordered #endif template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::erase(const_iterator position) { return iterator(table_.erase(position.node_)); } template - BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + typename unordered_multiset::size_type unordered_multiset::erase(const key_type& k) { return table_.erase_key(k); } template - BOOST_DEDUCED_TYPENAME unordered_multiset::iterator + typename unordered_multiset::iterator unordered_multiset::erase(const_iterator first, const_iterator last) { return iterator(table_.erase_range(first.node_, last.node_)); @@ -1359,14 +1330,14 @@ namespace unordered // observers template - BOOST_DEDUCED_TYPENAME unordered_multiset::hasher + typename unordered_multiset::hasher unordered_multiset::hash_function() const { return table_.hash_function(); } template - BOOST_DEDUCED_TYPENAME unordered_multiset::key_equal + typename unordered_multiset::key_equal unordered_multiset::key_eq() const { return table_.key_eq(); @@ -1375,7 +1346,7 @@ namespace unordered // lookup template - BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator + typename unordered_multiset::const_iterator unordered_multiset::find(const key_type& k) const { return const_iterator(table_.find_node(k)); @@ -1384,7 +1355,7 @@ namespace unordered template template - BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator + typename unordered_multiset::const_iterator unordered_multiset::find( CompatibleKey const& k, CompatibleHash const& hash, @@ -1394,7 +1365,7 @@ namespace unordered } template - BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + typename unordered_multiset::size_type unordered_multiset::count(const key_type& k) const { return table_.count(k); @@ -1402,16 +1373,15 @@ namespace unordered template std::pair< - BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator, - BOOST_DEDUCED_TYPENAME unordered_multiset::const_iterator> + typename unordered_multiset::const_iterator, + typename unordered_multiset::const_iterator> unordered_multiset::equal_range(const key_type& k) const { - return BOOST_UNORDERED_PAIR_CAST(const_iterator, const_iterator, - table_.equal_range(k)); + return table_.equal_range(k); } template - BOOST_DEDUCED_TYPENAME unordered_multiset::size_type + typename unordered_multiset::size_type unordered_multiset::bucket_size(size_type n) const { return table_.bucket_size(n); diff --git a/test/unordered/Jamfile.v2 b/test/unordered/Jamfile.v2 index 9919f61f..03d8ef9c 100644 --- a/test/unordered/Jamfile.v2 +++ b/test/unordered/Jamfile.v2 @@ -23,6 +23,7 @@ test-suite unordered [ run fwd_set_test.cpp ] [ run fwd_map_test.cpp ] [ run allocator_traits.cpp ] + [ run minimal_allocator.cpp ] [ run compile_set.cpp ] [ run compile_map.cpp ] [ run link_test_1.cpp link_test_2.cpp ] @@ -34,6 +35,9 @@ test-suite unordered [ run move_tests.cpp ] [ run assign_tests.cpp ] [ run insert_tests.cpp ] + [ run insert_tests.cpp : : + : BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT + : insert_deprecated ] [ run insert_stable_tests.cpp ] [ run unnecessary_copy_tests.cpp ] [ run erase_tests.cpp ] @@ -44,5 +48,6 @@ test-suite unordered [ run load_factor_tests.cpp ] [ run rehash_tests.cpp ] [ run equality_tests.cpp ] + [ run equality_deprecated.cpp ] [ run swap_tests.cpp ] ; diff --git a/test/unordered/compile_set.cpp b/test/unordered/compile_set.cpp index fd02cf38..602e1968 100644 --- a/test/unordered/compile_set.cpp +++ b/test/unordered/compile_set.cpp @@ -16,7 +16,7 @@ #include "./compile_tests.hpp" // Explicit instantiation to catch compile-time errors -/* + template class boost::unordered_set< int, boost::hash, @@ -27,7 +27,7 @@ template class boost::unordered_multiset< boost::hash, std::equal_to, test::minimal::allocator >; -*/ + template class boost::unordered_set< test::minimal::assignable, test::minimal::hash, diff --git a/test/unordered/equality_deprecated.cpp b/test/unordered/equality_deprecated.cpp new file mode 100644 index 00000000..826b11f4 --- /dev/null +++ b/test/unordered/equality_deprecated.cpp @@ -0,0 +1,173 @@ + +// Copyright 2008-2009 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) + +#define BOOST_UNORDERED_DEPRECATED_EQUALITY + +#include "../helpers/prefix.hpp" + +#include +#include +#include +#include +#include "../helpers/test.hpp" + +namespace equality_tests +{ + struct mod_compare + { + bool alt_hash_; + + explicit mod_compare(bool alt_hash = false) : alt_hash_(alt_hash) {} + + bool operator()(int x, int y) const + { + return x % 1000 == y % 1000; + } + + int operator()(int x) const + { + return alt_hash_ ? x % 250 : (x + 5) % 250; + } + }; + +#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \ + { \ + boost::unordered_set set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ + } + +#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \ + { \ + boost::unordered_multiset \ + set1, set2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \ + BOOST_TEST(set1 op set2); \ + } + +#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \ + { \ + boost::unordered_map \ + map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_TEST(map1 op map2); \ + } + +#define UNORDERED_EQUALITY_MULTIMAP_TEST(seq1, op, seq2) \ + { \ + boost::unordered_multimap \ + map1, map2; \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \ + BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \ + BOOST_TEST(map1 op map2); \ + } + +#define UNORDERED_SET_INSERT(r, set, item) set.insert(item); +#define UNORDERED_MAP_INSERT(r, map, item) \ + map.insert(std::pair BOOST_PP_SEQ_TO_TUPLE(item)); + + UNORDERED_AUTO_TEST(equality_size_tests) + { + boost::unordered_set x1, x2; + BOOST_TEST(x1 == x2); + BOOST_TEST(!(x1 != x2)); + + x1.insert(1); + BOOST_TEST(x1 != x2); + BOOST_TEST(!(x1 == x2)); + BOOST_TEST(x2 != x1); + BOOST_TEST(!(x2 == x1)); + + x2.insert(1); + BOOST_TEST(x1 == x2); + BOOST_TEST(!(x1 != x2)); + + x2.insert(2); + BOOST_TEST(x1 != x2); + BOOST_TEST(!(x1 == x2)); + BOOST_TEST(x2 != x1); + BOOST_TEST(!(x2 == x1)); + } + + UNORDERED_AUTO_TEST(equality_key_value_tests) + { + UNORDERED_EQUALITY_MULTISET_TEST((1), !=, (2)) + UNORDERED_EQUALITY_SET_TEST((2), ==, (2)) + UNORDERED_EQUALITY_MAP_TEST(((1)(1))((2)(1)), !=, ((1)(1))((3)(1))) + } + + UNORDERED_AUTO_TEST(equality_collision_test) + { + UNORDERED_EQUALITY_MULTISET_TEST( + (1), !=, (501)) + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(251), !=, (1)(501)) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((251)(1))((1)(1)), !=, ((501)(1))((1)(1))) + UNORDERED_EQUALITY_MULTISET_TEST( + (1)(501), ==, (1)(501)) + UNORDERED_EQUALITY_SET_TEST( + (1)(501), ==, (501)(1)) + } + + UNORDERED_AUTO_TEST(equality_group_size_test) + { + UNORDERED_EQUALITY_MULTISET_TEST( + (10)(20)(20), !=, (10)(10)(20)) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((10)(1))((20)(1))((20)(1)), !=, + ((10)(1))((20)(1))((10)(1))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((20)(1))((10)(1))((10)(1)), ==, + ((10)(1))((20)(1))((10)(1))) + } + + UNORDERED_AUTO_TEST(equality_map_value_test) + { + UNORDERED_EQUALITY_MAP_TEST( + ((1)(1)), !=, ((1)(2))) + UNORDERED_EQUALITY_MAP_TEST( + ((1)(1)), ==, ((1)(1))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(1)), !=, ((1)(2))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(1))((1)(1)), !=, ((1)(1))((1)(2))) + UNORDERED_EQUALITY_MULTIMAP_TEST( + ((1)(2))((1)(1)), !=, ((1)(1))((1)(2))) + } + + UNORDERED_AUTO_TEST(equality_predicate_test) + { + UNORDERED_EQUALITY_SET_TEST( + (1), ==, (1001)) + UNORDERED_EQUALITY_MAP_TEST( + ((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1))) + } + + // Test that equality still works when the two containers have + // different hash functions but the same equality predicate. + + UNORDERED_AUTO_TEST(equality_different_hash_test) + { + typedef boost::unordered_set set; + set set1(0, mod_compare(false), mod_compare(false)); + set set2(0, mod_compare(true), mod_compare(true)); + BOOST_TEST(set1 == set2); + set1.insert(1); set2.insert(2); + BOOST_TEST(set1 != set2); + set1.insert(2); set2.insert(1); + BOOST_TEST(set1 == set2); + set1.insert(10); set2.insert(20); + BOOST_TEST(set1 != set2); + set1.insert(20); set2.insert(10); + BOOST_TEST(set1 == set2); + } + +} + +RUN_TESTS() diff --git a/test/unordered/insert_tests.cpp b/test/unordered/insert_tests.cpp index 2ea3a40a..54cca259 100644 --- a/test/unordered/insert_tests.cpp +++ b/test/unordered/insert_tests.cpp @@ -537,8 +537,6 @@ struct overloaded_constructor } }; -// This will actually be deprecated pretty soon. - UNORDERED_AUTO_TEST(map_emplace_test) { boost::unordered_map x; @@ -547,14 +545,15 @@ UNORDERED_AUTO_TEST(map_emplace_test) BOOST_TEST(x.find(0) != x.end() && x.find(0)->second == overloaded_constructor()); - x.emplace(1); - BOOST_TEST(x.find(1) != x.end() && - x.find(1)->second == overloaded_constructor()); - x.emplace(2, 3); BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3)); +#if defined (BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT) + x.emplace(1); + BOOST_TEST(x.find(1) != x.end() && + x.find(1)->second == overloaded_constructor()); + x.emplace(4, 5, 6); BOOST_TEST(x.find(4) != x.end() && x.find(4)->second == overloaded_constructor(5, 6)); @@ -562,6 +561,7 @@ UNORDERED_AUTO_TEST(map_emplace_test) x.emplace(7, 8, 9, 10); BOOST_TEST(x.find(7) != x.end() && x.find(7)->second == overloaded_constructor(8, 9, 10)); +#endif } UNORDERED_AUTO_TEST(set_emplace_test) @@ -593,6 +593,37 @@ UNORDERED_AUTO_TEST(set_emplace_test) BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); } +UNORDERED_AUTO_TEST(map_emplace_test2) +{ + boost::unordered_map x; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor()) != x.end() && + x.find(overloaded_constructor())->second == overloaded_constructor()); + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(1), boost::make_tuple()); + BOOST_TEST(x.find(overloaded_constructor(1)) != x.end() && + x.find(overloaded_constructor(1))->second == overloaded_constructor()); + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(2,3), boost::make_tuple(4,5,6)); + BOOST_TEST(x.find(overloaded_constructor(2,3)) != x.end() && + x.find(overloaded_constructor(2,3))->second == overloaded_constructor(4,5,6)); +} + +UNORDERED_AUTO_TEST(set_emplace_test2) +{ + boost::unordered_set > x; + std::pair check; + + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(), boost::make_tuple()); + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); + + x.clear(); + x.emplace(boost::unordered::piecewise_construct, boost::make_tuple(1), boost::make_tuple(2,3)); + check = std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));; + BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check); +} + } RUN_TESTS() diff --git a/test/unordered/minimal_allocator.cpp b/test/unordered/minimal_allocator.cpp new file mode 100644 index 00000000..7904ae9f --- /dev/null +++ b/test/unordered/minimal_allocator.cpp @@ -0,0 +1,89 @@ + +// Copyright 2011 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 +#include "../objects/test.hpp" + +template +struct SimpleAllocator +{ + typedef Tp value_type; + + SimpleAllocator() + { + } + + template SimpleAllocator(const SimpleAllocator& other) + { + } + + Tp *allocate(std::size_t n) + { + return static_cast(::operator new(n * sizeof(Tp))); + } + + void deallocate(Tp* p, std::size_t) + { + ::operator delete((void*) p); + } +}; + +template +void test_simple_allocator() +{ + test::check_instances check_; + + typedef boost::unordered::detail::allocator_traits< + SimpleAllocator > traits; + + BOOST_MPL_ASSERT((boost::is_same >)); + + BOOST_MPL_ASSERT((boost::is_same)); + + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + //BOOST_MPL_ASSERT((boost::is_same)); + //BOOST_MPL_ASSERT((boost::is_same)); + + BOOST_MPL_ASSERT((boost::is_same)); + BOOST_MPL_ASSERT((boost::is_same)); + + BOOST_TEST(!traits::propagate_on_container_copy_assignment::value); + BOOST_TEST(!traits::propagate_on_container_move_assignment::value); + BOOST_TEST(!traits::propagate_on_container_swap::value); + + // rebind_alloc + // rebind_traits + + SimpleAllocator a; + + T* ptr1 = traits::allocate(a, 1); + //T* ptr2 = traits::allocate(a, 1, static_cast(ptr1)); + + traits::construct(a, ptr1, T(10)); + //traits::construct(a, ptr2, T(30), ptr1); + + BOOST_TEST(*ptr1 == T(10)); + //BOOST_TEST(*ptr2 == T(30)); + + traits::destroy(a, ptr1); + //traits::destroy(a, ptr2); + + //traits::deallocate(a, ptr2, 1); + traits::deallocate(a, ptr1, 1); + + traits::max_size(a); +} + +int main() +{ + test_simple_allocator(); + test_simple_allocator(); + + return boost::report_errors(); +} diff --git a/test/unordered/unnecessary_copy_tests.cpp b/test/unordered/unnecessary_copy_tests.cpp index 6ebfd8b5..ee5a1eaa 100644 --- a/test/unordered/unnecessary_copy_tests.cpp +++ b/test/unordered/unnecessary_copy_tests.cpp @@ -1,4 +1,4 @@ - +#include // Copyright 2006-2009 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) @@ -327,6 +327,13 @@ namespace unnecessary_copy_tests x.emplace(); COPY_COUNT(2); MOVE_COUNT(0); + reset(); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(), + boost::make_tuple()); + COPY_COUNT(2); MOVE_COUNT(0); + + // // 1 argument // @@ -345,19 +352,23 @@ namespace unnecessary_copy_tests (defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ > 2) || \ (defined(BOOST_MSVC) && BOOST_MSVC >= 1600 ) || \ (!defined(__GNUC__) && !defined(BOOST_MSVC)) + count_copies part; reset(); std::pair a_ref(part, part); x.emplace(a_ref); COPY_COUNT(2); MOVE_COUNT(0); + #endif #if defined(BOOST_UNORDERED_STD_FORWARD_MOVE) + // No move should take place. // (since a is already in the container) reset(); x.emplace(std::move(a)); COPY_COUNT(0); MOVE_COUNT(0); + #endif // @@ -382,6 +393,47 @@ namespace unnecessary_copy_tests reset(); x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_)); COPY_COUNT(2); MOVE_COUNT(0); + + reset(); + x.emplace(boost::unordered::piecewise_construct, + boost::make_tuple(boost::ref(b.first)), + boost::make_tuple(boost::ref(b.second))); + COPY_COUNT(0); MOVE_COUNT(0); + +#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE) + + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::make_tuple(std::ref(b.first)), + std::make_tuple(std::ref(b.second))); + COPY_COUNT(0); MOVE_COUNT(0); + + std::pair move_source_trial; + reset(); + std::make_tuple(std::move(move_source_trial.first)); + std::make_tuple(std::move(move_source_trial.second)); + int tuple_move_cost = ::unnecessary_copy_tests::count_copies::moves; + int tuple_copy_cost = ::unnecessary_copy_tests::count_copies::copies; + + std::pair move_source; + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::make_tuple(std::move(move_source.first)), + std::make_tuple(std::move(move_source.second))); + COPY_COUNT(tuple_copy_cost); + MOVE_COUNT(tuple_move_cost); + +#if defined(__GNUC__) && __GNUC__ > 4 || \ + defined(__GNUC__) && __GNUC__ == 4 && __GNUC_MINOR__ >= 6 + reset(); + x.emplace(boost::unordered::piecewise_construct, + std::forward_as_tuple(b.first), + std::forward_as_tuple(b.second)); + COPY_COUNT(0); MOVE_COUNT(0); +#endif + +#endif + } }