forked from boostorg/unordered
Unordered: Merge to release.
Using Boost.Move and better C++11 support. [SVN r73987]
This commit is contained in:
@ -134,4 +134,21 @@ First official release.
|
|||||||
* Fix a bug when inserting into an `unordered_map` or `unordered_set` using
|
* Fix a bug when inserting into an `unordered_map` or `unordered_set` using
|
||||||
iterators which returns `value_type` by copy.
|
iterators which returns `value_type` by copy.
|
||||||
|
|
||||||
|
[h2 Boost 1.48.0]
|
||||||
|
|
||||||
|
This is major change which has been converted to use Boost.Move's move
|
||||||
|
emulation, and be more compliant with the C++11 standard. This has resulted
|
||||||
|
in some breaking changes:
|
||||||
|
|
||||||
|
* Equality comparison has been changed to the C++11 specification.
|
||||||
|
In a container with equivalent keys, elements in a group with equal
|
||||||
|
keys used to have to be in the same order to be considered equal,
|
||||||
|
now they can be a permutation of each other.
|
||||||
|
|
||||||
|
* The behaviour of swap is different when the two containers to be
|
||||||
|
swapped has unequal allocators. It used to allocate new nodes using
|
||||||
|
the appropriate allocators, it now swaps the allocators if
|
||||||
|
the allocator has a member structure `propagate_on_container_swap`,
|
||||||
|
such that `propagate_on_container_swap::value` is true.
|
||||||
|
|
||||||
[endsect]
|
[endsect]
|
||||||
|
54
doc/compliance.qbk
Normal file
54
doc/compliance.qbk
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
[/ 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) ]
|
||||||
|
|
||||||
|
[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).
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:move Move emulation]
|
||||||
|
|
||||||
|
Move emulation is implemented using Boost.Move. If rvalue references are
|
||||||
|
available it will use them, but if not it uses a close, but imperfect emulation
|
||||||
|
and to get the advantage of using movable container elements, you'll need to
|
||||||
|
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/.
|
||||||
|
* Argument forwarding is not perfect.
|
||||||
|
* /TODO/: Constructor call for pairs.
|
||||||
|
|
||||||
|
[endsect]
|
||||||
|
|
||||||
|
[section:other Other]
|
||||||
|
|
||||||
|
* 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]
|
||||||
|
|
||||||
|
[endsect]
|
@ -126,7 +126,7 @@ a little to accomodate non-C++0x compilers.
|
|||||||
|
|
||||||
It isn't clear how to swap containers when their allocators aren't equal.
|
It isn't clear how to swap containers when their allocators aren't equal.
|
||||||
This is
|
This is
|
||||||
[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#431
|
[@http://www.open-std.org/jtc1/sc22/wg21/docs/lwg-defects.html#431
|
||||||
Issue 431: Swapping containers with unequal allocators]. This has been resolved
|
Issue 431: Swapping containers with unequal allocators]. This has been resolved
|
||||||
with the new allocator specification, so this should be fixed when
|
with the new allocator specification, so this should be fixed when
|
||||||
support is added.
|
support is added.
|
||||||
|
1040
doc/ref.php
Normal file
1040
doc/ref.php
Normal file
File diff suppressed because it is too large
Load Diff
128
doc/ref.xml
128
doc/ref.xml
@ -40,8 +40,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Pred</emphasis></entry>
|
<entry><emphasis>Pred</emphasis></entry>
|
||||||
<entry>A binary function object that implements an equivalence relation on values of type <code>Value</code>.
|
<entry>A binary function object that implements an equivalence relation on values of type <code>Value</code>.
|
||||||
A binary function object that induces an equivalence relation on values of type Key.
|
A binary function object that induces an equivalence relation on values of type <code>Value</code>.
|
||||||
It takes two arguments of type Key and returns a value of type bool.</entry></row>
|
It takes two arguments of type <code>Value</code> and returns a value of type bool.</entry></row>
|
||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Alloc</emphasis></entry>
|
<entry><emphasis>Alloc</emphasis></entry>
|
||||||
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
||||||
@ -360,7 +360,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent value.</para>
|
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent value.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value.</para>
|
<para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value.</para>
|
||||||
@ -383,7 +383,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>std::pair<iterator, bool></type>
|
<type>std::pair<iterator, bool></type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container if and only if there is no element in the container with an equivalent value.</para>
|
<para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent value.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>The bool component of the return type is true if an insert took place.</para>
|
<para>The bool component of the return type is true if an insert took place.</para>
|
||||||
@ -406,7 +406,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container if and only if there is no element in the container with an equivalent value.</para>
|
<para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent value.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
@ -815,8 +815,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="Equality Comparisons">
|
<free-function-group name="Equality Comparisons">
|
||||||
<function name="operator==">
|
<function name="operator==">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Value">
|
<template-type-parameter name="Value">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -839,8 +839,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</function>
|
</function>
|
||||||
<function name="operator!=">
|
<function name="operator!=">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Value">
|
<template-type-parameter name="Value">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -865,8 +865,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="swap">
|
<free-function-group name="swap">
|
||||||
<function name="swap">
|
<function name="swap">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Value">
|
<template-type-parameter name="Value">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -909,7 +909,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
</template>
|
</template>
|
||||||
<purpose><simpara>
|
<purpose><simpara>
|
||||||
An unordered associative container that stores values. The same key can be stored multiple times.
|
An unordered associative container that stores values. The same key can be stored multiple times.
|
||||||
</simpara></purpose>
|
</simpara></purpose>
|
||||||
<description>
|
<description>
|
||||||
<para>Based on chapter 23 of
|
<para>Based on chapter 23 of
|
||||||
@ -929,8 +929,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Pred</emphasis></entry>
|
<entry><emphasis>Pred</emphasis></entry>
|
||||||
<entry>A binary function object that implements an equivalence relation on values of type <code>Value</code>.
|
<entry>A binary function object that implements an equivalence relation on values of type <code>Value</code>.
|
||||||
A binary function object that induces an equivalence relation on values of type Key.
|
A binary function object that induces an equivalence relation on values of type <code>Value</code>.
|
||||||
It takes two arguments of type Key and returns a value of type bool.</entry></row>
|
It takes two arguments of type <code>Value</code> and returns a value of type bool.</entry></row>
|
||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Alloc</emphasis></entry>
|
<entry><emphasis>Alloc</emphasis></entry>
|
||||||
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
||||||
@ -1248,7 +1248,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>An iterator pointing to the inserted element.</para>
|
<para>An iterator pointing to the inserted element.</para>
|
||||||
@ -1271,7 +1271,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container.</para>
|
<para>Inserts <code>obj</code> in the container.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>An iterator pointing to the inserted element.</para>
|
<para>An iterator pointing to the inserted element.</para>
|
||||||
@ -1293,7 +1293,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container.</para>
|
<para>Inserts <code>obj</code> in the container.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
@ -1321,7 +1321,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>void</type>
|
<type>void</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts a range of elements into the container.</para>
|
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent value.</para>
|
||||||
</description>
|
</description>
|
||||||
<throws>
|
<throws>
|
||||||
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||||
@ -1702,8 +1702,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="Equality Comparisons">
|
<free-function-group name="Equality Comparisons">
|
||||||
<function name="operator==">
|
<function name="operator==">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Value">
|
<template-type-parameter name="Value">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -1726,8 +1726,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</function>
|
</function>
|
||||||
<function name="operator!=">
|
<function name="operator!=">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Value">
|
<template-type-parameter name="Value">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -1752,8 +1752,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="swap">
|
<free-function-group name="swap">
|
||||||
<function name="swap">
|
<function name="swap">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Value">
|
<template-type-parameter name="Value">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -1798,7 +1798,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<default><type>std::equal_to<Key></type></default>
|
<default><type>std::equal_to<Key></type></default>
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Alloc">
|
<template-type-parameter name="Alloc">
|
||||||
<default><type>std::allocator<std::pair<Key const, Mapped> ></type></default>
|
<default><type>std::allocator<std::pair<Key const, Mapped>></type></default>
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
</template>
|
</template>
|
||||||
<purpose><simpara>
|
<purpose><simpara>
|
||||||
@ -1825,8 +1825,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Pred</emphasis></entry>
|
<entry><emphasis>Pred</emphasis></entry>
|
||||||
<entry>A binary function object that implements an equivalence relation on values of type <code>Key</code>.
|
<entry>A binary function object that implements an equivalence relation on values of type <code>Key</code>.
|
||||||
A binary function object that induces an equivalence relation on values of type Key.
|
A binary function object that induces an equivalence relation on values of type <code>Key</code>.
|
||||||
It takes two arguments of type Key and returns a value of type bool.</entry></row>
|
It takes two arguments of type <code>Key</code> and returns a value of type bool.</entry></row>
|
||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Alloc</emphasis></entry>
|
<entry><emphasis>Alloc</emphasis></entry>
|
||||||
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
||||||
@ -1882,7 +1882,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<typedef name="iterator">
|
<typedef name="iterator">
|
||||||
<type><emphasis>implementation-defined</emphasis></type>
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
<description>
|
<description>
|
||||||
<para>A iterator whose value type is <type>value_type</type>. </para>
|
<para>An iterator whose value type is <type>value_type</type>. </para>
|
||||||
<para>The iterator category is at least a forward iterator.</para>
|
<para>The iterator category is at least a forward iterator.</para>
|
||||||
<para>Convertible to <type>const_iterator</type>.</para>
|
<para>Convertible to <type>const_iterator</type>.</para>
|
||||||
</description>
|
</description>
|
||||||
@ -2148,7 +2148,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent key.</para>
|
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container if and only if there is no element in the container with an equivalent key.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.</para>
|
<para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.</para>
|
||||||
@ -2171,7 +2171,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>std::pair<iterator, bool></type>
|
<type>std::pair<iterator, bool></type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container if and only if there is no element in the container with an equivalent key.</para>
|
<para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent key.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>The bool component of the return type is true if an insert took place.</para>
|
<para>The bool component of the return type is true if an insert took place.</para>
|
||||||
@ -2194,7 +2194,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container if and only if there is no element in the container with an equivalent key.</para>
|
<para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent key.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
@ -2638,10 +2638,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="Equality Comparisons">
|
<free-function-group name="Equality Comparisons">
|
||||||
<function name="operator==">
|
<function name="operator==">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Key">
|
<template-type-parameter name="Key">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Mapped">
|
<template-type-parameter name="Mapped">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -2664,10 +2664,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</function>
|
</function>
|
||||||
<function name="operator!=">
|
<function name="operator!=">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Key">
|
<template-type-parameter name="Key">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Mapped">
|
<template-type-parameter name="Mapped">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -2692,10 +2692,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="swap">
|
<free-function-group name="swap">
|
||||||
<function name="swap">
|
<function name="swap">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Key">
|
<template-type-parameter name="Key">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Mapped">
|
<template-type-parameter name="Mapped">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -2736,11 +2736,11 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<default><type>std::equal_to<Key></type></default>
|
<default><type>std::equal_to<Key></type></default>
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Alloc">
|
<template-type-parameter name="Alloc">
|
||||||
<default><type>std::allocator<std::pair<Key const, Mapped> ></type></default>
|
<default><type>std::allocator<std::pair<Key const, Mapped>></type></default>
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
</template>
|
</template>
|
||||||
<purpose><simpara>
|
<purpose><simpara>
|
||||||
An unordered associative container that associates keys with another value. The same key can be stored multiple times.
|
An unordered associative container that associates keys with another value. The same key can be stored multiple times.
|
||||||
</simpara></purpose>
|
</simpara></purpose>
|
||||||
<description>
|
<description>
|
||||||
<para>Based on chapter 23 of
|
<para>Based on chapter 23 of
|
||||||
@ -2763,8 +2763,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Pred</emphasis></entry>
|
<entry><emphasis>Pred</emphasis></entry>
|
||||||
<entry>A binary function object that implements an equivalence relation on values of type <code>Key</code>.
|
<entry>A binary function object that implements an equivalence relation on values of type <code>Key</code>.
|
||||||
A binary function object that induces an equivalence relation on values of type Key.
|
A binary function object that induces an equivalence relation on values of type <code>Key</code>.
|
||||||
It takes two arguments of type Key and returns a value of type bool.</entry></row>
|
It takes two arguments of type <code>Key</code> and returns a value of type bool.</entry></row>
|
||||||
<row>
|
<row>
|
||||||
<entry><emphasis>Alloc</emphasis></entry>
|
<entry><emphasis>Alloc</emphasis></entry>
|
||||||
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
<entry>An allocator whose value type is the same as the container's value type.</entry></row></tbody></tgroup></informaltable></para>
|
||||||
@ -2820,7 +2820,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<typedef name="iterator">
|
<typedef name="iterator">
|
||||||
<type><emphasis>implementation-defined</emphasis></type>
|
<type><emphasis>implementation-defined</emphasis></type>
|
||||||
<description>
|
<description>
|
||||||
<para>A iterator whose value type is <type>value_type</type>. </para>
|
<para>An iterator whose value type is <type>value_type</type>. </para>
|
||||||
<para>The iterator category is at least a forward iterator.</para>
|
<para>The iterator category is at least a forward iterator.</para>
|
||||||
<para>Convertible to <type>const_iterator</type>.</para>
|
<para>Convertible to <type>const_iterator</type>.</para>
|
||||||
</description>
|
</description>
|
||||||
@ -3085,7 +3085,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>An iterator pointing to the inserted element.</para>
|
<para>An iterator pointing to the inserted element.</para>
|
||||||
@ -3108,7 +3108,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container.</para>
|
<para>Inserts <code>obj</code> in the container.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
<para>An iterator pointing to the inserted element.</para>
|
<para>An iterator pointing to the inserted element.</para>
|
||||||
@ -3130,7 +3130,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>iterator</type>
|
<type>iterator</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts obj in the container.</para>
|
<para>Inserts <code>obj</code> in the container.</para>
|
||||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||||
</description>
|
</description>
|
||||||
<returns>
|
<returns>
|
||||||
@ -3158,7 +3158,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</parameter>
|
</parameter>
|
||||||
<type>void</type>
|
<type>void</type>
|
||||||
<description>
|
<description>
|
||||||
<para>Inserts a range of elements into the container.</para>
|
<para>Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.</para>
|
||||||
</description>
|
</description>
|
||||||
<throws>
|
<throws>
|
||||||
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
<para>When inserting a single element, if an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||||
@ -3539,10 +3539,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="Equality Comparisons">
|
<free-function-group name="Equality Comparisons">
|
||||||
<function name="operator==">
|
<function name="operator==">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Key">
|
<template-type-parameter name="Key">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Mapped">
|
<template-type-parameter name="Mapped">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -3565,10 +3565,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
</function>
|
</function>
|
||||||
<function name="operator!=">
|
<function name="operator!=">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Key">
|
<template-type-parameter name="Key">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Mapped">
|
<template-type-parameter name="Mapped">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
@ -3593,10 +3593,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<free-function-group name="swap">
|
<free-function-group name="swap">
|
||||||
<function name="swap">
|
<function name="swap">
|
||||||
<template>
|
<template>
|
||||||
<template-type-parameter name="Key">
|
<template-type-parameter name="Key">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Mapped">
|
<template-type-parameter name="Mapped">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Hash">
|
<template-type-parameter name="Hash">
|
||||||
</template-type-parameter>
|
</template-type-parameter>
|
||||||
<template-type-parameter name="Pred">
|
<template-type-parameter name="Pred">
|
||||||
|
@ -31,6 +31,7 @@
|
|||||||
[include:unordered buckets.qbk]
|
[include:unordered buckets.qbk]
|
||||||
[include:unordered hash_equality.qbk]
|
[include:unordered hash_equality.qbk]
|
||||||
[include:unordered comparison.qbk]
|
[include:unordered comparison.qbk]
|
||||||
|
[include:unordered compliance.qbk]
|
||||||
[include:unordered rationale.qbk]
|
[include:unordered rationale.qbk]
|
||||||
[include:unordered changes.qbk]
|
[include:unordered changes.qbk]
|
||||||
[xinclude ref.xml]
|
[xinclude ref.xml]
|
||||||
|
@ -1,9 +1,12 @@
|
|||||||
|
|
||||||
// Copyright 2005-2009 Daniel James.
|
// Copyright 2005-2011 Daniel James.
|
||||||
|
// Copyright 2009 Pablo Halpern.
|
||||||
|
//
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
//
|
||||||
// A couple of templates to make using allocators easier.
|
// Written by Daniel James using some code from Pablo Halpern's
|
||||||
|
// allocator traits implementation.
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||||
@ -13,6 +16,8 @@
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/detail/select_type.hpp>
|
||||||
|
#include <boost/utility/enable_if.hpp>
|
||||||
|
|
||||||
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
|
#if (defined(BOOST_NO_STD_ALLOCATOR) || defined(BOOST_DINKUMWARE_STDLIB)) \
|
||||||
&& !defined(__BORLANDC__)
|
&& !defined(__BORLANDC__)
|
||||||
@ -23,24 +28,257 @@
|
|||||||
# include <boost/detail/allocator_utilities.hpp>
|
# include <boost/detail/allocator_utilities.hpp>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
|
||||||
|
# include <memory>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
|
||||||
|
#include <type_traits>
|
||||||
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
using std::integral_constant;
|
||||||
|
using std::true_type;
|
||||||
|
using std::false_type;
|
||||||
|
}}}
|
||||||
|
#else
|
||||||
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
template <typename T, T Value>
|
||||||
|
struct integral_constant { enum { value = Value }; };
|
||||||
|
typedef integral_constant<bool, true> true_type;
|
||||||
|
typedef integral_constant<bool, false> false_type;
|
||||||
|
}}}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// TODO: Use std::addressof if available?
|
||||||
|
#include <boost/utility/addressof.hpp>
|
||||||
|
|
||||||
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
|
||||||
|
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS
|
||||||
|
template <typename Alloc>
|
||||||
|
struct allocator_traits : std::allocator_traits<Alloc> {};
|
||||||
|
|
||||||
|
template <typename Alloc, typename T>
|
||||||
|
struct rebind_wrap
|
||||||
|
{
|
||||||
|
typedef typename allocator_traits<Alloc>::rebind_alloc<T> type;
|
||||||
|
};
|
||||||
|
#else
|
||||||
// rebind_wrap
|
// rebind_wrap
|
||||||
//
|
//
|
||||||
// Rebind allocators. For some problematic libraries, use rebind_to
|
// Rebind allocators. For some problematic libraries, use rebind_to
|
||||||
// from <boost/detail/allocator_utilities.hpp>.
|
// from <boost/detail/allocator_utilities.hpp>.
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
# if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
||||||
template <class Alloc, class T>
|
template <typename Alloc, typename T>
|
||||||
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
|
struct rebind_wrap : ::boost::detail::allocator::rebind_to<Alloc, T> {};
|
||||||
#else
|
# else
|
||||||
template <class Alloc, class T>
|
template <typename Alloc, typename T>
|
||||||
struct rebind_wrap
|
struct rebind_wrap
|
||||||
{
|
{
|
||||||
typedef BOOST_DEDUCED_TYPENAME
|
typedef BOOST_DEDUCED_TYPENAME
|
||||||
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
|
Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other
|
||||||
type;
|
type;
|
||||||
};
|
};
|
||||||
|
# endif
|
||||||
|
|
||||||
|
struct convertible_from_anything
|
||||||
|
{
|
||||||
|
template<typename T> convertible_from_anything(T const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef char (&no_type)[1];
|
||||||
|
typedef char (&yes_type)[2];
|
||||||
|
|
||||||
|
template <typename T> struct sfinae {
|
||||||
|
typedef yes_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Infrastructure for providing a default type for Tp::tname if absent.
|
||||||
|
#define BOOST_DEFAULT_TYPE_TMPLT(tname) \
|
||||||
|
template <typename Tp, typename Default> \
|
||||||
|
struct default_type_ ## tname { \
|
||||||
|
template <typename T> \
|
||||||
|
static BOOST_DEDUCED_TYPENAME sfinae< \
|
||||||
|
BOOST_DEDUCED_TYPENAME T::tname>::type test(int); \
|
||||||
|
template <typename T> \
|
||||||
|
static no_type test(long); \
|
||||||
|
\
|
||||||
|
enum { value = sizeof(test<Tp>(0)) == sizeof(yes_type) }; \
|
||||||
|
\
|
||||||
|
struct DefaultWrap { typedef Default tname; }; \
|
||||||
|
\
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME \
|
||||||
|
boost::detail::if_true<value>:: \
|
||||||
|
BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
|
||||||
|
::type::tname type; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BOOST_DEFAULT_TYPE(T,tname, arg) \
|
||||||
|
BOOST_DEDUCED_TYPENAME default_type_ ## tname<T, arg>::type
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_SFINAE_EXPR) || BOOST_WORKAROUND(BOOST_MSVC, >= 1500)
|
||||||
|
// Specialization is only needed for Visual C++. Without it SFINAE doesn't
|
||||||
|
// kick in.
|
||||||
|
template <unsigned int>
|
||||||
|
struct expr_sfinae;
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct expr_sfinae<sizeof(yes_type)> {
|
||||||
|
typedef yes_type type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct has_select_on_container_copy_construction
|
||||||
|
{
|
||||||
|
// This needs to be a template for Visual C++.
|
||||||
|
template <typename T2>
|
||||||
|
static yes_type to_yes_type(const T2&);
|
||||||
|
|
||||||
|
template <typename T2>
|
||||||
|
static typename expr_sfinae<sizeof(to_yes_type(
|
||||||
|
((T2 const*)0)->select_on_container_copy_construction()
|
||||||
|
))>::type check(T2*);
|
||||||
|
|
||||||
|
static no_type check(void*);
|
||||||
|
|
||||||
|
enum { value = sizeof(check((T*) 0)) == sizeof(yes_type) };
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
template <typename T>
|
||||||
|
struct has_select_on_container_copy_construction
|
||||||
|
{
|
||||||
|
typedef T (T::*SelectFunc)() const;
|
||||||
|
|
||||||
|
template <SelectFunc e> struct sfinae { typedef yes_type type; };
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
static typename sfinae<&U::select_on_container_copy_construction>::type
|
||||||
|
test(int);
|
||||||
|
template <class U>
|
||||||
|
static no_type test(...);
|
||||||
|
|
||||||
|
enum { value = sizeof(test<T>(1)) == sizeof(yes_type) };
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
inline BOOST_DEDUCED_TYPENAME boost::enable_if<
|
||||||
|
has_select_on_container_copy_construction<Alloc>, Alloc
|
||||||
|
>::type call_select_on_container_copy_construction(const Alloc& rhs)
|
||||||
|
{
|
||||||
|
return rhs.select_on_container_copy_construction();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
inline BOOST_DEDUCED_TYPENAME boost::disable_if<
|
||||||
|
has_select_on_container_copy_construction<Alloc>, Alloc
|
||||||
|
>::type call_select_on_container_copy_construction(const Alloc& rhs)
|
||||||
|
{
|
||||||
|
return rhs;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
struct allocator_traits
|
||||||
|
{
|
||||||
|
typedef Alloc allocator_type;
|
||||||
|
typedef typename Alloc::value_type value_type;
|
||||||
|
|
||||||
|
typedef BOOST_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<pointer>::
|
||||||
|
// BOOST_NESTED_TEMPLATE rebind<const value_type>::other)
|
||||||
|
// const_pointer;
|
||||||
|
|
||||||
|
typedef BOOST_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,
|
||||||
|
// BOOST_NESTED_TEMPLATE pointer_traits<pointer>::
|
||||||
|
// BOOST_NESTED_TEMPLATE rebind<void>::other)
|
||||||
|
// void_pointer;
|
||||||
|
|
||||||
|
//typedef BOOST_DEFAULT_TYPE(Alloc, const_void_pointer,
|
||||||
|
// BOOST_DEDUCED_TYPENAME pointer_traits<pointer>::
|
||||||
|
// BOOST_NESTED_TEMPLATE rebind<const void>::other)
|
||||||
|
// const_void_pointer;
|
||||||
|
|
||||||
|
typedef BOOST_DEFAULT_TYPE(Alloc, difference_type, std::ptrdiff_t)
|
||||||
|
difference_type;
|
||||||
|
|
||||||
|
typedef BOOST_DEFAULT_TYPE(Alloc, size_type, std::size_t)
|
||||||
|
size_type;
|
||||||
|
|
||||||
|
// TODO: rebind_alloc and rebind_traits
|
||||||
|
|
||||||
|
static pointer allocate(Alloc& a, size_type n)
|
||||||
|
{ return a.allocate(n); }
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
// { 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
|
||||||
|
|
||||||
|
// template <typename T, typename... Args>
|
||||||
|
// static void construct(Alloc& a, T* p, Args&&... args) {
|
||||||
|
// DEFAULT_FUNC(construct,void)(a, p, std::forward<Args>(args)...);
|
||||||
|
// }
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void construct(Alloc& a, T* p, T const& x) {
|
||||||
|
a.construct(p, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void destroy(Alloc& a, T* p) {
|
||||||
|
// DEFAULT_FUNC(destroy,void)(a, p);
|
||||||
|
a.destroy(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
static size_type max_size(const Alloc& a)
|
||||||
|
{ return a.max_size(); }
|
||||||
|
|
||||||
|
// Allocator propagation on construction
|
||||||
|
|
||||||
|
static Alloc select_on_container_copy_construction(Alloc const& rhs)
|
||||||
|
{
|
||||||
|
return boost::unordered::detail::
|
||||||
|
call_select_on_container_copy_construction(rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocator propagation on assignment and swap.
|
||||||
|
// Return true if lhs is modified.
|
||||||
|
typedef BOOST_DEFAULT_TYPE(
|
||||||
|
Alloc, propagate_on_container_copy_assignment, false_type)
|
||||||
|
propagate_on_container_copy_assignment;
|
||||||
|
typedef BOOST_DEFAULT_TYPE(
|
||||||
|
Alloc,propagate_on_container_move_assignment, false_type)
|
||||||
|
propagate_on_container_move_assignment;
|
||||||
|
typedef BOOST_DEFAULT_TYPE(
|
||||||
|
Alloc,propagate_on_container_swap,false_type)
|
||||||
|
propagate_on_container_swap;
|
||||||
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// allocator_array_constructor
|
// allocator_array_constructor
|
||||||
@ -49,10 +287,11 @@ namespace boost { namespace unordered_detail {
|
|||||||
// clean up if an exception is thrown before the container takes charge
|
// clean up if an exception is thrown before the container takes charge
|
||||||
// of it.
|
// of it.
|
||||||
|
|
||||||
template <class Allocator>
|
template <typename Allocator>
|
||||||
struct allocator_array_constructor
|
struct allocator_array_constructor
|
||||||
{
|
{
|
||||||
typedef BOOST_DEDUCED_TYPENAME Allocator::pointer pointer;
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<Allocator>::pointer
|
||||||
|
pointer;
|
||||||
|
|
||||||
Allocator& alloc_;
|
Allocator& alloc_;
|
||||||
pointer ptr_;
|
pointer ptr_;
|
||||||
@ -69,21 +308,23 @@ namespace boost { namespace unordered_detail {
|
|||||||
~allocator_array_constructor() {
|
~allocator_array_constructor() {
|
||||||
if (ptr_) {
|
if (ptr_) {
|
||||||
for(pointer p = ptr_; p != constructed_; ++p)
|
for(pointer p = ptr_; p != constructed_; ++p)
|
||||||
alloc_.destroy(p);
|
allocator_traits<Allocator>::destroy(alloc_,
|
||||||
|
boost::addressof(*p));
|
||||||
|
|
||||||
alloc_.deallocate(ptr_, length_);
|
allocator_traits<Allocator>::deallocate(alloc_, ptr_, length_);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class V>
|
template <typename V>
|
||||||
void construct(V const& v, std::size_t l)
|
void construct(V const& v, std::size_t l)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(!ptr_);
|
BOOST_ASSERT(!ptr_);
|
||||||
length_ = l;
|
length_ = l;
|
||||||
ptr_ = alloc_.allocate(length_);
|
ptr_ = allocator_traits<Allocator>::allocate(alloc_, length_);
|
||||||
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
|
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
|
||||||
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
|
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
|
||||||
alloc_.construct(constructed_, v);
|
allocator_traits<Allocator>::construct(alloc_,
|
||||||
|
boost::addressof(*constructed_), v);
|
||||||
}
|
}
|
||||||
|
|
||||||
pointer get() const
|
pointer get() const
|
||||||
@ -102,7 +343,7 @@ namespace boost { namespace unordered_detail {
|
|||||||
allocator_array_constructor& operator=(
|
allocator_array_constructor& operator=(
|
||||||
allocator_array_constructor const&);
|
allocator_array_constructor const&);
|
||||||
};
|
};
|
||||||
}}
|
}}}
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
#if defined(BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES)
|
||||||
# undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
|
# undef BOOST_UNORDERED_USE_ALLOCATOR_UTILITIES
|
||||||
|
@ -1,183 +1,808 @@
|
|||||||
|
|
||||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||||
// Copyright (C) 2005-2009 Daniel James
|
// Copyright (C) 2005-2011 Daniel James
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_MANAGER_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <boost/unordered/detail/node.hpp>
|
#include <boost/unordered/detail/node.hpp>
|
||||||
#include <boost/unordered/detail/util.hpp>
|
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Buckets
|
//
|
||||||
|
// Now the main data structure:
|
||||||
|
//
|
||||||
|
// buckets<A, Unique> functions<H, P>
|
||||||
|
// | |
|
||||||
|
// +---------------+--------------+
|
||||||
|
// |
|
||||||
|
// table<T>
|
||||||
|
//
|
||||||
|
// T is a class which contains typedefs for all the types we need.
|
||||||
|
|
||||||
template <class A, class G>
|
// buckets
|
||||||
inline std::size_t hash_buckets<A, G>::max_bucket_count() const {
|
//
|
||||||
// -1 to account for the sentinel.
|
// This is responsible for allocating and deallocating buckets and nodes.
|
||||||
return prev_prime(this->bucket_alloc().max_size() - 1);
|
//
|
||||||
}
|
// Notes:
|
||||||
|
// 1. For the sake exception safety the consturctors don't allocate
|
||||||
|
// anything.
|
||||||
|
// 2. It's the callers responsibility to allocate the buckets before calling
|
||||||
|
// any of the methods (other than getters and setters).
|
||||||
|
|
||||||
template <class A, class G>
|
template <class A, bool Unique>
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
|
class buckets
|
||||||
hash_buckets<A, G>::get_bucket(std::size_t num) const
|
|
||||||
{
|
{
|
||||||
return buckets_ + static_cast<std::ptrdiff_t>(num);
|
buckets(buckets const&);
|
||||||
}
|
buckets& operator=(buckets const&);
|
||||||
|
public:
|
||||||
|
// Types
|
||||||
|
|
||||||
template <class A, class G>
|
typedef BOOST_DEDUCED_TYPENAME ::boost::detail::if_true<Unique>::
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::bucket_ptr
|
BOOST_NESTED_TEMPLATE then<
|
||||||
hash_buckets<A, G>::bucket_ptr_from_hash(std::size_t hashed) const
|
::boost::unordered::detail::ungrouped_node<A>,
|
||||||
{
|
::boost::unordered::detail::grouped_node<A>
|
||||||
return get_bucket(hashed % bucket_count_);
|
>::type node;
|
||||||
}
|
|
||||||
|
typedef A value_allocator;
|
||||||
|
typedef ::boost::unordered::detail::bucket<A> bucket;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type value_type;
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator
|
||||||
|
bucket_allocator;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<bucket_allocator>::pointer bucket_ptr;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
|
||||||
|
node_allocator;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME allocator_traits<node_allocator>::pointer real_node_ptr;
|
||||||
|
|
||||||
|
// Members
|
||||||
|
|
||||||
|
bucket_ptr buckets_;
|
||||||
|
std::size_t bucket_count_;
|
||||||
|
std::size_t size_;
|
||||||
|
compressed_pair<bucket_allocator, node_allocator> allocators_;
|
||||||
|
|
||||||
|
// Data access
|
||||||
|
|
||||||
|
bucket_allocator const& bucket_alloc() const
|
||||||
|
{
|
||||||
|
return allocators_.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
node_allocator const& node_alloc() const
|
||||||
|
{
|
||||||
|
return allocators_.second();
|
||||||
|
}
|
||||||
|
|
||||||
|
bucket_allocator& bucket_alloc()
|
||||||
|
{
|
||||||
|
return allocators_.first();
|
||||||
|
}
|
||||||
|
|
||||||
|
node_allocator& node_alloc()
|
||||||
|
{
|
||||||
|
return allocators_.second();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t max_bucket_count() const
|
||||||
|
{
|
||||||
|
// -1 to account for the start bucket.
|
||||||
|
return prev_prime(allocator_traits<bucket_allocator>::max_size(bucket_alloc()) - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Constructors and Destructors
|
||||||
|
|
||||||
|
buckets(node_allocator const& a, std::size_t bucket_count)
|
||||||
|
: buckets_(),
|
||||||
|
bucket_count_(bucket_count),
|
||||||
|
size_(),
|
||||||
|
allocators_(a,a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
buckets(buckets& b, move_tag m)
|
||||||
|
: buckets_(),
|
||||||
|
bucket_count_(b.bucket_count_),
|
||||||
|
size_(),
|
||||||
|
allocators_(b.allocators_, m)
|
||||||
|
{
|
||||||
|
swap(b);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
buckets(table<T>& x, move_tag m)
|
||||||
|
: buckets_(),
|
||||||
|
bucket_count_(x.bucket_count_),
|
||||||
|
allocators_(x.allocators_, m)
|
||||||
|
{
|
||||||
|
swap(x);
|
||||||
|
x.size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
inline ~buckets()
|
||||||
|
{
|
||||||
|
if(this->buckets_) { this->delete_buckets(); }
|
||||||
|
}
|
||||||
|
|
||||||
|
void create_buckets()
|
||||||
|
{
|
||||||
|
// The array constructor will clean up in the event of an
|
||||||
|
// exception.
|
||||||
|
allocator_array_constructor<bucket_allocator>
|
||||||
|
constructor(bucket_alloc());
|
||||||
|
|
||||||
template <class A, class G>
|
// Creates an extra bucket to act as the start node.
|
||||||
std::size_t hash_buckets<A, G>::bucket_size(std::size_t index) const
|
constructor.construct(bucket(), this->bucket_count_ + 1);
|
||||||
{
|
|
||||||
if(!buckets_) return 0;
|
// Only release the buckets once everything is successfully
|
||||||
bucket_ptr ptr = get_bucket(index)->next_;
|
// done.
|
||||||
std::size_t count = 0;
|
this->buckets_ = constructor.release();
|
||||||
while(ptr) {
|
}
|
||||||
++count;
|
|
||||||
|
void swap(buckets& other, false_type = false_type())
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||||
|
std::swap(buckets_, other.buckets_);
|
||||||
|
std::swap(bucket_count_, other.bucket_count_);
|
||||||
|
std::swap(size_, other.size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(buckets& other, true_type)
|
||||||
|
{
|
||||||
|
allocators_.swap(other.allocators_);
|
||||||
|
std::swap(buckets_, other.buckets_);
|
||||||
|
std::swap(bucket_count_, other.bucket_count_);
|
||||||
|
std::swap(size_, other.size_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_buckets_from(buckets& other)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||||
|
BOOST_ASSERT(!this->buckets_);
|
||||||
|
this->buckets_ = other.buckets_;
|
||||||
|
this->bucket_count_ = other.bucket_count_;
|
||||||
|
this->size_ = other.size_;
|
||||||
|
other.buckets_ = bucket_ptr();
|
||||||
|
other.bucket_count_ = 0;
|
||||||
|
other.size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t bucket_size(std::size_t index) const
|
||||||
|
{
|
||||||
|
if (!this->size_) return 0;
|
||||||
|
node_ptr ptr = this->buckets_[index].next_;
|
||||||
|
if (!ptr) return 0;
|
||||||
ptr = ptr->next_;
|
ptr = ptr->next_;
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_buckets<A, G>::node_ptr
|
|
||||||
hash_buckets<A, G>::bucket_begin(std::size_t num) const
|
|
||||||
{
|
|
||||||
return buckets_ ? get_bucket(num)->next_ : node_ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Delete
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline void hash_buckets<A, G>::delete_node(node_ptr b)
|
|
||||||
{
|
|
||||||
node* raw_ptr = static_cast<node*>(&*b);
|
|
||||||
boost::unordered_detail::destroy(raw_ptr->value_ptr());
|
|
||||||
real_node_ptr n(node_alloc().address(*raw_ptr));
|
|
||||||
node_alloc().destroy(n);
|
|
||||||
node_alloc().deallocate(n, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline void hash_buckets<A, G>::clear_bucket(bucket_ptr b)
|
|
||||||
{
|
|
||||||
node_ptr node_it = b->next_;
|
|
||||||
b->next_ = node_ptr();
|
|
||||||
|
|
||||||
while(node_it) {
|
|
||||||
node_ptr node_to_delete = node_it;
|
|
||||||
node_it = node_it->next_;
|
|
||||||
delete_node(node_to_delete);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline void hash_buckets<A, G>::delete_buckets()
|
|
||||||
{
|
|
||||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
|
||||||
|
|
||||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
|
||||||
clear_bucket(begin);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Destroy the buckets (including the sentinel bucket).
|
|
||||||
++end;
|
|
||||||
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
|
||||||
bucket_alloc().destroy(begin);
|
|
||||||
}
|
|
||||||
|
|
||||||
bucket_alloc().deallocate(this->buckets_, this->bucket_count_ + 1);
|
|
||||||
|
|
||||||
this->buckets_ = bucket_ptr();
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline std::size_t hash_buckets<A, G>::delete_nodes(
|
|
||||||
node_ptr begin, node_ptr end)
|
|
||||||
{
|
|
||||||
std::size_t count = 0;
|
|
||||||
while(begin != end) {
|
|
||||||
node_ptr n = begin;
|
|
||||||
begin = begin->next_;
|
|
||||||
delete_node(n);
|
|
||||||
++count;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Constructors and Destructors
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline hash_buckets<A, G>::hash_buckets(
|
|
||||||
node_allocator const& a, std::size_t bucket_count)
|
|
||||||
: buckets_(),
|
|
||||||
bucket_count_(bucket_count),
|
|
||||||
allocators_(a,a)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
inline hash_buckets<A, G>::~hash_buckets()
|
|
||||||
{
|
|
||||||
if(this->buckets_) { this->delete_buckets(); }
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A, class G>
|
std::size_t count = 0;
|
||||||
inline void hash_buckets<A, G>::create_buckets()
|
while(BOOST_UNORDERED_BORLAND_BOOL(ptr) &&
|
||||||
|
node::get_hash(ptr) % this->bucket_count_ == index)
|
||||||
|
{
|
||||||
|
++count;
|
||||||
|
ptr = ptr->next_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ptr bucket_begin(std::size_t bucket_index) const
|
||||||
|
{
|
||||||
|
if (!this->size_) return node_ptr();
|
||||||
|
bucket& b = this->buckets_[bucket_index];
|
||||||
|
if (!b.next_) return node_ptr();
|
||||||
|
return b.next_->next_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// For the remaining functions, buckets_ must not be null.
|
||||||
|
|
||||||
|
bucket_ptr get_bucket(std::size_t bucket_index) const
|
||||||
|
{
|
||||||
|
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
|
||||||
|
}
|
||||||
|
|
||||||
|
float load_factor() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(this->bucket_count_ != 0);
|
||||||
|
return static_cast<float>(this->size_)
|
||||||
|
/ static_cast<float>(this->bucket_count_);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Delete
|
||||||
|
|
||||||
|
void delete_node(node_ptr n)
|
||||||
|
{
|
||||||
|
node* raw_ptr = static_cast<node*>(boost::addressof(*n));
|
||||||
|
real_node_ptr real_ptr(node_alloc().address(*raw_ptr));
|
||||||
|
|
||||||
|
::boost::unordered::detail::destroy(raw_ptr->value_ptr());
|
||||||
|
allocator_traits<node_allocator>::destroy(node_alloc(), raw_ptr);
|
||||||
|
allocator_traits<node_allocator>::deallocate(node_alloc(), real_ptr, 1);
|
||||||
|
|
||||||
|
--this->size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
void delete_buckets()
|
||||||
|
{
|
||||||
|
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||||
|
node_ptr n = (end)->next_;
|
||||||
|
while(BOOST_UNORDERED_BORLAND_BOOL(n))
|
||||||
|
{
|
||||||
|
node_ptr node_to_delete = n;
|
||||||
|
n = n->next_;
|
||||||
|
delete_node(node_to_delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
++end;
|
||||||
|
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||||
|
allocator_traits<bucket_allocator>::destroy(bucket_alloc(),
|
||||||
|
boost::addressof(*begin));
|
||||||
|
}
|
||||||
|
|
||||||
|
allocator_traits<bucket_allocator>::deallocate(bucket_alloc(), this->buckets_, this->bucket_count_ + 1);
|
||||||
|
|
||||||
|
this->buckets_ = bucket_ptr();
|
||||||
|
BOOST_ASSERT(this->size_ == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::size_t delete_nodes(node_ptr begin, node_ptr end)
|
||||||
|
{
|
||||||
|
std::size_t count = 0;
|
||||||
|
while(begin != end) {
|
||||||
|
node_ptr n = begin;
|
||||||
|
begin = begin->next_;
|
||||||
|
delete_node(n);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear()
|
||||||
|
{
|
||||||
|
if(!this->size_) return;
|
||||||
|
|
||||||
|
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
||||||
|
|
||||||
|
node_ptr n = (end)->next_;
|
||||||
|
while(BOOST_UNORDERED_BORLAND_BOOL(n))
|
||||||
|
{
|
||||||
|
node_ptr node_to_delete = n;
|
||||||
|
n = n->next_;
|
||||||
|
this->delete_node(node_to_delete);
|
||||||
|
}
|
||||||
|
|
||||||
|
++end;
|
||||||
|
for(bucket_ptr begin = this->buckets_; begin != end; ++begin) {
|
||||||
|
begin->next_ = bucket_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
this->size_ = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ptr erase(node_ptr r)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(r);
|
||||||
|
node_ptr next = r->next_;
|
||||||
|
|
||||||
|
bucket_ptr bucket = this->get_bucket(
|
||||||
|
node::get_hash(r) % this->bucket_count_);
|
||||||
|
node_ptr prev = node::unlink_node(*bucket, r);
|
||||||
|
|
||||||
|
this->fix_buckets(bucket, prev, next);
|
||||||
|
|
||||||
|
this->delete_node(r);
|
||||||
|
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ptr erase_range(node_ptr r1, node_ptr r2)
|
||||||
|
{
|
||||||
|
if (r1 == r2) return r2;
|
||||||
|
|
||||||
|
std::size_t bucket_index = node::get_hash(r1) % this->bucket_count_;
|
||||||
|
node_ptr prev = node::unlink_nodes(
|
||||||
|
this->buckets_[bucket_index], r1, r2);
|
||||||
|
this->fix_buckets_range(bucket_index, prev, r1, r2);
|
||||||
|
this->delete_nodes(r1, r2);
|
||||||
|
|
||||||
|
return r2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called after erasing a node or group of nodes to fix up
|
||||||
|
// the bucket pointers.
|
||||||
|
void fix_buckets(bucket_ptr bucket, node_ptr prev, node_ptr next)
|
||||||
|
{
|
||||||
|
if (!next)
|
||||||
|
{
|
||||||
|
if (bucket->next_ == prev) bucket->next_ = node_ptr();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
bucket_ptr next_bucket = this->get_bucket(
|
||||||
|
node::get_hash(next) % this->bucket_count_);
|
||||||
|
if (next_bucket != bucket)
|
||||||
|
{
|
||||||
|
next_bucket->next_ = prev;
|
||||||
|
if (bucket->next_ == prev) bucket->next_ = node_ptr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is called after erasing a range of nodes to fix any bucket
|
||||||
|
// pointers into that range.
|
||||||
|
void fix_buckets_range(
|
||||||
|
std::size_t bucket_index, node_ptr prev, node_ptr begin, node_ptr end)
|
||||||
|
{
|
||||||
|
node_ptr n = begin;
|
||||||
|
|
||||||
|
// If we're not at the start of the current bucket, then
|
||||||
|
// go to the start of the next bucket.
|
||||||
|
if (this->get_bucket(bucket_index)->next_ != prev)
|
||||||
|
{
|
||||||
|
for(;;) {
|
||||||
|
n = n->next_;
|
||||||
|
if (n == end) return;
|
||||||
|
|
||||||
|
std::size_t new_bucket_index =
|
||||||
|
node::get_hash(n) % this->bucket_count_;
|
||||||
|
if (bucket_index != new_bucket_index) {
|
||||||
|
bucket_index = new_bucket_index;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through the remaining nodes, clearing out the bucket
|
||||||
|
// pointers.
|
||||||
|
this->buckets_[bucket_index].next_ = bucket_ptr();
|
||||||
|
for(;;) {
|
||||||
|
n = n->next_;
|
||||||
|
if (n == end) break;
|
||||||
|
|
||||||
|
std::size_t new_bucket_index =
|
||||||
|
node::get_hash(n) % this->bucket_count_;
|
||||||
|
if (bucket_index != new_bucket_index) {
|
||||||
|
bucket_index = new_bucket_index;
|
||||||
|
this->buckets_[bucket_index].next_ = bucket_ptr();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Finally fix the bucket containing the trailing node.
|
||||||
|
if (BOOST_UNORDERED_BORLAND_BOOL(n)) {
|
||||||
|
this->buckets_[node::get_hash(n) % this->bucket_count_].next_
|
||||||
|
= prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Iterate through the nodes placing them in the correct buckets.
|
||||||
|
// pre: prev->next_ is not null.
|
||||||
|
node_ptr place_in_bucket(node_ptr prev, node_ptr end) {
|
||||||
|
bucket_ptr b = this->get_bucket(node::get_hash(prev->next_) % this->bucket_count_);
|
||||||
|
|
||||||
|
if (!b->next_) {
|
||||||
|
b->next_ = prev;
|
||||||
|
return end;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node_ptr next = end->next_;
|
||||||
|
end->next_ = b->next_->next_;
|
||||||
|
b->next_->next_ = prev->next_;
|
||||||
|
prev->next_ = next;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void copy_buckets_to(buckets&) const;
|
||||||
|
void move_buckets_to(buckets&) const;
|
||||||
|
void rehash_impl(std::size_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Assigning and swapping the equality and hash function objects
|
||||||
|
// needs strong exception safety. To implement that normally we'd
|
||||||
|
// require one of them to be known to not throw and the other to
|
||||||
|
// guarantee strong exception safety. Unfortunately they both only
|
||||||
|
// have basic exception safety. So to acheive strong exception
|
||||||
|
// safety we have storage space for two copies, and assign the new
|
||||||
|
// copies to the unused space. Then switch to using that to use
|
||||||
|
// them. This is implemented in 'set_hash_functions' which
|
||||||
|
// atomically assigns the new function objects in a strongly
|
||||||
|
// exception safe manner.
|
||||||
|
|
||||||
|
template <class H, class P> class set_hash_functions;
|
||||||
|
|
||||||
|
template <class H, class P>
|
||||||
|
class functions
|
||||||
{
|
{
|
||||||
// The array constructor will clean up in the event of an
|
friend class set_hash_functions<H, P>;
|
||||||
// exception.
|
functions& operator=(functions const&);
|
||||||
allocator_array_constructor<bucket_allocator>
|
|
||||||
constructor(bucket_alloc());
|
|
||||||
|
|
||||||
// Creates an extra bucket to act as a sentinel.
|
typedef compressed_pair<H, P> function_pair;
|
||||||
constructor.construct(bucket(), this->bucket_count_ + 1);
|
typedef BOOST_DEDUCED_TYPENAME ::boost::aligned_storage<
|
||||||
|
sizeof(function_pair),
|
||||||
|
::boost::alignment_of<function_pair>::value>::type aligned_function;
|
||||||
|
|
||||||
// Set up the sentinel (node_ptr cast)
|
bool current_; // The currently active functions.
|
||||||
bucket_ptr sentinel = constructor.get() +
|
aligned_function funcs_[2];
|
||||||
static_cast<std::ptrdiff_t>(this->bucket_count_);
|
|
||||||
sentinel->next_ = sentinel;
|
|
||||||
|
|
||||||
// Only release the buckets once everything is successfully
|
function_pair const& current() const {
|
||||||
// done.
|
return *static_cast<function_pair const*>(
|
||||||
this->buckets_ = constructor.release();
|
static_cast<void const*>(&funcs_[current_]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void construct(bool which, H const& hf, P const& eq)
|
||||||
|
{
|
||||||
|
new((void*) &funcs_[which]) function_pair(hf, eq);
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct(bool which, function_pair const& f)
|
||||||
|
{
|
||||||
|
new((void*) &funcs_[which]) function_pair(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void destroy(bool which)
|
||||||
|
{
|
||||||
|
::boost::unordered::detail::destroy((function_pair*)(&funcs_[which]));
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
functions(H const& hf, P const& eq)
|
||||||
|
: current_(false)
|
||||||
|
{
|
||||||
|
construct(current_, hf, eq);
|
||||||
|
}
|
||||||
|
|
||||||
|
functions(functions const& bf)
|
||||||
|
: current_(false)
|
||||||
|
{
|
||||||
|
construct(current_, bf.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
~functions() {
|
||||||
|
destroy(current_);
|
||||||
|
}
|
||||||
|
|
||||||
|
H const& hash_function() const {
|
||||||
|
return current().first();
|
||||||
|
}
|
||||||
|
|
||||||
|
P const& key_eq() const {
|
||||||
|
return current().second();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class H, class P>
|
||||||
|
class set_hash_functions
|
||||||
|
{
|
||||||
|
set_hash_functions(set_hash_functions const&);
|
||||||
|
set_hash_functions& operator=(set_hash_functions const&);
|
||||||
|
|
||||||
|
functions<H,P>& functions_;
|
||||||
|
bool tmp_functions_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
set_hash_functions(functions<H,P>& f, H const& h, P const& p)
|
||||||
|
: functions_(f),
|
||||||
|
tmp_functions_(!f.current_)
|
||||||
|
{
|
||||||
|
f.construct(tmp_functions_, h, p);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_hash_functions(functions<H,P>& f, functions<H,P> const& other)
|
||||||
|
: functions_(f),
|
||||||
|
tmp_functions_(!f.current_)
|
||||||
|
{
|
||||||
|
f.construct(tmp_functions_, other.current());
|
||||||
|
}
|
||||||
|
|
||||||
|
~set_hash_functions()
|
||||||
|
{
|
||||||
|
functions_.destroy(tmp_functions_);
|
||||||
|
}
|
||||||
|
|
||||||
|
void commit()
|
||||||
|
{
|
||||||
|
functions_.current_ = tmp_functions_;
|
||||||
|
tmp_functions_ = !tmp_functions_;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Constructors and Destructors
|
// Node Constructors
|
||||||
|
|
||||||
// no throw
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template <class A, class G>
|
|
||||||
inline void hash_buckets<A, G>::move(hash_buckets& other)
|
template <class T, class... Args>
|
||||||
|
inline void construct_impl(T*, void* address, Args&&... args)
|
||||||
{
|
{
|
||||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
new(address) T(std::forward<Args>(args)...);
|
||||||
if(this->buckets_) { this->delete_buckets(); }
|
|
||||||
this->buckets_ = other.buckets_;
|
|
||||||
this->bucket_count_ = other.bucket_count_;
|
|
||||||
other.buckets_ = bucket_ptr();
|
|
||||||
other.bucket_count_ = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class A, class G>
|
#else
|
||||||
inline void hash_buckets<A, G>::swap(hash_buckets<A, G>& other)
|
|
||||||
{
|
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
||||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
template < \
|
||||||
std::swap(buckets_, other.buckets_);
|
class T, \
|
||||||
std::swap(bucket_count_, other.bucket_count_);
|
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||||
|
> \
|
||||||
|
inline void construct_impl( \
|
||||||
|
T*, void* address, \
|
||||||
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||||
|
) \
|
||||||
|
{ \
|
||||||
|
new(address) T( \
|
||||||
|
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template <class First, class Second, class Key, \
|
||||||
|
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||||
|
> \
|
||||||
|
inline void construct_impl( \
|
||||||
|
std::pair<First, Second>*, void* address, \
|
||||||
|
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||||
|
{ \
|
||||||
|
new(address) std::pair<First, Second>(k, \
|
||||||
|
Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
|
||||||
}
|
}
|
||||||
}}
|
|
||||||
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||||
|
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
|
||||||
|
|
||||||
|
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Node construction
|
||||||
|
|
||||||
|
template <class Alloc, bool Unique>
|
||||||
|
class node_constructor
|
||||||
|
{
|
||||||
|
typedef ::boost::unordered::detail::buckets<Alloc, Unique> 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;
|
||||||
|
|
||||||
|
buckets& buckets_;
|
||||||
|
real_node_ptr node_;
|
||||||
|
bool node_constructed_;
|
||||||
|
bool value_constructed_;
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
node_constructor(buckets& m) :
|
||||||
|
buckets_(m),
|
||||||
|
node_(),
|
||||||
|
node_constructed_(false),
|
||||||
|
value_constructed_(false)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~node_constructor();
|
||||||
|
void construct_preamble();
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
|
template <class... Args>
|
||||||
|
void construct(Args&&... args)
|
||||||
|
{
|
||||||
|
construct_preamble();
|
||||||
|
construct_impl((value_type*) 0, node_->address(),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
value_constructed_ = true;
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
|
#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
|
||||||
|
template < \
|
||||||
|
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||||
|
> \
|
||||||
|
void construct( \
|
||||||
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||||
|
) \
|
||||||
|
{ \
|
||||||
|
construct_preamble(); \
|
||||||
|
construct_impl( \
|
||||||
|
(value_type*) 0, node_->address(), \
|
||||||
|
BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
||||||
|
); \
|
||||||
|
value_constructed_ = true; \
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||||
|
BOOST_UNORDERED_CONSTRUCT, _)
|
||||||
|
|
||||||
|
#undef BOOST_UNORDERED_CONSTRUCT
|
||||||
|
|
||||||
|
#endif
|
||||||
|
template <class K, class M>
|
||||||
|
void construct_pair(K const& k, M*)
|
||||||
|
{
|
||||||
|
construct_preamble();
|
||||||
|
new(node_->address()) value_type(k, M());
|
||||||
|
value_constructed_ = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
value_type& value() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(node_);
|
||||||
|
return node_->value();
|
||||||
|
}
|
||||||
|
|
||||||
|
// no throw
|
||||||
|
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
|
||||||
|
{
|
||||||
|
real_node_ptr p = node_;
|
||||||
|
node_ = real_node_ptr();
|
||||||
|
// node_ptr cast
|
||||||
|
return buckets_.bucket_alloc().address(*p);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
node_constructor(node_constructor const&);
|
||||||
|
node_constructor& operator=(node_constructor const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// node_constructor
|
||||||
|
|
||||||
|
template <class Alloc, bool Unique>
|
||||||
|
inline node_constructor<Alloc, Unique>::~node_constructor()
|
||||||
|
{
|
||||||
|
if (node_) {
|
||||||
|
if (value_constructed_) {
|
||||||
|
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
||||||
|
struct dummy { node<Alloc, Grouped> x; };
|
||||||
|
#endif
|
||||||
|
::boost::unordered::detail::destroy(node_->value_ptr());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (node_constructed_)
|
||||||
|
allocator_traits<node_allocator>::destroy(buckets_.node_alloc(),
|
||||||
|
boost::addressof(*node_));
|
||||||
|
|
||||||
|
allocator_traits<node_allocator>::deallocate(buckets_.node_alloc(), node_, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Alloc, bool Unique>
|
||||||
|
inline void node_constructor<Alloc, Unique>::construct_preamble()
|
||||||
|
{
|
||||||
|
if(!node_) {
|
||||||
|
node_constructed_ = false;
|
||||||
|
value_constructed_ = false;
|
||||||
|
|
||||||
|
node_ = allocator_traits<node_allocator>::allocate(buckets_.node_alloc(), 1);
|
||||||
|
allocator_traits<node_allocator>::construct(buckets_.node_alloc(),
|
||||||
|
boost::addressof(*node_), node());
|
||||||
|
node_->init(buckets_.bucket_alloc().address(*node_));
|
||||||
|
|
||||||
|
node_constructed_ = true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_ASSERT(node_constructed_ && value_constructed_);
|
||||||
|
::boost::unordered::detail::destroy(node_->value_ptr());
|
||||||
|
value_constructed_ = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// copy_buckets_to
|
||||||
|
//
|
||||||
|
// basic exception safety. If an exception is thrown this will
|
||||||
|
// leave dst partially filled and the buckets unset.
|
||||||
|
|
||||||
|
template <class A, bool Unique>
|
||||||
|
void buckets<A, Unique>::copy_buckets_to(buckets& dst) const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!dst.buckets_);
|
||||||
|
|
||||||
|
dst.create_buckets();
|
||||||
|
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
|
||||||
|
|
||||||
|
{
|
||||||
|
node_constructor<A, Unique> a(dst);
|
||||||
|
|
||||||
|
node_ptr n = this->buckets_[this->bucket_count_].next_;
|
||||||
|
node_ptr prev = dst_start;
|
||||||
|
|
||||||
|
while(n) {
|
||||||
|
std::size_t hash = node::get_hash(n);
|
||||||
|
node_ptr group_end = node::next_group(n);
|
||||||
|
|
||||||
|
a.construct(node::get_value(n));
|
||||||
|
node_ptr first_node = a.release();
|
||||||
|
node::set_hash(first_node, hash);
|
||||||
|
node_ptr end = prev->next_ = first_node;
|
||||||
|
++dst.size_;
|
||||||
|
|
||||||
|
for(n = n->next_; n != group_end; n = n->next_) {
|
||||||
|
a.construct(node::get_value(n));
|
||||||
|
end = a.release();
|
||||||
|
node::set_hash(end, hash);
|
||||||
|
node::add_after_node(end, first_node);
|
||||||
|
++dst.size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = dst.place_in_bucket(prev, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// move_buckets_to
|
||||||
|
//
|
||||||
|
// Basic exception safety. The source nodes are left in an unusable state
|
||||||
|
// if an exception throws.
|
||||||
|
|
||||||
|
template <class A, bool Unique>
|
||||||
|
void buckets<A, Unique>::move_buckets_to(buckets& dst) const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!dst.buckets_);
|
||||||
|
|
||||||
|
dst.create_buckets();
|
||||||
|
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
|
||||||
|
|
||||||
|
{
|
||||||
|
node_constructor<A, Unique> a(dst);
|
||||||
|
|
||||||
|
node_ptr n = this->buckets_[this->bucket_count_].next_;
|
||||||
|
node_ptr prev = dst_start;
|
||||||
|
|
||||||
|
while(n) {
|
||||||
|
std::size_t hash = node::get_hash(n);
|
||||||
|
node_ptr group_end = node::next_group(n);
|
||||||
|
|
||||||
|
a.construct(boost::move(node::get_value(n)));
|
||||||
|
node_ptr first_node = a.release();
|
||||||
|
node::set_hash(first_node, hash);
|
||||||
|
node_ptr end = prev->next_ = first_node;
|
||||||
|
++dst.size_;
|
||||||
|
|
||||||
|
for(n = n->next_; n != group_end; n = n->next_) {
|
||||||
|
a.construct(boost::move(node::get_value(n)));
|
||||||
|
end = a.release();
|
||||||
|
node::set_hash(end, hash);
|
||||||
|
node::add_after_node(end, first_node);
|
||||||
|
++dst.size_;
|
||||||
|
}
|
||||||
|
|
||||||
|
prev = dst.place_in_bucket(prev, end);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// strong otherwise exception safety
|
||||||
|
template <class A, bool Unique>
|
||||||
|
void buckets<A, Unique>::rehash_impl(std::size_t num_buckets)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(this->size_);
|
||||||
|
|
||||||
|
buckets dst(this->node_alloc(), num_buckets);
|
||||||
|
dst.create_buckets();
|
||||||
|
|
||||||
|
bucket_ptr src_start = this->get_bucket(this->bucket_count_);
|
||||||
|
bucket_ptr dst_start = dst.get_bucket(dst.bucket_count_);
|
||||||
|
|
||||||
|
dst_start->next_ = src_start->next_;
|
||||||
|
src_start->next_ = bucket_ptr();
|
||||||
|
dst.size_ = this->size_;
|
||||||
|
this->size_ = 0;
|
||||||
|
|
||||||
|
node_ptr prev = dst_start;
|
||||||
|
while (BOOST_UNORDERED_BORLAND_BOOL(prev->next_))
|
||||||
|
prev = dst.place_in_bucket(prev, node::next_group2(prev));
|
||||||
|
|
||||||
|
// Swap the new nodes back into the container and setup the
|
||||||
|
// variables.
|
||||||
|
dst.swap(*this); // no throw
|
||||||
|
}
|
||||||
|
}}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,19 +1,18 @@
|
|||||||
|
|
||||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||||
// Copyright (C) 2005-2009 Daniel James
|
// Copyright (C) 2005-2011 Daniel James
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_EQUIVALENT_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/unordered/detail/table.hpp>
|
|
||||||
#include <boost/unordered/detail/extract_key.hpp>
|
#include <boost/unordered/detail/extract_key.hpp>
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class hash_equivalent_table : public T::table
|
class equivalent_table : public T::table_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||||
@ -21,54 +20,212 @@ namespace boost { namespace unordered_detail {
|
|||||||
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::table table;
|
typedef BOOST_DEDUCED_TYPENAME T::table_base table_base;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
hash_equivalent_table(std::size_t n,
|
equivalent_table(std::size_t n,
|
||||||
hasher const& hf, key_equal const& eq, value_allocator const& a)
|
hasher const& hf, key_equal const& eq, value_allocator const& a)
|
||||||
: table(n, hf, eq, a) {}
|
: table_base(n, hf, eq, a) {}
|
||||||
hash_equivalent_table(hash_equivalent_table const& x)
|
equivalent_table(equivalent_table const& x)
|
||||||
: table(x, x.node_alloc()) {}
|
: table_base(x,
|
||||||
hash_equivalent_table(hash_equivalent_table const& x,
|
allocator_traits<node_allocator>::
|
||||||
|
select_on_container_copy_construction(x.node_alloc())) {}
|
||||||
|
equivalent_table(equivalent_table const& x,
|
||||||
value_allocator const& a)
|
value_allocator const& a)
|
||||||
: table(x, a) {}
|
: table_base(x, a) {}
|
||||||
hash_equivalent_table(hash_equivalent_table& x, move_tag m)
|
equivalent_table(equivalent_table& x, move_tag m)
|
||||||
: table(x, m) {}
|
: table_base(x, m) {}
|
||||||
hash_equivalent_table(hash_equivalent_table& x,
|
equivalent_table(equivalent_table& x,
|
||||||
value_allocator const& a, move_tag m)
|
value_allocator const& a, move_tag m)
|
||||||
: table(x, a, m) {}
|
: table_base(x, a, m) {}
|
||||||
~hash_equivalent_table() {}
|
~equivalent_table() {}
|
||||||
|
|
||||||
|
// Equality
|
||||||
|
|
||||||
|
bool equals(equivalent_table const& other) const
|
||||||
|
{
|
||||||
|
if(this->size_ != other.size_) return false;
|
||||||
|
if(!this->size_) return true;
|
||||||
|
|
||||||
|
for(node_ptr n1 = this->buckets_[this->bucket_count_].next_; n1;)
|
||||||
|
{
|
||||||
|
node_ptr n2 = other.find_matching_node(n1);
|
||||||
|
if (!n2) return false;
|
||||||
|
node_ptr end1 = node::next_group(n1);
|
||||||
|
node_ptr end2 = node::next_group(n2);
|
||||||
|
if (!group_equals(n1, end1, n2, end2)) return false;
|
||||||
|
n1 = end1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool group_equals(node_ptr n1, node_ptr end1,
|
||||||
|
node_ptr n2, node_ptr end2)
|
||||||
|
{
|
||||||
|
for(;;)
|
||||||
|
{
|
||||||
|
if (node::get_value(n1) != node::get_value(n2))
|
||||||
|
break;
|
||||||
|
|
||||||
|
n1 = n1->next_;
|
||||||
|
n2 = n2->next_;
|
||||||
|
|
||||||
|
if (n1 == end1) return n2 == end2;
|
||||||
|
if (n2 == end2) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for(node_ptr n1a = n1, n2a = n2;;)
|
||||||
|
{
|
||||||
|
n1a = n1a->next_;
|
||||||
|
n2a = n2a->next_;
|
||||||
|
|
||||||
|
if (n1a == end1)
|
||||||
|
{
|
||||||
|
if (n2a == end2) break;
|
||||||
|
else return false;
|
||||||
|
}
|
||||||
|
if (n2a == end2) return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
node_ptr start = n1;
|
||||||
|
for(;n1 != end2; n1 = n1->next_)
|
||||||
|
{
|
||||||
|
value_type const& v = node::get_value(n1);
|
||||||
|
if (find(start, n1, v)) continue;
|
||||||
|
std::size_t matches = count_equal(n2, end2, v);
|
||||||
|
if (!matches || matches != 1 + count_equal(n1->next_, end1, v))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool find(node_ptr n, node_ptr end, value_type const& v)
|
||||||
|
{
|
||||||
|
for(;n != end; n = n->next_)
|
||||||
|
if (node::get_value(n) == v)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::size_t count_equal(node_ptr n, node_ptr end, value_type const& v)
|
||||||
|
{
|
||||||
|
std::size_t count = 0;
|
||||||
|
for(;n != end; n = n->next_)
|
||||||
|
if (node::get_value(n) == v) ++count;
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// A convenience method for adding nodes.
|
||||||
|
|
||||||
|
inline node_ptr add_node(
|
||||||
|
node_constructor& a,
|
||||||
|
std::size_t bucket_index,
|
||||||
|
std::size_t hash,
|
||||||
|
node_ptr pos)
|
||||||
|
{
|
||||||
|
node_ptr n = a.release();
|
||||||
|
node::set_hash(n, hash);
|
||||||
|
|
||||||
|
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||||
|
node::add_after_node(n, pos);
|
||||||
|
if (n->next_) {
|
||||||
|
std::size_t next_bucket =
|
||||||
|
node::get_hash(n->next_) % this->bucket_count_;
|
||||||
|
if (next_bucket != bucket_index) {
|
||||||
|
this->buckets_[next_bucket].next_ = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
bucket_ptr b = this->get_bucket(bucket_index);
|
||||||
|
|
||||||
|
if (!b->next_)
|
||||||
|
{
|
||||||
|
bucket_ptr start_node =
|
||||||
|
this->get_bucket(this->bucket_count_);
|
||||||
|
|
||||||
|
if (BOOST_UNORDERED_BORLAND_BOOL(start_node->next_)) {
|
||||||
|
this->buckets_[
|
||||||
|
node::get_hash(start_node->next_) %
|
||||||
|
this->bucket_count_].next_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
b->next_ = start_node;
|
||||||
|
n->next_ = start_node->next_;
|
||||||
|
start_node->next_ = n;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
n->next_ = b->next_->next_;
|
||||||
|
b->next_->next_ = n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
++this->size_;
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
// Insert methods
|
// Insert methods
|
||||||
|
|
||||||
iterator_base emplace_impl(node_constructor& a);
|
node_ptr emplace_impl(node_constructor& a)
|
||||||
void emplace_impl_no_rehash(node_constructor& a);
|
{
|
||||||
|
key_type const& k = this->get_key(a.value());
|
||||||
|
std::size_t hash = this->hash_function()(k);
|
||||||
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
|
node_ptr position = this->find_node(bucket_index, hash, k);
|
||||||
|
|
||||||
|
// reserve has basic exception safety if the hash function
|
||||||
|
// throws, strong otherwise.
|
||||||
|
if(this->reserve_for_insert(this->size_ + 1)) {
|
||||||
|
bucket_index = hash % this->bucket_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
return add_node(a, bucket_index, hash, position);
|
||||||
|
}
|
||||||
|
|
||||||
// equals
|
void emplace_impl_no_rehash(node_constructor& a)
|
||||||
|
{
|
||||||
|
key_type const& k = this->get_key(a.value());
|
||||||
|
std::size_t hash = this->hash_function()(k);
|
||||||
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
|
add_node(a, bucket_index, hash,
|
||||||
|
this->find_node(bucket_index, hash, k));
|
||||||
|
}
|
||||||
|
|
||||||
bool equals(hash_equivalent_table const&) const;
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
|
|
||||||
inline node_ptr add_node(node_constructor& a,
|
|
||||||
bucket_ptr bucket, node_ptr pos);
|
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
|
||||||
|
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
iterator_base emplace(Args&&... args);
|
node_ptr emplace(Args&&... args)
|
||||||
|
{
|
||||||
|
// Create the node before rehashing in case it throws an
|
||||||
|
// exception (need strong safety in such a case).
|
||||||
|
node_constructor a(*this);
|
||||||
|
a.construct(std::forward<Args>(args)...);
|
||||||
|
|
||||||
|
return emplace_impl(a);
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
|
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
||||||
iterator_base emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
|
node_ptr emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
||||||
|
{ \
|
||||||
|
node_constructor a(*this); \
|
||||||
|
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
||||||
|
return emplace_impl(a); \
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
BOOST_UNORDERED_INSERT_IMPL, _)
|
||||||
@ -76,229 +233,75 @@ namespace boost { namespace unordered_detail {
|
|||||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
#undef BOOST_UNORDERED_INSERT_IMPL
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Insert range methods
|
||||||
|
|
||||||
|
// if hash function throws, or inserting > 1 element, basic exception
|
||||||
|
// safety. Strong otherwise
|
||||||
template <class I>
|
template <class I>
|
||||||
void insert_for_range(I i, I j, forward_traversal_tag);
|
void insert_for_range(I i, I j, forward_traversal_tag)
|
||||||
|
{
|
||||||
|
if(i == j) return;
|
||||||
|
std::size_t distance = ::boost::unordered::detail::distance(i, j);
|
||||||
|
if(distance == 1) {
|
||||||
|
emplace(*i);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Only require basic exception safety here
|
||||||
|
this->reserve_for_insert(this->size_ + distance);
|
||||||
|
|
||||||
|
node_constructor a(*this);
|
||||||
|
for (; i != j; ++i) {
|
||||||
|
a.construct(*i);
|
||||||
|
emplace_impl_no_rehash(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
template <class I>
|
template <class I>
|
||||||
void insert_for_range(I i, I j, boost::incrementable_traversal_tag);
|
void insert_for_range(I i, I j, ::boost::incrementable_traversal_tag)
|
||||||
|
{
|
||||||
|
node_constructor a(*this);
|
||||||
|
for (; i != j; ++i) {
|
||||||
|
a.construct(*i);
|
||||||
|
emplace_impl(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If hash function throws, or inserting > 1 element, basic exception
|
||||||
|
// safety. Strong otherwise
|
||||||
template <class I>
|
template <class I>
|
||||||
void insert_range(I i, I j);
|
void insert_range(I i, I j)
|
||||||
|
{
|
||||||
|
BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal<I>::type
|
||||||
|
iterator_traversal_tag;
|
||||||
|
insert_for_range(i, j, iterator_traversal_tag);
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class H, class P, class A>
|
template <class H, class P, class A>
|
||||||
struct multiset : public types<
|
struct multiset : public types<
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
|
||||||
H, P, A,
|
H, P, A,
|
||||||
set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
|
set_extractor<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
|
||||||
grouped>
|
false>
|
||||||
{
|
{
|
||||||
typedef hash_equivalent_table<multiset<H, P, A> > impl;
|
typedef equivalent_table<multiset<H, P, A> > impl;
|
||||||
typedef hash_table<multiset<H, P, A> > table;
|
typedef table<multiset<H, P, A> > table_base;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class K, class H, class P, class A>
|
template <class K, class H, class P, class A>
|
||||||
struct multimap : public types<
|
struct multimap : public types<
|
||||||
K, BOOST_DEDUCED_TYPENAME A::value_type,
|
K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
|
||||||
H, P, A,
|
H, P, A,
|
||||||
map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
|
map_extractor<K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
|
||||||
grouped>
|
false>
|
||||||
{
|
{
|
||||||
typedef hash_equivalent_table<multimap<K, H, P, A> > impl;
|
typedef equivalent_table<multimap<K, H, P, A> > impl;
|
||||||
typedef hash_table<multimap<K, H, P, A> > table;
|
typedef table<multimap<K, H, P, A> > table_base;
|
||||||
};
|
};
|
||||||
|
}}}
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Equality
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
bool hash_equivalent_table<T>
|
|
||||||
::equals(hash_equivalent_table<T> const& other) const
|
|
||||||
{
|
|
||||||
if(this->size_ != other.size_) return false;
|
|
||||||
if(!this->size_) return true;
|
|
||||||
|
|
||||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
|
||||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
|
|
||||||
{
|
|
||||||
node_ptr it1 = i->next_;
|
|
||||||
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
|
|
||||||
{
|
|
||||||
node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
|
|
||||||
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
|
|
||||||
|
|
||||||
node_ptr end1 = node::next_group(it1);
|
|
||||||
node_ptr end2 = node::next_group(it2);
|
|
||||||
|
|
||||||
do {
|
|
||||||
if(!extractor::compare_mapped(
|
|
||||||
node::get_value(it1), node::get_value(it2)))
|
|
||||||
return false;
|
|
||||||
it1 = it1->next_;
|
|
||||||
it2 = it2->next_;
|
|
||||||
} while(it1 != end1 && it2 != end2);
|
|
||||||
if(it1 != end1 || it2 != end2) return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// A convenience method for adding nodes.
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::node_ptr
|
|
||||||
hash_equivalent_table<T>
|
|
||||||
::add_node(node_constructor& a, bucket_ptr bucket, node_ptr pos)
|
|
||||||
{
|
|
||||||
node_ptr n = a.release();
|
|
||||||
if(BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
|
||||||
node::add_after_node(n, pos);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
node::add_to_bucket(n, *bucket);
|
|
||||||
if(bucket < this->cached_begin_bucket_)
|
|
||||||
this->cached_begin_bucket_ = bucket;
|
|
||||||
}
|
|
||||||
++this->size_;
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Insert methods
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME
|
|
||||||
hash_equivalent_table<T>::iterator_base
|
|
||||||
hash_equivalent_table<T>::emplace_impl(node_constructor& a)
|
|
||||||
{
|
|
||||||
key_type const& k = this->get_key(a.value());
|
|
||||||
std::size_t hash_value = this->hash_function()(k);
|
|
||||||
|
|
||||||
if(!this->size_) {
|
|
||||||
return this->emplace_empty_impl_with_node(a, 1);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
|
||||||
node_ptr position = this->find_iterator(bucket, k);
|
|
||||||
|
|
||||||
// reserve has basic exception safety if the hash function
|
|
||||||
// throws, strong otherwise.
|
|
||||||
if(this->reserve_for_insert(this->size_ + 1))
|
|
||||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
|
||||||
|
|
||||||
return iterator_base(bucket, add_node(a, bucket, position));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void hash_equivalent_table<T>
|
|
||||||
::emplace_impl_no_rehash(node_constructor& a)
|
|
||||||
{
|
|
||||||
key_type const& k = this->get_key(a.value());
|
|
||||||
bucket_ptr bucket = this->get_bucket(this->bucket_index(k));
|
|
||||||
add_node(a, bucket, this->find_iterator(bucket, k));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
|
||||||
|
|
||||||
// Emplace (equivalent key containers)
|
|
||||||
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
|
|
||||||
|
|
||||||
// if hash function throws, basic exception safety
|
|
||||||
// strong otherwise
|
|
||||||
template <class T>
|
|
||||||
template <class... Args>
|
|
||||||
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base
|
|
||||||
hash_equivalent_table<T>
|
|
||||||
::emplace(Args&&... args)
|
|
||||||
{
|
|
||||||
// Create the node before rehashing in case it throws an
|
|
||||||
// exception (need strong safety in such a case).
|
|
||||||
node_constructor a(*this);
|
|
||||||
a.construct(std::forward<Args>(args)...);
|
|
||||||
|
|
||||||
return emplace_impl(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
|
||||||
template <class T> \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
|
||||||
BOOST_DEDUCED_TYPENAME hash_equivalent_table<T>::iterator_base \
|
|
||||||
hash_equivalent_table<T> \
|
|
||||||
::emplace(BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
||||||
{ \
|
|
||||||
node_constructor a(*this); \
|
|
||||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
|
||||||
return emplace_impl(a); \
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
||||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
|
||||||
|
|
||||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Insert range methods
|
|
||||||
|
|
||||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
|
||||||
// strong otherwise
|
|
||||||
template <class T>
|
|
||||||
template <class I>
|
|
||||||
inline void hash_equivalent_table<T>
|
|
||||||
::insert_for_range(I i, I j, forward_traversal_tag)
|
|
||||||
{
|
|
||||||
if(i == j) return;
|
|
||||||
std::size_t distance = unordered_detail::distance(i, j);
|
|
||||||
if(distance == 1) {
|
|
||||||
emplace(*i);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
node_constructor a(*this);
|
|
||||||
|
|
||||||
// Only require basic exception safety here
|
|
||||||
if(this->size_) {
|
|
||||||
this->reserve_for_insert(this->size_ + distance);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
a.construct(*i++);
|
|
||||||
this->emplace_empty_impl_with_node(a, distance);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (; i != j; ++i) {
|
|
||||||
a.construct(*i);
|
|
||||||
emplace_impl_no_rehash(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
|
||||||
// strong otherwise
|
|
||||||
template <class T>
|
|
||||||
template <class I>
|
|
||||||
inline void hash_equivalent_table<T>
|
|
||||||
::insert_for_range(I i, I j, boost::incrementable_traversal_tag)
|
|
||||||
{
|
|
||||||
node_constructor a(*this);
|
|
||||||
for (; i != j; ++i) {
|
|
||||||
a.construct(*i);
|
|
||||||
emplace_impl(a);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
|
||||||
// strong otherwise
|
|
||||||
template <class T>
|
|
||||||
template <class I>
|
|
||||||
void hash_equivalent_table<T>::insert_range(I i, I j)
|
|
||||||
{
|
|
||||||
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
|
|
||||||
iterator_traversal_tag;
|
|
||||||
insert_for_range(i, j, iterator_traversal_tag);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,17 +1,16 @@
|
|||||||
|
|
||||||
// Copyright (C) 2005-2009 Daniel James
|
// Copyright (C) 2005-2011 Daniel James
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_EXTRACT_KEY_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/unordered/detail/table.hpp>
|
||||||
#include <boost/type_traits/remove_const.hpp>
|
|
||||||
#include <boost/unordered/detail/fwd.hpp>
|
|
||||||
|
|
||||||
namespace boost {
|
namespace boost {
|
||||||
namespace unordered_detail {
|
namespace unordered {
|
||||||
|
namespace detail {
|
||||||
|
|
||||||
// key extractors
|
// key extractors
|
||||||
//
|
//
|
||||||
@ -39,12 +38,19 @@ namespace unordered_detail {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if BOOST_UNORDERED_USE_RV_REF
|
||||||
|
static key_type const& extract(BOOST_RV_REF(key_type) v)
|
||||||
|
{
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
static no_key extract()
|
static no_key extract()
|
||||||
{
|
{
|
||||||
return no_key();
|
return no_key();
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template <class... Args>
|
template <class... Args>
|
||||||
static no_key extract(Args const&...)
|
static no_key extract(Args const&...)
|
||||||
{
|
{
|
||||||
@ -75,7 +81,7 @@ namespace unordered_detail {
|
|||||||
struct map_extractor
|
struct map_extractor
|
||||||
{
|
{
|
||||||
typedef ValueType value_type;
|
typedef ValueType value_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::remove_const<Key>::type key_type;
|
typedef BOOST_DEDUCED_TYPENAME ::boost::remove_const<Key>::type key_type;
|
||||||
|
|
||||||
static key_type const& extract(value_type const& v)
|
static key_type const& extract(value_type const& v)
|
||||||
{
|
{
|
||||||
@ -87,6 +93,13 @@ namespace unordered_detail {
|
|||||||
return v;
|
return v;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Why does this cause errors?
|
||||||
|
//
|
||||||
|
//static key_type const& extract(BOOST_RV_REF(key_type) v)
|
||||||
|
//{
|
||||||
|
// return v;
|
||||||
|
//}
|
||||||
|
|
||||||
template <class Second>
|
template <class Second>
|
||||||
static key_type const& extract(std::pair<key_type, Second> const& v)
|
static key_type const& extract(std::pair<key_type, Second> const& v)
|
||||||
{
|
{
|
||||||
@ -100,7 +113,7 @@ namespace unordered_detail {
|
|||||||
return v.first;
|
return v.first;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template <class Arg1, class... Args>
|
template <class Arg1, class... Args>
|
||||||
static key_type const& extract(key_type const& k,
|
static key_type const& extract(key_type const& k,
|
||||||
Arg1 const&, Args const&...)
|
Arg1 const&, Args const&...)
|
||||||
@ -143,6 +156,6 @@ namespace unordered_detail {
|
|||||||
return x.second == y.second;
|
return x.second == y.second;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}}
|
}}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,932 +1,50 @@
|
|||||||
|
|
||||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
// Copyright (C) 2008-2011 Daniel James.
|
||||||
// Copyright (C) 2005-2009 Daniel James
|
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
// This contains the basic data structure, apart from the actual values. There's
|
#ifndef BOOST_UNORDERED_FWD_HPP_INCLUDED
|
||||||
// no construction or deconstruction here. So this only depends on the pointer
|
#define BOOST_UNORDERED_FWD_HPP_INCLUDED
|
||||||
// type.
|
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
|
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||||
#define BOOST_UNORDERED_DETAIL_FWD_HPP_INCLUDED
|
# pragma once
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/iterator.hpp>
|
#include <memory>
|
||||||
#include <boost/compressed_pair.hpp>
|
#include <functional>
|
||||||
#include <boost/type_traits/aligned_storage.hpp>
|
#include <boost/functional/hash_fwd.hpp>
|
||||||
#include <boost/type_traits/alignment_of.hpp>
|
|
||||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
// This header defines most of the classes used to implement the unordered
|
namespace boost
|
||||||
// containers. It doesn't include the insert methods as they require a lot
|
{
|
||||||
// of preprocessor metaprogramming - they are in unique.hpp and equivalent.hpp.
|
namespace unordered
|
||||||
|
{
|
||||||
|
template <class K,
|
||||||
|
class T,
|
||||||
|
class H = hash<K>,
|
||||||
|
class P = std::equal_to<K>,
|
||||||
|
class A = std::allocator<std::pair<const K, T> > >
|
||||||
|
class unordered_map;
|
||||||
|
|
||||||
// Template parameters:
|
template <class K,
|
||||||
//
|
class T,
|
||||||
// H = Hash Function
|
class H = hash<K>,
|
||||||
// P = Predicate
|
class P = std::equal_to<K>,
|
||||||
// A = Value Allocator
|
class A = std::allocator<std::pair<const K, T> > >
|
||||||
// G = Bucket group policy, 'grouped' or 'ungrouped'
|
class unordered_multimap;
|
||||||
// E = Key Extractor
|
|
||||||
|
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
template <class T,
|
||||||
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
class H = hash<T>,
|
||||||
// STLport doesn't have std::forward.
|
class P = std::equal_to<T>,
|
||||||
# else
|
class A = std::allocator<T> >
|
||||||
# define BOOST_UNORDERED_STD_FORWARD
|
class unordered_set;
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
|
template <class T,
|
||||||
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
|
class H = hash<T>,
|
||||||
#endif
|
class P = std::equal_to<T>,
|
||||||
|
class A = std::allocator<T> >
|
||||||
#if !defined(BOOST_UNORDERED_STD_FORWARD)
|
class unordered_multiset;
|
||||||
|
}
|
||||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
}
|
||||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
|
||||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
|
||||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
|
|
||||||
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
|
||||||
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, num_params, Arg, const& arg)
|
|
||||||
#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
|
||||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, arg)
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
|
||||||
|
|
||||||
static const float minimum_max_load_factor = 1e-3f;
|
|
||||||
static const std::size_t default_bucket_count = 11;
|
|
||||||
struct move_tag {};
|
|
||||||
|
|
||||||
template <class T> class hash_unique_table;
|
|
||||||
template <class T> class hash_equivalent_table;
|
|
||||||
template <class Alloc, class Grouped>
|
|
||||||
class hash_node_constructor;
|
|
||||||
template <class ValueType>
|
|
||||||
struct set_extractor;
|
|
||||||
template <class Key, class ValueType>
|
|
||||||
struct map_extractor;
|
|
||||||
struct no_key;
|
|
||||||
|
|
||||||
// Explicitly call a destructor
|
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
|
||||||
#pragma warning(push)
|
|
||||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
|
||||||
#endif
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
inline void destroy(T* x) {
|
|
||||||
x->~T();
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
|
||||||
#pragma warning(pop)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// This section implements buckets and nodes. Here's a rough
|
|
||||||
// inheritance diagram, to show how they pull together.
|
|
||||||
//
|
|
||||||
// For unordered_set/unordered_map:
|
|
||||||
//
|
|
||||||
// hash_bucket<A>
|
|
||||||
// |
|
|
||||||
// ungrouped_node_base<A> value_base<A::value_type>
|
|
||||||
// | |
|
|
||||||
// +--------------+-------------+
|
|
||||||
// |
|
|
||||||
// hash_node<A, ungrouped>
|
|
||||||
//
|
|
||||||
// For unordered_multiset/unordered_multimap:
|
|
||||||
//
|
|
||||||
// hash_bucket<A>
|
|
||||||
// |
|
|
||||||
// grouped_node_base<A> value_base<A::value_type>
|
|
||||||
// | |
|
|
||||||
// +--------------+-------------+
|
|
||||||
// |
|
|
||||||
// hash_node<A, grouped>
|
|
||||||
|
|
||||||
// hash_bucket
|
|
||||||
//
|
|
||||||
// hash_bucket is used for both the buckets and as a base class for
|
|
||||||
// nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
|
|
||||||
// to either a bucket or a node. This is used later to implement a
|
|
||||||
// sentinel at the end of the bucket array.
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
class hash_bucket
|
|
||||||
{
|
|
||||||
hash_bucket& operator=(hash_bucket const&);
|
|
||||||
public:
|
|
||||||
typedef hash_bucket<A> bucket;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME
|
|
||||||
boost::unordered_detail::rebind_wrap<A, bucket>::type
|
|
||||||
bucket_allocator;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket_allocator::pointer bucket_ptr;
|
|
||||||
typedef bucket_ptr node_ptr;
|
|
||||||
|
|
||||||
node_ptr next_;
|
|
||||||
|
|
||||||
hash_bucket() : next_() {}
|
|
||||||
};
|
|
||||||
|
|
||||||
// In containers with equivalent keys (unordered_multimap and
|
|
||||||
// unordered_multiset) equivalent nodes are grouped together, in
|
|
||||||
// containers with unique keys (unordered_map and unordered_set)
|
|
||||||
// individual nodes are treated as groups of one. The following two
|
|
||||||
// classes implement the data structure.
|
|
||||||
|
|
||||||
// This is used for containers with unique keys. There are no groups
|
|
||||||
// so it doesn't add any extra members, and just treats individual
|
|
||||||
// nodes as groups of one.
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
struct ungrouped_node_base : hash_bucket<A> {
|
|
||||||
typedef hash_bucket<A> bucket;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
|
||||||
|
|
||||||
ungrouped_node_base() : bucket() {}
|
|
||||||
static inline node_ptr& next_group(node_ptr ptr);
|
|
||||||
static inline std::size_t group_count(node_ptr ptr);
|
|
||||||
static inline void add_to_bucket(node_ptr n, bucket& b);
|
|
||||||
static inline void add_after_node(node_ptr n, node_ptr position);
|
|
||||||
static void unlink_node(bucket& b, node_ptr n);
|
|
||||||
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
|
|
||||||
static void unlink_nodes(bucket& b, node_ptr end);
|
|
||||||
};
|
|
||||||
|
|
||||||
// This is used for containers with equivalent keys. It implements a
|
|
||||||
// circular list running in the opposite direction to the linked
|
|
||||||
// list through the nodes.
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
struct grouped_node_base : hash_bucket<A>
|
|
||||||
{
|
|
||||||
typedef hash_bucket<A> bucket;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
|
||||||
|
|
||||||
node_ptr group_prev_;
|
|
||||||
|
|
||||||
grouped_node_base() : bucket(), group_prev_() {}
|
|
||||||
static inline node_ptr& next_group(node_ptr ptr);
|
|
||||||
static inline node_ptr first_in_group(node_ptr n);
|
|
||||||
static inline std::size_t group_count(node_ptr ptr);
|
|
||||||
static inline void add_to_bucket(node_ptr n, bucket& b);
|
|
||||||
static inline void add_after_node(node_ptr n, node_ptr position);
|
|
||||||
static void unlink_node(bucket& b, node_ptr n);
|
|
||||||
static void unlink_nodes(bucket& b, node_ptr begin, node_ptr end);
|
|
||||||
static void unlink_nodes(bucket& b, node_ptr end);
|
|
||||||
|
|
||||||
private:
|
|
||||||
static inline node_ptr split_group(node_ptr split);
|
|
||||||
static inline grouped_node_base& get(node_ptr ptr) {
|
|
||||||
return static_cast<grouped_node_base&>(*ptr);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// These two classes implement an easy way to pass around the node
|
|
||||||
// group policy classes without the messy template parameters.
|
|
||||||
// Whenever you see the template parameter 'G' it's one of these.
|
|
||||||
|
|
||||||
struct ungrouped
|
|
||||||
{
|
|
||||||
template <class A>
|
|
||||||
struct base {
|
|
||||||
typedef ungrouped_node_base<A> type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct grouped
|
|
||||||
{
|
|
||||||
template <class A>
|
|
||||||
struct base {
|
|
||||||
typedef grouped_node_base<A> type;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
// The space used to store values in a node.
|
|
||||||
|
|
||||||
template <class ValueType>
|
|
||||||
struct value_base
|
|
||||||
{
|
|
||||||
typedef ValueType value_type;
|
|
||||||
BOOST_DEDUCED_TYPENAME boost::aligned_storage<
|
|
||||||
sizeof(value_type),
|
|
||||||
::boost::alignment_of<value_type>::value>::type data_;
|
|
||||||
|
|
||||||
void* address() {
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
value_type& value() {
|
|
||||||
return *(ValueType*) this;
|
|
||||||
}
|
|
||||||
value_type* value_ptr() {
|
|
||||||
return (ValueType*) this;
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
value_base& operator=(value_base const&);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Node
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_node :
|
|
||||||
public G::BOOST_NESTED_TEMPLATE base<A>::type,
|
|
||||||
public value_base<BOOST_DEDUCED_TYPENAME A::value_type>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME hash_bucket<A>::node_ptr node_ptr;
|
|
||||||
|
|
||||||
static value_type& get_value(node_ptr p) {
|
|
||||||
return static_cast<hash_node&>(*p).value();
|
|
||||||
}
|
|
||||||
static value_type* get_value_ptr(node_ptr p) {
|
|
||||||
return static_cast<hash_node&>(*p).value_ptr();
|
|
||||||
}
|
|
||||||
private:
|
|
||||||
hash_node& operator=(hash_node const&);
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Iterator Base
|
|
||||||
//
|
|
||||||
// This is the iterator used internally, the external iterators are
|
|
||||||
// provided by lightweight wrappers (hash_iterator and
|
|
||||||
// hast_const_iterator) which provide the full iterator interface.
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_iterator_base
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef A value_allocator;
|
|
||||||
typedef hash_bucket<A> bucket;
|
|
||||||
typedef hash_node<A, G> node;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
|
||||||
|
|
||||||
bucket_ptr bucket_;
|
|
||||||
node_ptr node_;
|
|
||||||
|
|
||||||
hash_iterator_base() : bucket_(), node_() {}
|
|
||||||
explicit hash_iterator_base(bucket_ptr b)
|
|
||||||
: bucket_(b),
|
|
||||||
node_(b ? b->next_ : node_ptr()) {}
|
|
||||||
hash_iterator_base(bucket_ptr b, node_ptr n)
|
|
||||||
: bucket_(b),
|
|
||||||
node_(n) {}
|
|
||||||
|
|
||||||
bool operator==(hash_iterator_base const& x) const {
|
|
||||||
return node_ == x.node_; }
|
|
||||||
bool operator!=(hash_iterator_base const& x) const {
|
|
||||||
return node_ != x.node_; }
|
|
||||||
value_type& operator*() const {
|
|
||||||
return node::get_value(node_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void increment_bucket(node_ptr n) {
|
|
||||||
while(!n) {
|
|
||||||
++bucket_;
|
|
||||||
n = bucket_->next_;
|
|
||||||
}
|
|
||||||
node_ = bucket_ == n ? node_ptr() : n;
|
|
||||||
}
|
|
||||||
|
|
||||||
void increment() {
|
|
||||||
increment_bucket(node_->next_);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Now the main data structure:
|
|
||||||
//
|
|
||||||
// hash_buckets<A, G> hash_buffered_functions<H, P>
|
|
||||||
// | |
|
|
||||||
// +-------------+--------------+
|
|
||||||
// |
|
|
||||||
// hash_table<T>
|
|
||||||
//
|
|
||||||
// T is a class which contains typedefs for all the types we need.
|
|
||||||
|
|
||||||
// hash_buckets
|
|
||||||
//
|
|
||||||
// This is responsible for allocating and deallocating buckets and nodes.
|
|
||||||
//
|
|
||||||
// Notes:
|
|
||||||
// 1. For the sake exception safety the consturctors don't allocate
|
|
||||||
// anything.
|
|
||||||
// 2. It's the callers responsibility to allocate the buckets before calling
|
|
||||||
// any of the methods (other than getters and setters).
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_buckets
|
|
||||||
{
|
|
||||||
hash_buckets(hash_buckets const&);
|
|
||||||
hash_buckets& operator=(hash_buckets const&);
|
|
||||||
public:
|
|
||||||
// Types
|
|
||||||
|
|
||||||
typedef A value_allocator;
|
|
||||||
typedef hash_bucket<A> bucket;
|
|
||||||
typedef hash_iterator_base<A, G> iterator_base;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME iterator_base::node node;
|
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_allocator
|
|
||||||
bucket_allocator;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::bucket_ptr bucket_ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME bucket::node_ptr node_ptr;
|
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME rebind_wrap<value_allocator, node>::type
|
|
||||||
node_allocator;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME node_allocator::pointer real_node_ptr;
|
|
||||||
|
|
||||||
// Members
|
|
||||||
|
|
||||||
bucket_ptr buckets_;
|
|
||||||
std::size_t bucket_count_;
|
|
||||||
boost::compressed_pair<bucket_allocator, node_allocator> allocators_;
|
|
||||||
|
|
||||||
// Data access
|
|
||||||
|
|
||||||
bucket_allocator const& bucket_alloc() const {
|
|
||||||
return allocators_.first(); }
|
|
||||||
node_allocator const& node_alloc() const {
|
|
||||||
return allocators_.second(); }
|
|
||||||
bucket_allocator& bucket_alloc() {
|
|
||||||
return allocators_.first(); }
|
|
||||||
node_allocator& node_alloc() {
|
|
||||||
return allocators_.second(); }
|
|
||||||
std::size_t max_bucket_count() const;
|
|
||||||
|
|
||||||
// Constructors
|
|
||||||
|
|
||||||
hash_buckets(node_allocator const& a, std::size_t n);
|
|
||||||
void create_buckets();
|
|
||||||
~hash_buckets();
|
|
||||||
|
|
||||||
// no throw
|
|
||||||
void swap(hash_buckets& other);
|
|
||||||
void move(hash_buckets& other);
|
|
||||||
|
|
||||||
// For the remaining functions, buckets_ must not be null.
|
|
||||||
|
|
||||||
bucket_ptr get_bucket(std::size_t n) const;
|
|
||||||
bucket_ptr bucket_ptr_from_hash(std::size_t hashed) const;
|
|
||||||
std::size_t bucket_size(std::size_t index) const;
|
|
||||||
node_ptr bucket_begin(std::size_t n) const;
|
|
||||||
|
|
||||||
// Alloc/Dealloc
|
|
||||||
|
|
||||||
void delete_node(node_ptr);
|
|
||||||
|
|
||||||
//
|
|
||||||
void delete_buckets();
|
|
||||||
void clear_bucket(bucket_ptr);
|
|
||||||
std::size_t delete_nodes(node_ptr begin, node_ptr end);
|
|
||||||
std::size_t delete_to_bucket_end(node_ptr begin);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Assigning and swapping the equality and hash function objects
|
|
||||||
// needs strong exception safety. To implement that normally we'd
|
|
||||||
// require one of them to be known to not throw and the other to
|
|
||||||
// guarantee strong exception safety. Unfortunately they both only
|
|
||||||
// have basic exception safety. So to acheive strong exception
|
|
||||||
// safety we have storage space for two copies, and assign the new
|
|
||||||
// copies to the unused space. Then switch to using that to use
|
|
||||||
// them. This is implemented in 'set_hash_functions' which
|
|
||||||
// atomically assigns the new function objects in a strongly
|
|
||||||
// exception safe manner.
|
|
||||||
|
|
||||||
template <class H, class P> class set_hash_functions;
|
|
||||||
|
|
||||||
template <class H, class P>
|
|
||||||
class hash_buffered_functions
|
|
||||||
{
|
|
||||||
friend class set_hash_functions<H, P>;
|
|
||||||
hash_buffered_functions& operator=(hash_buffered_functions const&);
|
|
||||||
|
|
||||||
typedef boost::compressed_pair<H, P> function_pair;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME boost::aligned_storage<
|
|
||||||
sizeof(function_pair),
|
|
||||||
::boost::alignment_of<function_pair>::value>::type aligned_function;
|
|
||||||
|
|
||||||
bool current_; // The currently active functions.
|
|
||||||
aligned_function funcs_[2];
|
|
||||||
|
|
||||||
function_pair const& current() const {
|
|
||||||
return *static_cast<function_pair const*>(
|
|
||||||
static_cast<void const*>(&funcs_[current_]));
|
|
||||||
}
|
|
||||||
|
|
||||||
void construct(bool which, H const& hf, P const& eq)
|
|
||||||
{
|
|
||||||
new((void*) &funcs_[which]) function_pair(hf, eq);
|
|
||||||
}
|
|
||||||
|
|
||||||
void construct(bool which, function_pair const& f)
|
|
||||||
{
|
|
||||||
new((void*) &funcs_[which]) function_pair(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy(bool which)
|
|
||||||
{
|
|
||||||
boost::unordered_detail::destroy((function_pair*)(&funcs_[which]));
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
hash_buffered_functions(H const& hf, P const& eq)
|
|
||||||
: current_(false)
|
|
||||||
{
|
|
||||||
construct(current_, hf, eq);
|
|
||||||
}
|
|
||||||
|
|
||||||
hash_buffered_functions(hash_buffered_functions const& bf)
|
|
||||||
: current_(false)
|
|
||||||
{
|
|
||||||
construct(current_, bf.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
~hash_buffered_functions() {
|
|
||||||
destroy(current_);
|
|
||||||
}
|
|
||||||
|
|
||||||
H const& hash_function() const {
|
|
||||||
return current().first();
|
|
||||||
}
|
|
||||||
|
|
||||||
P const& key_eq() const {
|
|
||||||
return current().second();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class H, class P>
|
|
||||||
class set_hash_functions
|
|
||||||
{
|
|
||||||
set_hash_functions(set_hash_functions const&);
|
|
||||||
set_hash_functions& operator=(set_hash_functions const&);
|
|
||||||
|
|
||||||
typedef hash_buffered_functions<H, P> buffered_functions;
|
|
||||||
buffered_functions& buffered_functions_;
|
|
||||||
bool tmp_functions_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
set_hash_functions(buffered_functions& f, H const& h, P const& p)
|
|
||||||
: buffered_functions_(f),
|
|
||||||
tmp_functions_(!f.current_)
|
|
||||||
{
|
|
||||||
f.construct(tmp_functions_, h, p);
|
|
||||||
}
|
|
||||||
|
|
||||||
set_hash_functions(buffered_functions& f,
|
|
||||||
buffered_functions const& other)
|
|
||||||
: buffered_functions_(f),
|
|
||||||
tmp_functions_(!f.current_)
|
|
||||||
{
|
|
||||||
f.construct(tmp_functions_, other.current());
|
|
||||||
}
|
|
||||||
|
|
||||||
~set_hash_functions()
|
|
||||||
{
|
|
||||||
buffered_functions_.destroy(tmp_functions_);
|
|
||||||
}
|
|
||||||
|
|
||||||
void commit()
|
|
||||||
{
|
|
||||||
buffered_functions_.current_ = tmp_functions_;
|
|
||||||
tmp_functions_ = !tmp_functions_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// This implements almost all of the required functionality, apart
|
|
||||||
// from some things that are specific to containers with unique and
|
|
||||||
// equivalent keys which is implemented in hash_unique_table and
|
|
||||||
// hash_equivalent_table. See unique.hpp and equivalent.hpp for
|
|
||||||
// their declaration and implementation.
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
class hash_table : public T::buckets, public T::buffered_functions
|
|
||||||
{
|
|
||||||
hash_table(hash_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::buffered_functions base;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::buckets buckets;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
|
||||||
typedef BOOST_DEDUCED_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::iterator_base iterator_base;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_pair iterator_pair;
|
|
||||||
|
|
||||||
// Members
|
|
||||||
|
|
||||||
std::size_t size_;
|
|
||||||
float mlf_;
|
|
||||||
// Cached data - invalid if !this->buckets_
|
|
||||||
bucket_ptr cached_begin_bucket_;
|
|
||||||
std::size_t max_load_;
|
|
||||||
|
|
||||||
// Helper methods
|
|
||||||
|
|
||||||
key_type const& get_key(value_type const& v) const {
|
|
||||||
return extractor::extract(v);
|
|
||||||
}
|
|
||||||
key_type const& get_key_from_ptr(node_ptr n) const {
|
|
||||||
return extractor::extract(node::get_value(n));
|
|
||||||
}
|
|
||||||
bool equal(key_type const& k, value_type const& v) const;
|
|
||||||
template <class Key, class Pred>
|
|
||||||
node_ptr find_iterator(bucket_ptr bucket, Key const& k,
|
|
||||||
Pred const&) const;
|
|
||||||
node_ptr find_iterator(bucket_ptr bucket, key_type const& k) const;
|
|
||||||
node_ptr find_iterator(key_type const& k) const;
|
|
||||||
node_ptr* find_for_erase(bucket_ptr bucket, key_type const& k) const;
|
|
||||||
|
|
||||||
// Load methods
|
|
||||||
|
|
||||||
std::size_t max_size() const;
|
|
||||||
std::size_t bucket_index(key_type const& k) const;
|
|
||||||
void max_load_factor(float z);
|
|
||||||
std::size_t min_buckets_for_size(std::size_t n) const;
|
|
||||||
std::size_t calculate_max_load();
|
|
||||||
|
|
||||||
// Constructors
|
|
||||||
|
|
||||||
hash_table(std::size_t n, hasher const& hf, key_equal const& eq,
|
|
||||||
node_allocator const& a);
|
|
||||||
hash_table(hash_table const& x, node_allocator const& a);
|
|
||||||
hash_table(hash_table& x, move_tag m);
|
|
||||||
hash_table(hash_table& x, node_allocator const& a, move_tag m);
|
|
||||||
~hash_table() {}
|
|
||||||
hash_table& operator=(hash_table const&);
|
|
||||||
|
|
||||||
// Iterators
|
|
||||||
|
|
||||||
iterator_base begin() const {
|
|
||||||
return this->size_ ?
|
|
||||||
iterator_base(this->cached_begin_bucket_) :
|
|
||||||
iterator_base();
|
|
||||||
}
|
|
||||||
iterator_base end() const {
|
|
||||||
return iterator_base();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Swap & Move
|
|
||||||
|
|
||||||
void swap(hash_table& x);
|
|
||||||
void fast_swap(hash_table& other);
|
|
||||||
void slow_swap(hash_table& other);
|
|
||||||
void partial_swap(hash_table& other);
|
|
||||||
void move(hash_table& x);
|
|
||||||
|
|
||||||
// Reserve and rehash
|
|
||||||
|
|
||||||
void create_for_insert(std::size_t n);
|
|
||||||
bool reserve_for_insert(std::size_t n);
|
|
||||||
void rehash(std::size_t n);
|
|
||||||
void rehash_impl(std::size_t n);
|
|
||||||
|
|
||||||
// Move/copy buckets
|
|
||||||
|
|
||||||
void move_buckets_to(buckets& dst);
|
|
||||||
void copy_buckets_to(buckets& dst) const;
|
|
||||||
|
|
||||||
// Misc. key methods
|
|
||||||
|
|
||||||
std::size_t count(key_type const& k) const;
|
|
||||||
iterator_base find(key_type const& k) const;
|
|
||||||
template <class Key, class Hash, class Pred>
|
|
||||||
iterator_base find(Key const& k, Hash const& h, Pred const& eq) const;
|
|
||||||
value_type& at(key_type const& k) const;
|
|
||||||
iterator_pair equal_range(key_type const& k) const;
|
|
||||||
|
|
||||||
// Erase
|
|
||||||
//
|
|
||||||
// no throw
|
|
||||||
|
|
||||||
void clear();
|
|
||||||
std::size_t erase_key(key_type const& k);
|
|
||||||
iterator_base erase_return_iterator(iterator_base r);
|
|
||||||
void erase(iterator_base r);
|
|
||||||
std::size_t erase_group(node_ptr* it, bucket_ptr bucket);
|
|
||||||
iterator_base erase_range(iterator_base r1, iterator_base r2);
|
|
||||||
|
|
||||||
// recompute_begin_bucket
|
|
||||||
|
|
||||||
void init_buckets();
|
|
||||||
|
|
||||||
// After an erase cached_begin_bucket_ might be left pointing to
|
|
||||||
// an empty bucket, so this is called to update it
|
|
||||||
//
|
|
||||||
// no throw
|
|
||||||
|
|
||||||
void recompute_begin_bucket(bucket_ptr b);
|
|
||||||
|
|
||||||
// This is called when a range has been erased
|
|
||||||
//
|
|
||||||
// no throw
|
|
||||||
|
|
||||||
void recompute_begin_bucket(bucket_ptr b1, bucket_ptr b2);
|
|
||||||
|
|
||||||
// no throw
|
|
||||||
float load_factor() const;
|
|
||||||
|
|
||||||
iterator_base emplace_empty_impl_with_node(
|
|
||||||
node_constructor&, std::size_t);
|
|
||||||
};
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// Iterators
|
|
||||||
|
|
||||||
// iterator_access is used to access the internal iterator without
|
|
||||||
// making it publicly available.
|
|
||||||
|
|
||||||
class iterator_access
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
template <class Iterator>
|
|
||||||
static BOOST_DEDUCED_TYPENAME Iterator::base const&
|
|
||||||
get(Iterator const& it)
|
|
||||||
{
|
|
||||||
return it.base_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A, class G> class hash_iterator;
|
|
||||||
template <class A, class G> class hash_const_iterator;
|
|
||||||
template <class A, class G> class hash_local_iterator;
|
|
||||||
template <class A, class G> class hash_const_local_iterator;
|
|
||||||
|
|
||||||
// Local Iterators
|
|
||||||
//
|
|
||||||
// all no throw
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_local_iterator
|
|
||||||
: public boost::iterator <
|
|
||||||
std::forward_iterator_tag,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
std::ptrdiff_t,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::pointer,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::reference>
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef hash_buckets<A, G> buckets;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr node_ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
|
||||||
typedef hash_const_local_iterator<A, G> const_local_iterator;
|
|
||||||
|
|
||||||
friend class hash_const_local_iterator<A, G>;
|
|
||||||
node_ptr ptr_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
hash_local_iterator() : ptr_() {}
|
|
||||||
explicit hash_local_iterator(node_ptr x) : ptr_(x) {}
|
|
||||||
BOOST_DEDUCED_TYPENAME A::reference operator*() const {
|
|
||||||
return node::get_value(ptr_);
|
|
||||||
}
|
|
||||||
value_type* operator->() const {
|
|
||||||
return node::get_value_ptr(ptr_);
|
|
||||||
}
|
|
||||||
hash_local_iterator& operator++() {
|
|
||||||
ptr_ = ptr_->next_; return *this;
|
|
||||||
}
|
|
||||||
hash_local_iterator operator++(int) {
|
|
||||||
hash_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp; }
|
|
||||||
bool operator==(hash_local_iterator x) const {
|
|
||||||
return ptr_ == x.ptr_;
|
|
||||||
}
|
|
||||||
bool operator==(const_local_iterator x) const {
|
|
||||||
return ptr_ == x.ptr_;
|
|
||||||
}
|
|
||||||
bool operator!=(hash_local_iterator x) const {
|
|
||||||
return ptr_ != x.ptr_;
|
|
||||||
}
|
|
||||||
bool operator!=(const_local_iterator x) const {
|
|
||||||
return ptr_ != x.ptr_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_const_local_iterator
|
|
||||||
: public boost::iterator <
|
|
||||||
std::forward_iterator_tag,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
std::ptrdiff_t,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::const_pointer,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::const_reference >
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef hash_buckets<A, G> buckets;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_ptr ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
|
||||||
typedef hash_local_iterator<A, G> local_iterator;
|
|
||||||
friend class hash_local_iterator<A, G>;
|
|
||||||
ptr ptr_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
hash_const_local_iterator() : ptr_() {}
|
|
||||||
explicit hash_const_local_iterator(ptr x) : ptr_(x) {}
|
|
||||||
hash_const_local_iterator(local_iterator x) : ptr_(x.ptr_) {}
|
|
||||||
BOOST_DEDUCED_TYPENAME A::const_reference
|
|
||||||
operator*() const {
|
|
||||||
return node::get_value(ptr_);
|
|
||||||
}
|
|
||||||
value_type const* operator->() const {
|
|
||||||
return node::get_value_ptr(ptr_);
|
|
||||||
}
|
|
||||||
hash_const_local_iterator& operator++() {
|
|
||||||
ptr_ = ptr_->next_; return *this;
|
|
||||||
}
|
|
||||||
hash_const_local_iterator operator++(int) {
|
|
||||||
hash_const_local_iterator tmp(ptr_); ptr_ = ptr_->next_; return tmp;
|
|
||||||
}
|
|
||||||
bool operator==(local_iterator x) const {
|
|
||||||
return ptr_ == x.ptr_;
|
|
||||||
}
|
|
||||||
bool operator==(hash_const_local_iterator x) const {
|
|
||||||
return ptr_ == x.ptr_;
|
|
||||||
}
|
|
||||||
bool operator!=(local_iterator x) const {
|
|
||||||
return ptr_ != x.ptr_;
|
|
||||||
}
|
|
||||||
bool operator!=(hash_const_local_iterator x) const {
|
|
||||||
return ptr_ != x.ptr_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Iterators
|
|
||||||
//
|
|
||||||
// all no throw
|
|
||||||
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_iterator
|
|
||||||
: public boost::iterator <
|
|
||||||
std::forward_iterator_tag,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
std::ptrdiff_t,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::pointer,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::reference >
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef hash_buckets<A, G> buckets;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base;
|
|
||||||
typedef hash_const_iterator<A, G> const_iterator;
|
|
||||||
friend class hash_const_iterator<A, G>;
|
|
||||||
base base_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
hash_iterator() : base_() {}
|
|
||||||
explicit hash_iterator(base const& x) : base_(x) {}
|
|
||||||
BOOST_DEDUCED_TYPENAME A::reference operator*() const {
|
|
||||||
return *base_;
|
|
||||||
}
|
|
||||||
value_type* operator->() const {
|
|
||||||
return &*base_;
|
|
||||||
}
|
|
||||||
hash_iterator& operator++() {
|
|
||||||
base_.increment(); return *this;
|
|
||||||
}
|
|
||||||
hash_iterator operator++(int) {
|
|
||||||
hash_iterator tmp(base_); base_.increment(); return tmp;
|
|
||||||
}
|
|
||||||
bool operator==(hash_iterator const& x) const {
|
|
||||||
return base_ == x.base_;
|
|
||||||
}
|
|
||||||
bool operator==(const_iterator const& x) const {
|
|
||||||
return base_ == x.base_;
|
|
||||||
}
|
|
||||||
bool operator!=(hash_iterator const& x) const {
|
|
||||||
return base_ != x.base_;
|
|
||||||
}
|
|
||||||
bool operator!=(const_iterator const& x) const {
|
|
||||||
return base_ != x.base_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class A, class G>
|
|
||||||
class hash_const_iterator
|
|
||||||
: public boost::iterator <
|
|
||||||
std::forward_iterator_tag,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
std::ptrdiff_t,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::const_pointer,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::const_reference >
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME A::value_type value_type;
|
|
||||||
|
|
||||||
private:
|
|
||||||
typedef hash_buckets<A, G> buckets;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::iterator_base base;
|
|
||||||
typedef hash_iterator<A, G> iterator;
|
|
||||||
friend class hash_iterator<A, G>;
|
|
||||||
friend class iterator_access;
|
|
||||||
base base_;
|
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
hash_const_iterator() : base_() {}
|
|
||||||
explicit hash_const_iterator(base const& x) : base_(x) {}
|
|
||||||
hash_const_iterator(iterator const& x) : base_(x.base_) {}
|
|
||||||
BOOST_DEDUCED_TYPENAME A::const_reference operator*() const {
|
|
||||||
return *base_;
|
|
||||||
}
|
|
||||||
value_type const* operator->() const {
|
|
||||||
return &*base_;
|
|
||||||
}
|
|
||||||
hash_const_iterator& operator++() {
|
|
||||||
base_.increment(); return *this;
|
|
||||||
}
|
|
||||||
hash_const_iterator operator++(int) {
|
|
||||||
hash_const_iterator tmp(base_); base_.increment(); return tmp;
|
|
||||||
}
|
|
||||||
bool operator==(iterator const& x) const {
|
|
||||||
return base_ == x.base_;
|
|
||||||
}
|
|
||||||
bool operator==(hash_const_iterator const& x) const {
|
|
||||||
return base_ == x.base_;
|
|
||||||
}
|
|
||||||
bool operator!=(iterator const& x) const {
|
|
||||||
return base_ != x.base_;
|
|
||||||
}
|
|
||||||
bool operator!=(hash_const_iterator const& x) const {
|
|
||||||
return base_ != x.base_;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
//
|
|
||||||
// types
|
|
||||||
//
|
|
||||||
// This is used to convieniently pass around a container's typedefs
|
|
||||||
// without having 7 template parameters.
|
|
||||||
|
|
||||||
template <class K, class V, class H, class P, class A, class E, class G>
|
|
||||||
struct types
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
typedef K key_type;
|
|
||||||
typedef V value_type;
|
|
||||||
typedef H hasher;
|
|
||||||
typedef P key_equal;
|
|
||||||
typedef A value_allocator;
|
|
||||||
typedef E extractor;
|
|
||||||
typedef G group_type;
|
|
||||||
|
|
||||||
typedef hash_node_constructor<value_allocator, group_type>
|
|
||||||
node_constructor;
|
|
||||||
typedef hash_buckets<value_allocator, group_type> buckets;
|
|
||||||
typedef hash_buffered_functions<hasher, key_equal> buffered_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::iterator_base iterator_base;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node_allocator node_allocator;
|
|
||||||
|
|
||||||
typedef std::pair<iterator_base, iterator_base> iterator_pair;
|
|
||||||
};
|
|
||||||
}}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,243 +0,0 @@
|
|||||||
/*
|
|
||||||
Copyright 2005-2007 Adobe Systems Incorporated
|
|
||||||
|
|
||||||
Use, modification and distribution are subject to 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).
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
|
||||||
#define BOOST_UNORDERED_DETAIL_MOVE_HEADER
|
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <boost/mpl/bool.hpp>
|
|
||||||
#include <boost/mpl/and.hpp>
|
|
||||||
#include <boost/mpl/or.hpp>
|
|
||||||
#include <boost/mpl/not.hpp>
|
|
||||||
#include <boost/type_traits/is_convertible.hpp>
|
|
||||||
#include <boost/type_traits/is_same.hpp>
|
|
||||||
#include <boost/type_traits/is_class.hpp>
|
|
||||||
#include <boost/utility/enable_if.hpp>
|
|
||||||
#include <boost/detail/workaround.hpp>
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#if defined(BOOST_NO_SFINAE)
|
|
||||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
||||||
#elif defined(__GNUC__) && \
|
|
||||||
(__GNUC__ < 3 || __GNUC__ == 3 && __GNUC_MINOR__ <= 3)
|
|
||||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
||||||
#elif BOOST_WORKAROUND(BOOST_INTEL, < 900) || \
|
|
||||||
BOOST_WORKAROUND(__EDG_VERSION__, < 304) || \
|
|
||||||
BOOST_WORKAROUND(__BORLANDC__, BOOST_TESTED_AT(0x0593))
|
|
||||||
# define BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
namespace boost {
|
|
||||||
namespace unordered_detail {
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
namespace move_detail {
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct class_has_move_assign {
|
|
||||||
class type {
|
|
||||||
typedef T& (T::*E)(T t);
|
|
||||||
typedef char (&no_type)[1];
|
|
||||||
typedef char (&yes_type)[2];
|
|
||||||
template <E e> struct sfinae { typedef yes_type type; };
|
|
||||||
template <class U>
|
|
||||||
static typename sfinae<&U::operator=>::type test(int);
|
|
||||||
template <class U>
|
|
||||||
static no_type test(...);
|
|
||||||
public:
|
|
||||||
enum {value = sizeof(test<T>(1)) == sizeof(yes_type)};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
template<typename T>
|
|
||||||
struct has_move_assign : boost::mpl::and_<boost::is_class<T>, class_has_move_assign<T> > {};
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
class test_can_convert_anything { };
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#endif // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*
|
|
||||||
REVISIT (sparent@adobe.com): This is a work around for Boost 1.34.1 and VC++ 2008 where
|
|
||||||
boost::is_convertible<T, T> fails to compile.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T, typename U>
|
|
||||||
struct is_convertible : boost::mpl::or_<
|
|
||||||
boost::is_same<T, U>,
|
|
||||||
boost::is_convertible<T, U>
|
|
||||||
> { };
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
} //namespace move_detail
|
|
||||||
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\ingroup move_related
|
|
||||||
\brief move_from is used for move_ctors.
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct move_from
|
|
||||||
{
|
|
||||||
explicit move_from(T& x) : source(x) { }
|
|
||||||
T& source;
|
|
||||||
private:
|
|
||||||
move_from& operator=(move_from const&);
|
|
||||||
};
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#if !defined(BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN)
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\ingroup move_related
|
|
||||||
\brief The is_movable trait can be used to identify movable types.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
struct is_movable : boost::mpl::and_<
|
|
||||||
boost::is_convertible<move_from<T>, T>,
|
|
||||||
move_detail::has_move_assign<T>,
|
|
||||||
boost::mpl::not_<boost::is_convertible<move_detail::test_can_convert_anything, T> >
|
|
||||||
> { };
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#else // BOOST_UNORDERED_NO_HAS_MOVE_ASSIGN
|
|
||||||
|
|
||||||
// On compilers which don't have adequate SFINAE support, treat most types as unmovable,
|
|
||||||
// unless the trait is specialized.
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
struct is_movable : boost::mpl::false_ { };
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#if !defined(BOOST_NO_SFINAE)
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\ingroup move_related
|
|
||||||
\brief copy_sink and move_sink are used to select between overloaded operations according to
|
|
||||||
whether type T is movable and convertible to type U.
|
|
||||||
\sa move
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T,
|
|
||||||
typename U = T,
|
|
||||||
typename R = void*>
|
|
||||||
struct copy_sink : boost::enable_if<
|
|
||||||
boost::mpl::and_<
|
|
||||||
boost::unordered_detail::move_detail::is_convertible<T, U>,
|
|
||||||
boost::mpl::not_<is_movable<T> >
|
|
||||||
>,
|
|
||||||
R
|
|
||||||
>
|
|
||||||
{ };
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\ingroup move_related
|
|
||||||
\brief move_sink and copy_sink are used to select between overloaded operations according to
|
|
||||||
whether type T is movable and convertible to type U.
|
|
||||||
\sa move
|
|
||||||
*/
|
|
||||||
|
|
||||||
template <typename T,
|
|
||||||
typename U = T,
|
|
||||||
typename R = void*>
|
|
||||||
struct move_sink : boost::enable_if<
|
|
||||||
boost::mpl::and_<
|
|
||||||
boost::unordered_detail::move_detail::is_convertible<T, U>,
|
|
||||||
is_movable<T>
|
|
||||||
>,
|
|
||||||
R
|
|
||||||
>
|
|
||||||
{ };
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\ingroup move_related
|
|
||||||
\brief This version of move is selected when T is_movable . It in turn calls the move
|
|
||||||
constructor. This call, with the help of the return value optimization, will cause x to be moved
|
|
||||||
instead of copied to its destination. See adobe/test/move/main.cpp for examples.
|
|
||||||
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
T move(T& x, typename move_sink<T>::type = 0) { return T(move_from<T>(x)); }
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
/*!
|
|
||||||
\ingroup move_related
|
|
||||||
\brief This version of move is selected when T is not movable . The net result will be that
|
|
||||||
x gets copied.
|
|
||||||
*/
|
|
||||||
template <typename T>
|
|
||||||
T& move(T& x, typename copy_sink<T>::type = 0) { return x; }
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#else // BOOST_NO_SFINAE
|
|
||||||
|
|
||||||
// On compilers without SFINAE, define copy_sink to always use the copy function.
|
|
||||||
|
|
||||||
template <typename T,
|
|
||||||
typename U = T,
|
|
||||||
typename R = void*>
|
|
||||||
struct copy_sink
|
|
||||||
{
|
|
||||||
typedef R type;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Always copy the element unless this is overloaded.
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
T& move(T& x) {
|
|
||||||
return x;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // BOOST_NO_SFINAE
|
|
||||||
|
|
||||||
} // namespace unordered_detail
|
|
||||||
} // namespace boost
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*************************************************************************************************/
|
|
@ -1,6 +1,6 @@
|
|||||||
|
|
||||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||||
// Copyright (C) 2005-2009 Daniel James
|
// Copyright (C) 2005-2011 Daniel James
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -11,10 +11,7 @@
|
|||||||
#ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_NODE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/unordered/detail/util.hpp>
|
||||||
#include <boost/assert.hpp>
|
|
||||||
#include <boost/detail/workaround.hpp>
|
|
||||||
#include <boost/unordered/detail/fwd.hpp>
|
|
||||||
|
|
||||||
#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
|
#if BOOST_WORKAROUND(__BORLANDC__, <= 0X0582)
|
||||||
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
|
#define BOOST_UNORDERED_BORLAND_BOOL(x) (bool)(x)
|
||||||
@ -22,205 +19,348 @@
|
|||||||
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
|
#define BOOST_UNORDERED_BORLAND_BOOL(x) x
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
|
||||||
|
// Some forward declarations for buckets and tables
|
||||||
|
|
||||||
|
template <typename T> class table;
|
||||||
|
template <class A, bool Unique> class buckets;
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// ungrouped node implementation
|
//
|
||||||
|
// This section implements buckets and nodes. Here's a rough
|
||||||
|
// inheritance diagram, to show how they pull together.
|
||||||
|
//
|
||||||
|
// For unordered_set/unordered_map:
|
||||||
|
//
|
||||||
|
// bucket<A> value_base<allocator_traits<A>::value_type>
|
||||||
|
// | |
|
||||||
|
// +--------------+-------------+
|
||||||
|
// |
|
||||||
|
// ungrouped_node<A>
|
||||||
|
//
|
||||||
|
// For unordered_multiset/unordered_multimap:
|
||||||
|
//
|
||||||
|
// bucket<A> value_base<allocator_traits<A>::value_type>
|
||||||
|
// | |
|
||||||
|
// +--------------+-------------+
|
||||||
|
// |
|
||||||
|
// grouped_node<A>
|
||||||
|
|
||||||
|
// bucket
|
||||||
|
//
|
||||||
|
// bucket is used for both the buckets and as a base class for
|
||||||
|
// nodes. By using 'bucket_ptr' for 'node_ptr', 'next_' can point
|
||||||
|
// to either a bucket or a node. This is used later to implement a
|
||||||
|
// sentinel at the end of the bucket array.
|
||||||
|
|
||||||
template <class A>
|
template <class A>
|
||||||
inline BOOST_DEDUCED_TYPENAME ungrouped_node_base<A>::node_ptr&
|
class bucket
|
||||||
ungrouped_node_base<A>::next_group(node_ptr ptr)
|
|
||||||
{
|
{
|
||||||
return ptr->next_;
|
bucket& operator=(bucket const&);
|
||||||
}
|
public:
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME
|
||||||
template <class A>
|
::boost::unordered::detail::rebind_wrap<A, bucket>::type
|
||||||
inline std::size_t ungrouped_node_base<A>::group_count(node_ptr)
|
bucket_allocator;
|
||||||
{
|
typedef BOOST_DEDUCED_TYPENAME
|
||||||
return 1;
|
allocator_traits<bucket_allocator>::pointer bucket_ptr;
|
||||||
}
|
typedef bucket_ptr node_ptr;
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline void ungrouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
|
|
||||||
{
|
|
||||||
n->next_ = b.next_;
|
|
||||||
b.next_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline void ungrouped_node_base<A>::add_after_node(node_ptr n,
|
|
||||||
node_ptr position)
|
|
||||||
{
|
|
||||||
n->next_ = position->next_;
|
|
||||||
position->next_ = position;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
node_ptr next_;
|
||||||
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b,
|
|
||||||
node_ptr begin, node_ptr end)
|
bucket() : next_() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// The space used to store values in a node.
|
||||||
|
|
||||||
|
template <class ValueType>
|
||||||
|
struct value_base
|
||||||
{
|
{
|
||||||
node_ptr* pos = &b.next_;
|
typedef ValueType value_type;
|
||||||
while(*pos != begin) pos = &(*pos)->next_;
|
BOOST_DEDUCED_TYPENAME ::boost::aligned_storage<
|
||||||
*pos = end;
|
sizeof(value_type),
|
||||||
}
|
::boost::alignment_of<value_type>::value>::type data_;
|
||||||
|
|
||||||
template <class A>
|
void* address() {
|
||||||
inline void ungrouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
|
return this;
|
||||||
{
|
|
||||||
b.next_ = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline void ungrouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
|
|
||||||
{
|
|
||||||
unlink_nodes(b, n, n->next_);
|
|
||||||
}
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// grouped node implementation
|
|
||||||
|
|
||||||
// If ptr is the first element in a group, return pointer to next group.
|
|
||||||
// Otherwise returns a pointer to ptr.
|
|
||||||
template <class A>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr&
|
|
||||||
grouped_node_base<A>::next_group(node_ptr ptr)
|
|
||||||
{
|
|
||||||
return get(ptr).group_prev_->next_;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
|
|
||||||
grouped_node_base<A>::first_in_group(node_ptr ptr)
|
|
||||||
{
|
|
||||||
while(next_group(ptr) == ptr)
|
|
||||||
ptr = get(ptr).group_prev_;
|
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline std::size_t grouped_node_base<A>::group_count(node_ptr ptr)
|
|
||||||
{
|
|
||||||
node_ptr start = ptr;
|
|
||||||
std::size_t size = 0;
|
|
||||||
do {
|
|
||||||
++size;
|
|
||||||
ptr = get(ptr).group_prev_;
|
|
||||||
} while(ptr != start);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline void grouped_node_base<A>::add_to_bucket(node_ptr n, bucket& b)
|
|
||||||
{
|
|
||||||
n->next_ = b.next_;
|
|
||||||
get(n).group_prev_ = n;
|
|
||||||
b.next_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
inline void grouped_node_base<A>::add_after_node(node_ptr n, node_ptr pos)
|
|
||||||
{
|
|
||||||
n->next_ = next_group(pos);
|
|
||||||
get(n).group_prev_ = get(pos).group_prev_;
|
|
||||||
next_group(pos) = n;
|
|
||||||
get(pos).group_prev_ = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Break a ciruclar list into two, with split as the beginning
|
|
||||||
// of the second group (if split is at the beginning then don't
|
|
||||||
// split).
|
|
||||||
template <class A>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME grouped_node_base<A>::node_ptr
|
|
||||||
grouped_node_base<A>::split_group(node_ptr split)
|
|
||||||
{
|
|
||||||
node_ptr first = first_in_group(split);
|
|
||||||
if(first == split) return split;
|
|
||||||
|
|
||||||
node_ptr last = get(first).group_prev_;
|
|
||||||
get(first).group_prev_ = get(split).group_prev_;
|
|
||||||
get(split).group_prev_ = last;
|
|
||||||
|
|
||||||
return first;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
|
||||||
void grouped_node_base<A>::unlink_node(bucket& b, node_ptr n)
|
|
||||||
{
|
|
||||||
node_ptr next = n->next_;
|
|
||||||
node_ptr* pos = &next_group(n);
|
|
||||||
|
|
||||||
if(*pos != n) {
|
|
||||||
// The node is at the beginning of a group.
|
|
||||||
|
|
||||||
// Find the previous node pointer:
|
|
||||||
pos = &b.next_;
|
|
||||||
while(*pos != n) pos = &next_group(*pos);
|
|
||||||
|
|
||||||
// Remove from group
|
|
||||||
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
|
||||||
get(next).group_prev_ == n)
|
|
||||||
{
|
|
||||||
get(next).group_prev_ = get(n).group_prev_;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
value_type& value() {
|
||||||
get(next).group_prev_ == n)
|
return *(ValueType*) this;
|
||||||
|
}
|
||||||
|
value_type* value_ptr() {
|
||||||
|
return (ValueType*) this;
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
value_base& operator=(value_base const&);
|
||||||
|
};
|
||||||
|
|
||||||
|
// In containers with equivalent keys (unordered_multimap and
|
||||||
|
// unordered_multiset) equivalent nodes are grouped together, in
|
||||||
|
// containers with unique keys (unordered_map and unordered_set)
|
||||||
|
// individual nodes are treated as groups of one. The following two
|
||||||
|
// classes implement the data structure.
|
||||||
|
|
||||||
|
// This is used for containers with unique keys. There are no groups
|
||||||
|
// so it doesn't add any extra members, and just treats individual
|
||||||
|
// nodes as groups of one.
|
||||||
|
|
||||||
|
template <class A>
|
||||||
|
struct ungrouped_node
|
||||||
|
: ::boost::unordered::detail::bucket<A>,
|
||||||
|
value_base<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>
|
||||||
|
{
|
||||||
|
typedef ::boost::unordered::detail::bucket<A> 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<A>::value_type value_type;
|
||||||
|
|
||||||
|
std::size_t hash_;
|
||||||
|
|
||||||
|
ungrouped_node() : bucket() {}
|
||||||
|
|
||||||
|
void init(node_ptr) {}
|
||||||
|
|
||||||
|
static node_ptr next_group(node_ptr ptr)
|
||||||
{
|
{
|
||||||
// The deleted node is not at the end of the group, so
|
return ptr->next_;
|
||||||
// change the link from the next node.
|
|
||||||
get(next).group_prev_ = get(n).group_prev_;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
// The deleted node is at the end of the group, so the
|
static node_ptr next_group2(node_ptr ptr)
|
||||||
// first node in the group is pointing to it.
|
{
|
||||||
// Find that to change its pointer.
|
return ptr->next_;
|
||||||
node_ptr x = get(n).group_prev_;
|
|
||||||
while(get(x).group_prev_ != n) {
|
|
||||||
x = get(x).group_prev_;
|
|
||||||
}
|
|
||||||
get(x).group_prev_ = get(n).group_prev_;
|
|
||||||
}
|
}
|
||||||
*pos = next;
|
|
||||||
}
|
static std::size_t group_count(node_ptr n)
|
||||||
|
{
|
||||||
|
return !n ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_after_node(node_ptr n, node_ptr position)
|
||||||
|
{
|
||||||
|
n->next_ = position->next_;
|
||||||
|
position->next_ = position;
|
||||||
|
}
|
||||||
|
|
||||||
|
static node_ptr unlink_node(bucket& b, node_ptr n)
|
||||||
|
{
|
||||||
|
return unlink_nodes(b, n, n->next_);
|
||||||
|
}
|
||||||
|
|
||||||
|
static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
|
||||||
|
{
|
||||||
|
node_ptr prev = b.next_;
|
||||||
|
while(prev->next_ != begin) prev = prev->next_;
|
||||||
|
prev->next_ = end;
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::size_t get_hash(node_ptr p)
|
||||||
|
{
|
||||||
|
return static_cast<ungrouped_node&>(*p).hash_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void set_hash(node_ptr p, std::size_t hash)
|
||||||
|
{
|
||||||
|
static_cast<ungrouped_node&>(*p).hash_ = hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type& get_value(node_ptr p)
|
||||||
|
{
|
||||||
|
return static_cast<ungrouped_node&>(*p).value();
|
||||||
|
}
|
||||||
|
|
||||||
|
static value_type* get_value_ptr(node_ptr p)
|
||||||
|
{
|
||||||
|
return static_cast<ungrouped_node&>(*p).value_ptr();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is used for containers with equivalent keys. It implements a
|
||||||
|
// circular list running in the opposite direction to the linked
|
||||||
|
// list through the nodes.
|
||||||
|
|
||||||
template <class A>
|
template <class A>
|
||||||
void grouped_node_base<A>::unlink_nodes(bucket& b,
|
struct grouped_node
|
||||||
node_ptr begin, node_ptr end)
|
: ::boost::unordered::detail::bucket<A>,
|
||||||
|
value_base<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>
|
||||||
{
|
{
|
||||||
node_ptr* pos = &next_group(begin);
|
typedef ::boost::unordered::detail::bucket<A> 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<A>::value_type value_type;
|
||||||
|
|
||||||
if(*pos != begin) {
|
std::size_t hash_;
|
||||||
// The node is at the beginning of a group.
|
node_ptr group_prev_;
|
||||||
|
|
||||||
// Find the previous node pointer:
|
grouped_node() : bucket(), group_prev_() {}
|
||||||
pos = &b.next_;
|
void init(node_ptr n)
|
||||||
while(*pos != begin) pos = &next_group(*pos);
|
{
|
||||||
|
group_prev_ = n;
|
||||||
// Remove from group
|
|
||||||
if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
node_ptr group1 = split_group(begin);
|
|
||||||
if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
|
|
||||||
node_ptr group2 = split_group(end);
|
|
||||||
|
|
||||||
if(begin == group2) {
|
static node_ptr next_group(node_ptr ptr)
|
||||||
node_ptr end1 = get(group1).group_prev_;
|
{
|
||||||
node_ptr end2 = get(group2).group_prev_;
|
return get(ptr).group_prev_->next_;
|
||||||
get(group1).group_prev_ = end2;
|
}
|
||||||
get(group2).group_prev_ = end1;
|
|
||||||
|
static node_ptr next_group2(node_ptr ptr)
|
||||||
|
{
|
||||||
|
return get(ptr->next_).group_prev_;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::size_t group_count(node_ptr ptr)
|
||||||
|
{
|
||||||
|
if (!ptr) return 0;
|
||||||
|
|
||||||
|
node_ptr start = ptr;
|
||||||
|
std::size_t size = 0;
|
||||||
|
do {
|
||||||
|
++size;
|
||||||
|
ptr = get(ptr).group_prev_;
|
||||||
|
} while(ptr != start);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void add_after_node(node_ptr n, node_ptr pos)
|
||||||
|
{
|
||||||
|
n->next_ = get(pos).group_prev_->next_;
|
||||||
|
get(n).group_prev_ = get(pos).group_prev_;
|
||||||
|
get(pos).group_prev_->next_ = n;
|
||||||
|
get(pos).group_prev_ = n;
|
||||||
|
}
|
||||||
|
|
||||||
|
static node_ptr unlink_node(bucket& b, node_ptr n)
|
||||||
|
{
|
||||||
|
node_ptr next = n->next_;
|
||||||
|
node_ptr prev = get(n).group_prev_;
|
||||||
|
|
||||||
|
if(prev->next_ != n) {
|
||||||
|
// The node is at the beginning of a group.
|
||||||
|
|
||||||
|
// Find the previous node pointer:
|
||||||
|
prev = b.next_;
|
||||||
|
while(prev->next_ != n) {
|
||||||
|
prev = next_group2(prev);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove from group
|
||||||
|
if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
||||||
|
get(next).group_prev_ == n)
|
||||||
|
{
|
||||||
|
get(next).group_prev_ = get(n).group_prev_;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
else if(BOOST_UNORDERED_BORLAND_BOOL(next) &&
|
||||||
|
get(next).group_prev_ == n)
|
||||||
|
{
|
||||||
|
// The deleted node is not at the end of the group, so
|
||||||
|
// change the link from the next node.
|
||||||
|
get(next).group_prev_ = get(n).group_prev_;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// The deleted node is at the end of the group, so the
|
||||||
|
// first node in the group is pointing to it.
|
||||||
|
// Find that to change its pointer.
|
||||||
|
node_ptr x = get(n).group_prev_;
|
||||||
|
while(get(x).group_prev_ != n) {
|
||||||
|
x = get(x).group_prev_;
|
||||||
|
}
|
||||||
|
get(x).group_prev_ = get(n).group_prev_;
|
||||||
|
}
|
||||||
|
prev->next_ = next;
|
||||||
|
|
||||||
|
return prev;
|
||||||
}
|
}
|
||||||
*pos = end;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class A>
|
static node_ptr unlink_nodes(bucket& b, node_ptr begin, node_ptr end)
|
||||||
void grouped_node_base<A>::unlink_nodes(bucket& b, node_ptr end)
|
{
|
||||||
|
node_ptr prev = get(begin).group_prev_;
|
||||||
|
|
||||||
|
if(prev->next_ != begin) {
|
||||||
|
// The node is at the beginning of a group.
|
||||||
|
|
||||||
|
// Find the previous node pointer:
|
||||||
|
prev = b.next_;
|
||||||
|
while(prev->next_ != begin) prev = next_group2(prev);
|
||||||
|
|
||||||
|
if(BOOST_UNORDERED_BORLAND_BOOL(end)) split_group(end);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
node_ptr group1 = split_group(begin);
|
||||||
|
if(BOOST_UNORDERED_BORLAND_BOOL(end)) {
|
||||||
|
node_ptr group2 = split_group(end);
|
||||||
|
|
||||||
|
if(begin == group2) {
|
||||||
|
node_ptr end1 = get(group1).group_prev_;
|
||||||
|
node_ptr end2 = get(group2).group_prev_;
|
||||||
|
get(group1).group_prev_ = end2;
|
||||||
|
get(group2).group_prev_ = end1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
prev->next_ = end;
|
||||||
|
|
||||||
|
return prev;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Break a ciruclar list into two, with split as the beginning
|
||||||
|
// of the second group (if split is at the beginning then don't
|
||||||
|
// split).
|
||||||
|
static node_ptr split_group(node_ptr split)
|
||||||
|
{
|
||||||
|
// Find first node in group.
|
||||||
|
node_ptr first = split;
|
||||||
|
while(next_group(first) == first)
|
||||||
|
first = get(first).group_prev_;
|
||||||
|
|
||||||
|
if(first == split) return split;
|
||||||
|
|
||||||
|
node_ptr last = get(first).group_prev_;
|
||||||
|
get(first).group_prev_ = get(split).group_prev_;
|
||||||
|
get(split).group_prev_ = last;
|
||||||
|
|
||||||
|
return first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::size_t get_hash(node_ptr p) {
|
||||||
|
return static_cast<grouped_node&>(*p).hash_;
|
||||||
|
}
|
||||||
|
static void set_hash(node_ptr p, std::size_t hash) {
|
||||||
|
static_cast<grouped_node&>(*p).hash_ = hash;
|
||||||
|
}
|
||||||
|
static value_type& get_value(node_ptr p) {
|
||||||
|
return static_cast<grouped_node&>(*p).value();
|
||||||
|
}
|
||||||
|
static value_type* get_value_ptr(node_ptr p) {
|
||||||
|
return static_cast<grouped_node&>(*p).value_ptr();
|
||||||
|
}
|
||||||
|
|
||||||
|
static grouped_node& get(node_ptr ptr) {
|
||||||
|
return static_cast<grouped_node&>(*ptr);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// These two classes implement an easy way to pass around the node
|
||||||
|
// group policy classes without the messy template parameters.
|
||||||
|
// Whenever you see the template parameter 'G' it's one of these.
|
||||||
|
|
||||||
|
struct ungrouped
|
||||||
{
|
{
|
||||||
split_group(end);
|
template <class A>
|
||||||
b.next_ = end;
|
struct node {
|
||||||
}
|
typedef ungrouped_node<A> type;
|
||||||
}}
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct grouped
|
||||||
|
{
|
||||||
|
template <class A>
|
||||||
|
struct node {
|
||||||
|
typedef grouped_node<A> type;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,19 +1,18 @@
|
|||||||
|
|
||||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||||
// Copyright (C) 2005-2010 Daniel James
|
// Copyright (C) 2005-2011 Daniel James
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_UNIQUE_HPP_INCLUDED
|
||||||
|
|
||||||
#include <boost/unordered/detail/table.hpp>
|
|
||||||
#include <boost/unordered/detail/extract_key.hpp>
|
#include <boost/unordered/detail/extract_key.hpp>
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class hash_unique_table : public T::table
|
class unique_table : public T::table_base
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||||
@ -21,493 +20,398 @@ namespace boost { namespace unordered_detail {
|
|||||||
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
typedef BOOST_DEDUCED_TYPENAME T::value_allocator value_allocator;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
typedef BOOST_DEDUCED_TYPENAME T::key_type key_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::table table;
|
typedef BOOST_DEDUCED_TYPENAME T::table_base table_base;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
typedef BOOST_DEDUCED_TYPENAME T::node_constructor node_constructor;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME T::node_allocator node_allocator;
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
typedef BOOST_DEDUCED_TYPENAME T::node node;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
typedef BOOST_DEDUCED_TYPENAME T::node_ptr node_ptr;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
typedef BOOST_DEDUCED_TYPENAME T::bucket_ptr bucket_ptr;
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::iterator_base iterator_base;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
typedef BOOST_DEDUCED_TYPENAME T::extractor extractor;
|
||||||
|
|
||||||
typedef std::pair<iterator_base, bool> emplace_return;
|
typedef std::pair<node_ptr, bool> emplace_return;
|
||||||
|
|
||||||
// Constructors
|
// Constructors
|
||||||
|
|
||||||
hash_unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
|
unique_table(std::size_t n, hasher const& hf, key_equal const& eq,
|
||||||
value_allocator const& a)
|
value_allocator const& a)
|
||||||
: table(n, hf, eq, a) {}
|
: table_base(n, hf, eq, a) {}
|
||||||
hash_unique_table(hash_unique_table const& x)
|
unique_table(unique_table const& x)
|
||||||
: table(x, x.node_alloc()) {}
|
: table_base(x,
|
||||||
hash_unique_table(hash_unique_table const& x, value_allocator const& a)
|
allocator_traits<node_allocator>::
|
||||||
: table(x, a) {}
|
select_on_container_copy_construction(x.node_alloc())) {}
|
||||||
hash_unique_table(hash_unique_table& x, move_tag m)
|
unique_table(unique_table const& x, value_allocator const& a)
|
||||||
: table(x, m) {}
|
: table_base(x, a) {}
|
||||||
hash_unique_table(hash_unique_table& x, value_allocator const& a,
|
unique_table(unique_table& x, move_tag m)
|
||||||
|
: table_base(x, m) {}
|
||||||
|
unique_table(unique_table& x, value_allocator const& a,
|
||||||
move_tag m)
|
move_tag m)
|
||||||
: table(x, a, m) {}
|
: table_base(x, a, m) {}
|
||||||
~hash_unique_table() {}
|
~unique_table() {}
|
||||||
|
|
||||||
// Insert methods
|
|
||||||
|
|
||||||
emplace_return emplace_impl_with_node(node_constructor& a);
|
|
||||||
value_type& operator[](key_type const& k);
|
|
||||||
|
|
||||||
// equals
|
// equals
|
||||||
|
|
||||||
bool equals(hash_unique_table const&) const;
|
bool equals(unique_table const& other) const
|
||||||
|
|
||||||
node_ptr add_node(node_constructor& a, bucket_ptr bucket);
|
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
|
||||||
|
|
||||||
template<class... Args>
|
|
||||||
emplace_return emplace(Args&&... args);
|
|
||||||
template<class... Args>
|
|
||||||
emplace_return emplace_impl(key_type const& k, Args&&... args);
|
|
||||||
template<class... Args>
|
|
||||||
emplace_return emplace_impl(no_key, Args&&... args);
|
|
||||||
template<class... Args>
|
|
||||||
emplace_return emplace_empty_impl(Args&&... args);
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_INSERT_IMPL(z, n, _) \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
|
||||||
emplace_return emplace( \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
|
||||||
emplace_return emplace_impl(key_type const& k, \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
|
||||||
emplace_return emplace_impl(no_key, \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)); \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
|
||||||
emplace_return emplace_empty_impl( \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, n));
|
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
||||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
|
||||||
|
|
||||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// if hash function throws, or inserting > 1 element, basic exception
|
|
||||||
// safety strong otherwise
|
|
||||||
template <class InputIt>
|
|
||||||
void insert_range(InputIt i, InputIt j);
|
|
||||||
template <class InputIt>
|
|
||||||
void insert_range_impl(key_type const&, InputIt i, InputIt j);
|
|
||||||
template <class InputIt>
|
|
||||||
void insert_range_impl2(node_constructor&, key_type const&, InputIt i, InputIt j);
|
|
||||||
template <class InputIt>
|
|
||||||
void insert_range_impl(no_key, InputIt i, InputIt j);
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class H, class P, class A>
|
|
||||||
struct set : public types<
|
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
H, P, A,
|
|
||||||
set_extractor<BOOST_DEDUCED_TYPENAME A::value_type>,
|
|
||||||
ungrouped>
|
|
||||||
{
|
|
||||||
typedef hash_unique_table<set<H, P, A> > impl;
|
|
||||||
typedef hash_table<set<H, P, A> > table;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <class K, class H, class P, class A>
|
|
||||||
struct map : public types<
|
|
||||||
K, BOOST_DEDUCED_TYPENAME A::value_type,
|
|
||||||
H, P, A,
|
|
||||||
map_extractor<K, BOOST_DEDUCED_TYPENAME A::value_type>,
|
|
||||||
ungrouped>
|
|
||||||
{
|
|
||||||
typedef hash_unique_table<map<K, H, P, A> > impl;
|
|
||||||
typedef hash_table<map<K, H, P, A> > table;
|
|
||||||
};
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
|
||||||
// Equality
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
bool hash_unique_table<T>
|
|
||||||
::equals(hash_unique_table<T> const& other) const
|
|
||||||
{
|
|
||||||
if(this->size_ != other.size_) return false;
|
|
||||||
if(!this->size_) return true;
|
|
||||||
|
|
||||||
bucket_ptr end = this->get_bucket(this->bucket_count_);
|
|
||||||
for(bucket_ptr i = this->cached_begin_bucket_; i != end; ++i)
|
|
||||||
{
|
{
|
||||||
node_ptr it1 = i->next_;
|
if(this->size_ != other.size_) return false;
|
||||||
while(BOOST_UNORDERED_BORLAND_BOOL(it1))
|
if(!this->size_) return true;
|
||||||
|
|
||||||
|
for(node_ptr n1 = this->get_bucket(this->bucket_count_)->next_;
|
||||||
|
n1; n1 = n1->next_)
|
||||||
{
|
{
|
||||||
node_ptr it2 = other.find_iterator(this->get_key_from_ptr(it1));
|
node_ptr n2 = other.find_matching_node(n1);
|
||||||
if(!BOOST_UNORDERED_BORLAND_BOOL(it2)) return false;
|
if(!n2 || node::get_value(n1) != node::get_value(n2))
|
||||||
if(!extractor::compare_mapped(
|
|
||||||
node::get_value(it1), node::get_value(it2)))
|
|
||||||
return false;
|
return false;
|
||||||
it1 = it1->next_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
////////////////////////////////////////////////////////////////////////
|
||||||
}
|
// A convenience method for adding nodes.
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
node_ptr add_node(
|
||||||
// A convenience method for adding nodes.
|
node_constructor& a,
|
||||||
|
std::size_t bucket_index,
|
||||||
template <class T>
|
std::size_t hash)
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::node_ptr
|
{
|
||||||
hash_unique_table<T>::add_node(node_constructor& a,
|
bucket_ptr b = this->get_bucket(bucket_index);
|
||||||
bucket_ptr bucket)
|
node_ptr n = a.release();
|
||||||
{
|
node::set_hash(n, hash);
|
||||||
node_ptr n = a.release();
|
|
||||||
node::add_to_bucket(n, *bucket);
|
if (!b->next_)
|
||||||
++this->size_;
|
{
|
||||||
if(bucket < this->cached_begin_bucket_)
|
bucket_ptr start_node = this->get_bucket(this->bucket_count_);
|
||||||
this->cached_begin_bucket_ = bucket;
|
|
||||||
return n;
|
if (start_node->next_) {
|
||||||
}
|
this->buckets_[
|
||||||
|
node::get_hash(start_node->next_) % this->bucket_count_
|
||||||
////////////////////////////////////////////////////////////////////////////
|
].next_ = n;
|
||||||
// Insert methods
|
}
|
||||||
|
|
||||||
// if hash function throws, basic exception safety
|
b->next_ = start_node;
|
||||||
// strong otherwise
|
n->next_ = start_node->next_;
|
||||||
template <class T>
|
start_node->next_ = n;
|
||||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::value_type&
|
}
|
||||||
hash_unique_table<T>::operator[](key_type const& k)
|
else
|
||||||
{
|
{
|
||||||
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
|
n->next_ = b->next_->next_;
|
||||||
|
b->next_->next_ = n;
|
||||||
std::size_t hash_value = this->hash_function()(k);
|
}
|
||||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
|
||||||
|
++this->size_;
|
||||||
if(!this->buckets_) {
|
return n;
|
||||||
node_constructor a(*this);
|
|
||||||
a.construct_pair(k, (mapped_type*) 0);
|
|
||||||
return *this->emplace_empty_impl_with_node(a, 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
node_ptr pos = this->find_iterator(bucket, k);
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Insert methods
|
||||||
|
|
||||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
// if hash function throws, basic exception safety
|
||||||
return node::get_value(pos);
|
// strong otherwise
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Side effects only in this block.
|
|
||||||
|
|
||||||
|
value_type& operator[](key_type const& k)
|
||||||
|
{
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME value_type::second_type mapped_type;
|
||||||
|
|
||||||
|
std::size_t hash = this->hash_function()(k);
|
||||||
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
|
node_ptr pos = this->find_node(bucket_index, hash, k);
|
||||||
|
|
||||||
|
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||||
|
return node::get_value(pos);
|
||||||
|
}
|
||||||
|
|
||||||
// Create the node before rehashing in case it throws an
|
// Create the node before rehashing in case it throws an
|
||||||
// exception (need strong safety in such a case).
|
// exception (need strong safety in such a case).
|
||||||
node_constructor a(*this);
|
node_constructor a(*this);
|
||||||
a.construct_pair(k, (mapped_type*) 0);
|
a.construct_pair(k, (mapped_type*) 0);
|
||||||
|
|
||||||
// reserve has basic exception safety if the hash function
|
// reserve has basic exception safety if the hash function
|
||||||
// throws, strong otherwise.
|
// throws, strong otherwise.
|
||||||
if(this->reserve_for_insert(this->size_ + 1))
|
if(this->reserve_for_insert(this->size_ + 1))
|
||||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
bucket_index = hash % this->bucket_count_;
|
||||||
|
|
||||||
// Nothing after this point can throw.
|
// Nothing after this point can throw.
|
||||||
|
|
||||||
return node::get_value(add_node(a, bucket));
|
return node::get_value(add_node(a, bucket_index, hash));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
emplace_return emplace_impl_with_node(node_constructor& a)
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
{
|
||||||
hash_unique_table<T>::emplace_impl_with_node(node_constructor& a)
|
// No side effects in this initial code
|
||||||
{
|
key_type const& k = this->get_key(a.value());
|
||||||
// No side effects in this initial code
|
std::size_t hash = this->hash_function()(k);
|
||||||
key_type const& k = this->get_key(a.value());
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
std::size_t hash_value = this->hash_function()(k);
|
node_ptr pos = this->find_node(bucket_index, hash, k);
|
||||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
|
||||||
node_ptr pos = this->find_iterator(bucket, k);
|
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||||
|
// Found an existing key, return it (no throw).
|
||||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
return emplace_return(pos, false);
|
||||||
// Found an existing key, return it (no throw).
|
}
|
||||||
return emplace_return(iterator_base(bucket, pos), false);
|
|
||||||
} else {
|
|
||||||
// reserve has basic exception safety if the hash function
|
// reserve has basic exception safety if the hash function
|
||||||
// throws, strong otherwise.
|
// throws, strong otherwise.
|
||||||
if(this->reserve_for_insert(this->size_ + 1))
|
if(this->reserve_for_insert(this->size_ + 1))
|
||||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
bucket_index = hash % this->bucket_count_;
|
||||||
|
|
||||||
// Nothing after this point can throw.
|
// Nothing after this point can throw.
|
||||||
|
|
||||||
return emplace_return(
|
return emplace_return(add_node(a, bucket_index, hash), true);
|
||||||
iterator_base(bucket, add_node(a, bucket)),
|
|
||||||
true);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
emplace_return insert(value_type const& v)
|
||||||
|
{
|
||||||
|
key_type const& k = extractor::extract(v);
|
||||||
|
std::size_t hash = this->hash_function()(k);
|
||||||
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
|
node_ptr pos = this->find_node(bucket_index, hash, k);
|
||||||
|
|
||||||
|
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||||
|
// Found an existing key, return it (no throw).
|
||||||
|
return emplace_return(pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Isn't in table, add to bucket.
|
||||||
|
|
||||||
|
// Create the node before rehashing in case it throws an
|
||||||
|
// exception (need strong safety in such a case).
|
||||||
|
node_constructor a(*this);
|
||||||
|
a.construct(v);
|
||||||
|
|
||||||
|
// reserve has basic exception safety if the hash function
|
||||||
|
// throws, strong otherwise.
|
||||||
|
if(this->reserve_for_insert(this->size_ + 1))
|
||||||
|
bucket_index = hash % this->bucket_count_;
|
||||||
|
|
||||||
|
// Nothing after this point can throw.
|
||||||
|
|
||||||
|
return emplace_return(add_node(a, bucket_index, hash), true);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
|
||||||
template<class... Args>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
|
||||||
hash_unique_table<T>::emplace_impl(key_type const& k,
|
|
||||||
Args&&... args)
|
|
||||||
{
|
|
||||||
// No side effects in this initial code
|
|
||||||
std::size_t hash_value = this->hash_function()(k);
|
|
||||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
|
||||||
node_ptr pos = this->find_iterator(bucket, k);
|
|
||||||
|
|
||||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
// Found an existing key, return it (no throw).
|
|
||||||
return emplace_return(iterator_base(bucket, pos), false);
|
|
||||||
|
|
||||||
} else {
|
template<class... Args>
|
||||||
|
emplace_return emplace(Args&&... args)
|
||||||
|
{
|
||||||
|
return emplace_impl(
|
||||||
|
extractor::extract(std::forward<Args>(args)...),
|
||||||
|
std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class... Args>
|
||||||
|
emplace_return emplace_impl(key_type const& k, Args&&... args)
|
||||||
|
{
|
||||||
|
// No side effects in this initial code
|
||||||
|
std::size_t hash = this->hash_function()(k);
|
||||||
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
|
node_ptr pos = this->find_node(bucket_index, hash, k);
|
||||||
|
|
||||||
|
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||||
|
// Found an existing key, return it (no throw).
|
||||||
|
return emplace_return(pos, false);
|
||||||
|
}
|
||||||
|
|
||||||
// Doesn't already exist, add to bucket.
|
// Doesn't already exist, add to bucket.
|
||||||
// Side effects only in this block.
|
// Side effects only in this block.
|
||||||
|
|
||||||
// Create the node before rehashing in case it throws an
|
// Create the node before rehashing in case it throws an
|
||||||
// exception (need strong safety in such a case).
|
// exception (need strong safety in such a case).
|
||||||
node_constructor a(*this);
|
node_constructor a(*this);
|
||||||
a.construct(std::forward<Args>(args)...);
|
a.construct(std::forward<Args>(args)...);
|
||||||
|
|
||||||
// reserve has basic exception safety if the hash function
|
// reserve has basic exception safety if the hash function
|
||||||
// throws, strong otherwise.
|
// throws, strong otherwise.
|
||||||
if(this->reserve_for_insert(this->size_ + 1))
|
if(this->reserve_for_insert(this->size_ + 1))
|
||||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
bucket_index = hash % this->bucket_count_;
|
||||||
|
|
||||||
// Nothing after this point can throw.
|
|
||||||
|
|
||||||
return emplace_return(
|
|
||||||
iterator_base(bucket, add_node(a, bucket)),
|
|
||||||
true);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
template<class... Args>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
|
||||||
hash_unique_table<T>::emplace_impl(no_key, Args&&... args)
|
|
||||||
{
|
|
||||||
// Construct the node regardless - in order to get the key.
|
|
||||||
// It will be discarded if it isn't used
|
|
||||||
node_constructor a(*this);
|
|
||||||
a.construct(std::forward<Args>(args)...);
|
|
||||||
return emplace_impl_with_node(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
template<class... Args>
|
|
||||||
inline BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
|
||||||
hash_unique_table<T>::emplace_empty_impl(Args&&... args)
|
|
||||||
{
|
|
||||||
node_constructor a(*this);
|
|
||||||
a.construct(std::forward<Args>(args)...);
|
|
||||||
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
|
||||||
template <class T> \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
|
||||||
inline BOOST_DEDUCED_TYPENAME \
|
|
||||||
hash_unique_table<T>::emplace_return \
|
|
||||||
hash_unique_table<T>::emplace_impl( \
|
|
||||||
key_type const& k, \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
||||||
{ \
|
|
||||||
std::size_t hash_value = this->hash_function()(k); \
|
|
||||||
bucket_ptr bucket \
|
|
||||||
= this->bucket_ptr_from_hash(hash_value); \
|
|
||||||
node_ptr pos = this->find_iterator(bucket, k); \
|
|
||||||
\
|
|
||||||
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
|
|
||||||
return emplace_return(iterator_base(bucket, pos), false); \
|
|
||||||
} else { \
|
|
||||||
node_constructor a(*this); \
|
|
||||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
|
||||||
\
|
|
||||||
if(this->reserve_for_insert(this->size_ + 1)) \
|
|
||||||
bucket = this->bucket_ptr_from_hash(hash_value); \
|
|
||||||
\
|
|
||||||
return emplace_return(iterator_base(bucket, \
|
|
||||||
add_node(a, bucket)), true); \
|
|
||||||
} \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
template <class T> \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
|
||||||
inline BOOST_DEDUCED_TYPENAME \
|
|
||||||
hash_unique_table<T>::emplace_return \
|
|
||||||
hash_unique_table<T>:: \
|
|
||||||
emplace_impl(no_key, \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
||||||
{ \
|
|
||||||
node_constructor a(*this); \
|
|
||||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
|
||||||
return emplace_impl_with_node(a); \
|
|
||||||
} \
|
|
||||||
\
|
|
||||||
template <class T> \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
|
||||||
inline BOOST_DEDUCED_TYPENAME \
|
|
||||||
hash_unique_table<T>::emplace_return \
|
|
||||||
hash_unique_table<T>:: \
|
|
||||||
emplace_empty_impl( \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
||||||
{ \
|
|
||||||
node_constructor a(*this); \
|
|
||||||
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
|
||||||
return emplace_return(this->emplace_empty_impl_with_node(a, 1), true); \
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
||||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
|
||||||
|
|
||||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
|
||||||
|
|
||||||
// Emplace (unique keys)
|
|
||||||
// (I'm using an overloaded emplace for both 'insert' and 'emplace')
|
|
||||||
|
|
||||||
// if hash function throws, basic exception safety
|
|
||||||
// strong otherwise
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
template<class... Args>
|
|
||||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
|
||||||
hash_unique_table<T>::emplace(Args&&... args)
|
|
||||||
{
|
|
||||||
return this->size_ ?
|
|
||||||
emplace_impl(
|
|
||||||
extractor::extract(std::forward<Args>(args)...),
|
|
||||||
std::forward<Args>(args)...) :
|
|
||||||
emplace_empty_impl(std::forward<Args>(args)...);
|
|
||||||
}
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
template <class Arg0>
|
|
||||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return
|
|
||||||
hash_unique_table<T>::emplace(Arg0 const& arg0)
|
|
||||||
{
|
|
||||||
return this->size_ ?
|
|
||||||
emplace_impl(extractor::extract(arg0), arg0) :
|
|
||||||
emplace_empty_impl(arg0);
|
|
||||||
}
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_INSERT_IMPL(z, num_params, _) \
|
|
||||||
template <class T> \
|
|
||||||
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params)> \
|
|
||||||
BOOST_DEDUCED_TYPENAME hash_unique_table<T>::emplace_return \
|
|
||||||
hash_unique_table<T>::emplace( \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
||||||
{ \
|
|
||||||
return this->size_ ? \
|
|
||||||
emplace_impl(extractor::extract(arg0, arg1), \
|
|
||||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)) : \
|
|
||||||
emplace_empty_impl( \
|
|
||||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
||||||
BOOST_UNORDERED_INSERT_IMPL, _)
|
|
||||||
|
|
||||||
#undef BOOST_UNORDERED_INSERT_IMPL
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
// Nothing after this point can throw.
|
||||||
// Insert range methods
|
|
||||||
|
return emplace_return(add_node(a, bucket_index, hash), true);
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template<class... Args>
|
||||||
template <class InputIt>
|
emplace_return emplace_impl(no_key, Args&&... args)
|
||||||
inline void hash_unique_table<T>::insert_range_impl2(
|
{
|
||||||
node_constructor& a, key_type const& k, InputIt i, InputIt j)
|
// Construct the node regardless - in order to get the key.
|
||||||
{
|
// It will be discarded if it isn't used
|
||||||
// No side effects in this initial code
|
node_constructor a(*this);
|
||||||
std::size_t hash_value = this->hash_function()(k);
|
a.construct(std::forward<Args>(args)...);
|
||||||
bucket_ptr bucket = this->bucket_ptr_from_hash(hash_value);
|
return emplace_impl_with_node(a);
|
||||||
node_ptr pos = this->find_iterator(bucket, k);
|
}
|
||||||
|
#else
|
||||||
|
|
||||||
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
template <class Arg0>
|
||||||
// Doesn't already exist, add to bucket.
|
emplace_return emplace(BOOST_FWD_REF(Arg0) arg0)
|
||||||
// Side effects only in this block.
|
{
|
||||||
|
return emplace_impl(
|
||||||
|
extractor::extract(boost::forward<Arg0>(arg0)),
|
||||||
|
boost::forward<Arg0>(arg0));
|
||||||
|
}
|
||||||
|
|
||||||
// Create the node before rehashing in case it throws an
|
#define BOOST_UNORDERED_INSERT1_IMPL(z, n, _) \
|
||||||
// exception (need strong safety in such a case).
|
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||||
a.construct(*i);
|
emplace_return emplace( \
|
||||||
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
|
||||||
|
{ \
|
||||||
|
return emplace_impl(extractor::extract(arg0, arg1), \
|
||||||
|
BOOST_UNORDERED_CALL_PARAMS(z, n)); \
|
||||||
|
}
|
||||||
|
|
||||||
// reserve has basic exception safety if the hash function
|
#define BOOST_UNORDERED_INSERT2_IMPL(z, n, _) \
|
||||||
// throws, strong otherwise.
|
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||||
if(this->size_ + 1 >= this->max_load_) {
|
emplace_return emplace_impl(key_type const& k, \
|
||||||
this->reserve_for_insert(this->size_ + insert_size(i, j));
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
|
||||||
bucket = this->bucket_ptr_from_hash(hash_value);
|
{ \
|
||||||
|
std::size_t hash = this->hash_function()(k); \
|
||||||
|
std::size_t bucket_index = hash % this->bucket_count_; \
|
||||||
|
node_ptr pos = this->find_node(bucket_index, hash, k); \
|
||||||
|
\
|
||||||
|
if (BOOST_UNORDERED_BORLAND_BOOL(pos)) { \
|
||||||
|
return emplace_return(pos, false); \
|
||||||
|
} else { \
|
||||||
|
node_constructor a(*this); \
|
||||||
|
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
|
||||||
|
\
|
||||||
|
if(this->reserve_for_insert(this->size_ + 1)) \
|
||||||
|
bucket_index = hash % this->bucket_count_; \
|
||||||
|
\
|
||||||
|
return emplace_return( \
|
||||||
|
add_node(a, bucket_index, hash), \
|
||||||
|
true); \
|
||||||
|
} \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
template <BOOST_UNORDERED_TEMPLATE_ARGS(z, n)> \
|
||||||
|
emplace_return emplace_impl(no_key, \
|
||||||
|
BOOST_UNORDERED_FUNCTION_PARAMS(z, n)) \
|
||||||
|
{ \
|
||||||
|
node_constructor a(*this); \
|
||||||
|
a.construct(BOOST_UNORDERED_CALL_PARAMS(z, n)); \
|
||||||
|
return emplace_impl_with_node(a); \
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_PP_REPEAT_FROM_TO(2, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||||
|
BOOST_UNORDERED_INSERT1_IMPL, _)
|
||||||
|
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||||
|
BOOST_UNORDERED_INSERT2_IMPL, _)
|
||||||
|
|
||||||
|
#undef BOOST_UNORDERED_INSERT1_IMPL
|
||||||
|
#undef BOOST_UNORDERED_INSERT2_IMPL
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////
|
||||||
|
// Insert range methods
|
||||||
|
//
|
||||||
|
// if hash function throws, or inserting > 1 element, basic exception
|
||||||
|
// safety strong otherwise
|
||||||
|
|
||||||
|
template <class InputIt>
|
||||||
|
void insert_range(InputIt i, InputIt j)
|
||||||
|
{
|
||||||
|
if(i != j)
|
||||||
|
return insert_range_impl(extractor::extract(*i), i, j);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIt>
|
||||||
|
void insert_range_impl(key_type const&, InputIt i, InputIt j)
|
||||||
|
{
|
||||||
|
node_constructor a(*this);
|
||||||
|
|
||||||
|
// Special case for empty buckets so that we can use
|
||||||
|
// max_load_ (which isn't valid when buckets_ is null).
|
||||||
|
if (!this->buckets_) {
|
||||||
|
insert_range_empty(a, extractor::extract(*i), i, j);
|
||||||
|
if (++i == j) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Nothing after this point can throw.
|
do {
|
||||||
add_node(a, bucket);
|
// Note: can't use get_key as '*i' might not be value_type - it
|
||||||
|
// could be a pair with first_types as key_type without const or a
|
||||||
|
// different second_type.
|
||||||
|
//
|
||||||
|
// TODO: Might be worth storing the value_type instead of the key
|
||||||
|
// here. Could be more efficient if '*i' is expensive. Could be
|
||||||
|
// less efficient if copying the full value_type is expensive.
|
||||||
|
insert_range_impl2(a, extractor::extract(*i), i, j);
|
||||||
|
} while(++i != j);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
template <class InputIt>
|
||||||
template <class InputIt>
|
void insert_range_empty(node_constructor& a, key_type const& k,
|
||||||
inline void hash_unique_table<T>::insert_range_impl(
|
InputIt i, InputIt j)
|
||||||
key_type const&, InputIt i, InputIt j)
|
{
|
||||||
{
|
std::size_t hash = this->hash_function()(k);
|
||||||
node_constructor a(*this);
|
|
||||||
|
|
||||||
if(!this->size_) {
|
|
||||||
a.construct(*i);
|
a.construct(*i);
|
||||||
this->emplace_empty_impl_with_node(a, 1);
|
this->reserve_for_insert(this->size_ + insert_size(i, j));
|
||||||
++i;
|
add_node(a, hash % this->bucket_count_, hash);
|
||||||
if(i == j) return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
do {
|
template <class InputIt>
|
||||||
// Note: can't use get_key as '*i' might not be value_type - it
|
void insert_range_impl2(node_constructor& a, key_type const& k,
|
||||||
// could be a pair with first_types as key_type without const or a
|
InputIt i, InputIt j)
|
||||||
// different second_type.
|
{
|
||||||
//
|
|
||||||
// TODO: Might be worth storing the value_type instead of the key
|
|
||||||
// here. Could be more efficient if '*i' is expensive. Could be
|
|
||||||
// less efficient if copying the full value_type is expensive.
|
|
||||||
insert_range_impl2(a, extractor::extract(*i), i, j);
|
|
||||||
} while(++i != j);
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
|
||||||
template <class InputIt>
|
|
||||||
inline void hash_unique_table<T>::insert_range_impl(
|
|
||||||
no_key, InputIt i, InputIt j)
|
|
||||||
{
|
|
||||||
node_constructor a(*this);
|
|
||||||
|
|
||||||
if(!this->size_) {
|
|
||||||
a.construct(*i);
|
|
||||||
this->emplace_empty_impl_with_node(a, 1);
|
|
||||||
++i;
|
|
||||||
if(i == j) return;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
// No side effects in this initial code
|
// No side effects in this initial code
|
||||||
a.construct(*i);
|
std::size_t hash = this->hash_function()(k);
|
||||||
emplace_impl_with_node(a);
|
std::size_t bucket_index = hash % this->bucket_count_;
|
||||||
} while(++i != j);
|
node_ptr pos = this->find_node(bucket_index, hash, k);
|
||||||
}
|
|
||||||
|
if (!BOOST_UNORDERED_BORLAND_BOOL(pos)) {
|
||||||
|
// Doesn't already exist, add to bucket.
|
||||||
|
// Side effects only in this block.
|
||||||
|
|
||||||
|
// Create the node before rehashing in case it throws an
|
||||||
|
// exception (need strong safety in such a case).
|
||||||
|
a.construct(*i);
|
||||||
|
|
||||||
|
// reserve has basic exception safety if the hash function
|
||||||
|
// throws, strong otherwise.
|
||||||
|
if(this->size_ + 1 >= this->max_load_) {
|
||||||
|
this->reserve_for_insert(this->size_ + insert_size(i, j));
|
||||||
|
bucket_index = hash % this->bucket_count_;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing after this point can throw.
|
||||||
|
add_node(a, bucket_index, hash);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// if hash function throws, or inserting > 1 element, basic exception safety
|
template <class InputIt>
|
||||||
// strong otherwise
|
void insert_range_impl(no_key, InputIt i, InputIt j)
|
||||||
template <class T>
|
{
|
||||||
template <class InputIt>
|
node_constructor a(*this);
|
||||||
void hash_unique_table<T>::insert_range(InputIt i, InputIt j)
|
|
||||||
|
do {
|
||||||
|
// No side effects in this initial code
|
||||||
|
a.construct(*i);
|
||||||
|
emplace_impl_with_node(a);
|
||||||
|
} while(++i != j);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class H, class P, class A>
|
||||||
|
struct set : public types<
|
||||||
|
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
|
||||||
|
BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
|
||||||
|
H, P, A,
|
||||||
|
set_extractor<BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
|
||||||
|
true>
|
||||||
|
{
|
||||||
|
typedef ::boost::unordered::detail::unique_table<set<H, P, A> > impl;
|
||||||
|
typedef ::boost::unordered::detail::table<set<H, P, A> > table_base;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class K, class H, class P, class A>
|
||||||
|
struct map : public types<
|
||||||
|
K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type,
|
||||||
|
H, P, A,
|
||||||
|
map_extractor<K, BOOST_DEDUCED_TYPENAME allocator_traits<A>::value_type>,
|
||||||
|
true>
|
||||||
{
|
{
|
||||||
if(i != j)
|
typedef ::boost::unordered::detail::unique_table<map<K, H, P, A> > impl;
|
||||||
return insert_range_impl(extractor::extract(*i), i, j);
|
typedef ::boost::unordered::detail::table<map<K, H, P, A> > table_base;
|
||||||
}
|
};
|
||||||
}}
|
}}}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,22 +1,127 @@
|
|||||||
|
|
||||||
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
// Copyright (C) 2003-2004 Jeremy B. Maitin-Shepard.
|
||||||
// Copyright (C) 2005-2009 Daniel James
|
// Copyright (C) 2005-2011 Daniel James
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
#ifndef BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||||
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
#define BOOST_UNORDERED_DETAIL_UTIL_HPP_INCLUDED
|
||||||
|
|
||||||
#include <cstddef>
|
|
||||||
#include <utility>
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/config/no_tr1/cmath.hpp>
|
||||||
|
#include <boost/detail/workaround.hpp>
|
||||||
|
#include <boost/detail/select_type.hpp>
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/iterator.hpp>
|
||||||
#include <boost/iterator/iterator_categories.hpp>
|
#include <boost/iterator/iterator_categories.hpp>
|
||||||
|
#include <boost/type_traits/aligned_storage.hpp>
|
||||||
|
#include <boost/type_traits/alignment_of.hpp>
|
||||||
|
#include <boost/type_traits/remove_const.hpp>
|
||||||
|
#include <boost/type_traits/is_empty.hpp>
|
||||||
|
#include <boost/throw_exception.hpp>
|
||||||
|
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||||
#include <boost/preprocessor/seq/size.hpp>
|
#include <boost/preprocessor/seq/size.hpp>
|
||||||
#include <boost/preprocessor/seq/enum.hpp>
|
#include <boost/preprocessor/seq/enum.hpp>
|
||||||
#include <boost/unordered/detail/fwd.hpp>
|
#include <boost/preprocessor/repetition/enum.hpp>
|
||||||
|
#include <boost/move/move.hpp>
|
||||||
|
#include <boost/swap.hpp>
|
||||||
|
|
||||||
namespace boost { namespace unordered_detail {
|
// Template parameters:
|
||||||
|
//
|
||||||
|
// H = Hash Function
|
||||||
|
// P = Predicate
|
||||||
|
// A = Value Allocator
|
||||||
|
// G = Bucket group policy, 'grouped' or 'ungrouped'
|
||||||
|
// E = Key Extractor
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_RVALUE_REFERENCES) && \
|
||||||
|
!defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||||
|
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||||
|
# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
|
||||||
|
# elif defined(_LIBCPP_VERSION)
|
||||||
|
# define BOOST_UNORDERED_STD_FORWARD_MOVE
|
||||||
|
# elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||||
|
# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804
|
||||||
|
# define BOOST_UNORDERED_STD_FORWARD_MOVE
|
||||||
|
# endif
|
||||||
|
# elif defined(__STL_CONFIG_H)
|
||||||
|
# elif defined(__MSL_CPP__)
|
||||||
|
# elif defined(__IBMCPP__)
|
||||||
|
# elif defined(MSIPL_COMPILE_H)
|
||||||
|
# elif (defined(_YVALS) && !defined(__IBMCPP__)) || defined(_CPPLIB_VER)
|
||||||
|
// Visual C++. A version check would be a good idea.
|
||||||
|
# define BOOST_UNORDERED_STD_FORWARD_MOVE
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_UNORDERED_EMPLACE_LIMIT)
|
||||||
|
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__SUNPRO_CC)
|
||||||
|
#define BOOST_UNORDERED_USE_RV_REF 0
|
||||||
|
#else
|
||||||
|
#define BOOST_UNORDERED_USE_RV_REF 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
|
|
||||||
|
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||||
|
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||||
|
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||||
|
|
||||||
|
#define BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
||||||
|
BOOST_PP_ENUM_PARAMS_Z(z, num_params, class Arg)
|
||||||
|
|
||||||
|
#define BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
||||||
|
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_FUNCTION_PARAMS2, _)
|
||||||
|
#define BOOST_UNORDERED_FUNCTION_PARAMS2(z, i, _) \
|
||||||
|
BOOST_FWD_REF(Arg##i) arg##i
|
||||||
|
|
||||||
|
#define BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
||||||
|
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_PARAMS2, _)
|
||||||
|
#define BOOST_UNORDERED_CALL_PARAMS2(z, i, _) \
|
||||||
|
boost::forward<Arg##i>(arg##i)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost { namespace unordered { namespace detail {
|
||||||
|
|
||||||
|
static const float minimum_max_load_factor = 1e-3f;
|
||||||
|
static const std::size_t default_bucket_count = 11;
|
||||||
|
struct move_tag {};
|
||||||
|
|
||||||
|
struct empty_emplace {};
|
||||||
|
|
||||||
|
template <class T> class unique_table;
|
||||||
|
template <class T> class equivalent_table;
|
||||||
|
template <class Alloc, bool Unique> class node_constructor;
|
||||||
|
template <class ValueType>
|
||||||
|
struct set_extractor;
|
||||||
|
template <class Key, class ValueType>
|
||||||
|
struct map_extractor;
|
||||||
|
struct no_key;
|
||||||
|
|
||||||
|
// Explicitly call a destructor
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline void destroy(T* x) {
|
||||||
|
x->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// convert double to std::size_t
|
// convert double to std::size_t
|
||||||
@ -95,12 +200,19 @@ namespace boost { namespace unordered_detail {
|
|||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// pair_cast - because some libraries don't have the full pair constructors.
|
// pair_cast - because some libraries don't have the full pair constructors.
|
||||||
|
|
||||||
|
#if 0
|
||||||
template <class Dst1, class Dst2, class Src1, class Src2>
|
template <class Dst1, class Dst2, class Src1, class Src2>
|
||||||
inline std::pair<Dst1, Dst2> pair_cast(std::pair<Src1, Src2> const& x)
|
inline std::pair<Dst1, Dst2> pair_cast(std::pair<Src1, Src2> const& x)
|
||||||
{
|
{
|
||||||
return std::pair<Dst1, Dst2>(Dst1(x.first), Dst2(x.second));
|
return std::pair<Dst1, Dst2>(Dst1(x.first), Dst2(x.second));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \
|
||||||
|
::boost::unordered::detail::pair_cast<First, Last>(Argument)
|
||||||
|
#else
|
||||||
|
#define BOOST_UNORDERED_PAIR_CAST(First, Last, Argument) \
|
||||||
|
Argument
|
||||||
|
#endif
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// insert_size/initial_size
|
// insert_size/initial_size
|
||||||
|
|
||||||
@ -116,13 +228,13 @@ namespace boost { namespace unordered_detail {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <class I>
|
template <class I>
|
||||||
inline std::size_t insert_size(I i, I j, boost::forward_traversal_tag)
|
inline std::size_t insert_size(I i, I j, ::boost::forward_traversal_tag)
|
||||||
{
|
{
|
||||||
return std::distance(i, j);
|
return std::distance(i, j);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class I>
|
template <class I>
|
||||||
inline std::size_t insert_size(I, I, boost::incrementable_traversal_tag)
|
inline std::size_t insert_size(I, I, ::boost::incrementable_traversal_tag)
|
||||||
{
|
{
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
@ -130,202 +242,114 @@ namespace boost { namespace unordered_detail {
|
|||||||
template <class I>
|
template <class I>
|
||||||
inline std::size_t insert_size(I i, I j)
|
inline std::size_t insert_size(I i, I j)
|
||||||
{
|
{
|
||||||
BOOST_DEDUCED_TYPENAME boost::iterator_traversal<I>::type
|
BOOST_DEDUCED_TYPENAME ::boost::iterator_traversal<I>::type
|
||||||
iterator_traversal_tag;
|
iterator_traversal_tag;
|
||||||
return insert_size(i, j, iterator_traversal_tag);
|
return insert_size(i, j, iterator_traversal_tag);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class I>
|
template <class I>
|
||||||
inline std::size_t initial_size(I i, I j,
|
inline std::size_t initial_size(I i, I j,
|
||||||
std::size_t num_buckets = boost::unordered_detail::default_bucket_count)
|
std::size_t num_buckets = ::boost::unordered::detail::default_bucket_count)
|
||||||
{
|
{
|
||||||
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
|
return (std::max)(static_cast<std::size_t>(insert_size(i, j)) + 1,
|
||||||
num_buckets);
|
num_buckets);
|
||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////
|
||||||
// Node Constructors
|
// compressed_pair
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
template <typename T, int Index>
|
||||||
|
struct compressed_base : private T
|
||||||
template <class T, class... Args>
|
|
||||||
inline void construct_impl(T*, void* address, Args&&... args)
|
|
||||||
{
|
{
|
||||||
new(address) T(std::forward<Args>(args)...);
|
compressed_base(T const& x) : T(x) {}
|
||||||
}
|
compressed_base(T& x, move_tag) : T(boost::move(x)) {}
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_CPP0X_PAIR)
|
T& get() { return *this; }
|
||||||
template <class First, class Second, class Key, class Arg0, class... Args>
|
T const& get() const { return *this; }
|
||||||
inline void construct_impl(std::pair<First, Second>*, void* address,
|
};
|
||||||
Key&& k, Arg0&& arg0, Args&&... args)
|
|
||||||
)
|
template <typename T, int Index>
|
||||||
|
struct uncompressed_base
|
||||||
{
|
{
|
||||||
new(address) std::pair<First, Second>(k,
|
uncompressed_base(T const& x) : value_(x) {}
|
||||||
Second(arg0, std::forward<Args>(args)...);
|
uncompressed_base(T& x, move_tag) : value_(boost::move(x)) {}
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#else
|
T& get() { return value_; }
|
||||||
|
T const& get() const { return value_; }
|
||||||
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
private:
|
||||||
template < \
|
T value_;
|
||||||
class T, \
|
};
|
||||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
|
||||||
> \
|
template <typename T, int Index>
|
||||||
inline void construct_impl( \
|
struct generate_base
|
||||||
T*, void* address, \
|
: boost::detail::if_true<
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
boost::is_empty<T>::value
|
||||||
) \
|
>:: BOOST_NESTED_TEMPLATE then<
|
||||||
{ \
|
compressed_base<T, Index>,
|
||||||
new(address) T( \
|
uncompressed_base<T, Index>
|
||||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params)); \
|
>
|
||||||
} \
|
{};
|
||||||
\
|
|
||||||
template <class First, class Second, class Key, \
|
template <typename T1, typename T2>
|
||||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
struct compressed_pair
|
||||||
> \
|
: private generate_base<T1, 1>::type,
|
||||||
inline void construct_impl( \
|
private generate_base<T2, 2>::type
|
||||||
std::pair<First, Second>*, void* address, \
|
|
||||||
Key const& k, BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params)) \
|
|
||||||
{ \
|
|
||||||
new(address) std::pair<First, Second>(k, \
|
|
||||||
Second(BOOST_UNORDERED_CALL_PARAMS(z, num_params))); \
|
|
||||||
}
|
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
|
||||||
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
|
|
||||||
|
|
||||||
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// hash_node_constructor
|
|
||||||
//
|
|
||||||
// Used to construct nodes in an exception safe manner.
|
|
||||||
|
|
||||||
template <class Alloc, class Grouped>
|
|
||||||
class hash_node_constructor
|
|
||||||
{
|
{
|
||||||
typedef hash_buckets<Alloc, Grouped> buckets;
|
typedef BOOST_DEDUCED_TYPENAME generate_base<T1, 1>::type base1;
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::node node;
|
typedef BOOST_DEDUCED_TYPENAME generate_base<T2, 2>::type base2;
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::real_node_ptr real_node_ptr;
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME buckets::value_type value_type;
|
|
||||||
|
|
||||||
buckets& buckets_;
|
typedef T1 first_type;
|
||||||
real_node_ptr node_;
|
typedef T2 second_type;
|
||||||
bool node_constructed_;
|
|
||||||
bool value_constructed_;
|
first_type& first() {
|
||||||
|
return static_cast<base1*>(this)->get();
|
||||||
public:
|
|
||||||
|
|
||||||
hash_node_constructor(buckets& m) :
|
|
||||||
buckets_(m),
|
|
||||||
node_(),
|
|
||||||
node_constructed_(false),
|
|
||||||
value_constructed_(false)
|
|
||||||
{
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~hash_node_constructor();
|
first_type const& first() const {
|
||||||
void construct_preamble();
|
return static_cast<base1 const*>(this)->get();
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
|
||||||
template <class... Args>
|
|
||||||
void construct(Args&&... args)
|
|
||||||
{
|
|
||||||
construct_preamble();
|
|
||||||
construct_impl((value_type*) 0, node_->address(),
|
|
||||||
std::forward<Args>(args)...);
|
|
||||||
value_constructed_ = true;
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_CONSTRUCT(z, num_params, _) \
|
|
||||||
template < \
|
|
||||||
BOOST_UNORDERED_TEMPLATE_ARGS(z, num_params) \
|
|
||||||
> \
|
|
||||||
void construct( \
|
|
||||||
BOOST_UNORDERED_FUNCTION_PARAMS(z, num_params) \
|
|
||||||
) \
|
|
||||||
{ \
|
|
||||||
construct_preamble(); \
|
|
||||||
construct_impl( \
|
|
||||||
(value_type*) 0, node_->address(), \
|
|
||||||
BOOST_UNORDERED_CALL_PARAMS(z, num_params) \
|
|
||||||
); \
|
|
||||||
value_constructed_ = true; \
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT,
|
second_type& second() {
|
||||||
BOOST_UNORDERED_CONSTRUCT, _)
|
return static_cast<base2*>(this)->get();
|
||||||
|
|
||||||
#undef BOOST_UNORDERED_CONSTRUCT
|
|
||||||
|
|
||||||
#endif
|
|
||||||
template <class K, class M>
|
|
||||||
void construct_pair(K const& k, M*)
|
|
||||||
{
|
|
||||||
construct_preamble();
|
|
||||||
new(node_->address()) value_type(k, M());
|
|
||||||
value_constructed_ = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
value_type& value() const
|
second_type const& second() const {
|
||||||
{
|
return static_cast<base2 const*>(this)->get();
|
||||||
BOOST_ASSERT(node_);
|
|
||||||
return node_->value();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// no throw
|
template <typename First, typename Second>
|
||||||
BOOST_DEDUCED_TYPENAME buckets::node_ptr release()
|
compressed_pair(First const& x1, Second const& x2)
|
||||||
|
: base1(x1), base2(x2) {}
|
||||||
|
|
||||||
|
compressed_pair(compressed_pair const& x)
|
||||||
|
: base1(x.first()), base2(x.second()) {}
|
||||||
|
|
||||||
|
compressed_pair(compressed_pair& x, move_tag m)
|
||||||
|
: base1(x.first(), m), base2(x.second(), m) {}
|
||||||
|
|
||||||
|
void assign(compressed_pair const& x)
|
||||||
{
|
{
|
||||||
real_node_ptr p = node_;
|
first() = x.first();
|
||||||
node_ = real_node_ptr();
|
second() = x.second();
|
||||||
// node_ptr cast
|
}
|
||||||
return buckets_.bucket_alloc().address(*p);
|
|
||||||
|
void move_assign(compressed_pair& x)
|
||||||
|
{
|
||||||
|
first() = boost::move(x.first());
|
||||||
|
second() = boost::move(x.second());
|
||||||
|
}
|
||||||
|
|
||||||
|
void swap(compressed_pair& x)
|
||||||
|
{
|
||||||
|
boost::swap(first(), x.first());
|
||||||
|
boost::swap(second(), x.second());
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
hash_node_constructor(hash_node_constructor const&);
|
// Prevent assignment just to make use of assign or
|
||||||
hash_node_constructor& operator=(hash_node_constructor const&);
|
// move_assign explicit.
|
||||||
|
compressed_pair& operator=(compressed_pair const&);
|
||||||
};
|
};
|
||||||
|
}}}
|
||||||
// hash_node_constructor
|
|
||||||
|
|
||||||
template <class Alloc, class Grouped>
|
|
||||||
inline hash_node_constructor<Alloc, Grouped>::~hash_node_constructor()
|
|
||||||
{
|
|
||||||
if (node_) {
|
|
||||||
if (value_constructed_) {
|
|
||||||
#if BOOST_WORKAROUND(__CODEGEARC__, BOOST_TESTED_AT(0x0613))
|
|
||||||
struct dummy { hash_node<Alloc, Grouped> x; };
|
|
||||||
#endif
|
|
||||||
boost::unordered_detail::destroy(node_->value_ptr());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (node_constructed_)
|
|
||||||
buckets_.node_alloc().destroy(node_);
|
|
||||||
|
|
||||||
buckets_.node_alloc().deallocate(node_, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Alloc, class Grouped>
|
|
||||||
inline void hash_node_constructor<Alloc, Grouped>::construct_preamble()
|
|
||||||
{
|
|
||||||
if(!node_) {
|
|
||||||
node_constructed_ = false;
|
|
||||||
value_constructed_ = false;
|
|
||||||
|
|
||||||
node_ = buckets_.node_alloc().allocate(1);
|
|
||||||
buckets_.node_alloc().construct(node_, node());
|
|
||||||
node_constructed_ = true;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
BOOST_ASSERT(node_constructed_ && value_constructed_);
|
|
||||||
boost::unordered_detail::destroy(node_->value_ptr());
|
|
||||||
value_constructed_ = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
// Copyright (C) 2008-2009 Daniel James.
|
// Copyright (C) 2008-2011 Daniel James.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -10,44 +10,38 @@
|
|||||||
# pragma once
|
# pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/unordered/detail/fwd.hpp>
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
#include <boost/functional/hash_fwd.hpp>
|
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
template <class K,
|
namespace unordered
|
||||||
class T,
|
{
|
||||||
class H = hash<K>,
|
template <class K, class T, class H, class P, class A>
|
||||||
class P = std::equal_to<K>,
|
inline bool operator==(unordered_map<K, T, H, P, A> const&,
|
||||||
class A = std::allocator<std::pair<const K, T> > >
|
unordered_map<K, T, H, P, A> const&);
|
||||||
class unordered_map;
|
template <class K, class T, class H, class P, class A>
|
||||||
template <class K, class T, class H, class P, class A>
|
inline bool operator!=(unordered_map<K, T, H, P, A> const&,
|
||||||
inline bool operator==(unordered_map<K, T, H, P, A> const&,
|
unordered_map<K, T, H, P, A> const&);
|
||||||
unordered_map<K, T, H, P, A> const&);
|
template <class K, class T, class H, class P, class A>
|
||||||
template <class K, class T, class H, class P, class A>
|
inline void swap(unordered_map<K, T, H, P, A>&,
|
||||||
inline bool operator!=(unordered_map<K, T, H, P, A> const&,
|
unordered_map<K, T, H, P, A>&);
|
||||||
unordered_map<K, T, H, P, A> const&);
|
|
||||||
template <class K, class T, class H, class P, class A>
|
|
||||||
inline void swap(unordered_map<K, T, H, P, A>&,
|
|
||||||
unordered_map<K, T, H, P, A>&);
|
|
||||||
|
|
||||||
template <class K,
|
template <class K, class T, class H, class P, class A>
|
||||||
class T,
|
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
||||||
class H = hash<K>,
|
unordered_multimap<K, T, H, P, A> const&);
|
||||||
class P = std::equal_to<K>,
|
template <class K, class T, class H, class P, class A>
|
||||||
class A = std::allocator<std::pair<const K, T> > >
|
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||||
class unordered_multimap;
|
unordered_multimap<K, T, H, P, A> const&);
|
||||||
template <class K, class T, class H, class P, class A>
|
template <class K, class T, class H, class P, class A>
|
||||||
inline bool operator==(unordered_multimap<K, T, H, P, A> const&,
|
inline void swap(unordered_multimap<K, T, H, P, A>&,
|
||||||
unordered_multimap<K, T, H, P, A> const&);
|
unordered_multimap<K, T, H, P, A>&);
|
||||||
template <class K, class T, class H, class P, class A>
|
}
|
||||||
inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
|
||||||
unordered_multimap<K, T, H, P, A> const&);
|
using ::boost::unordered::unordered_map;
|
||||||
template <class K, class T, class H, class P, class A>
|
using ::boost::unordered::unordered_multimap;
|
||||||
inline void swap(unordered_multimap<K, T, H, P, A>&,
|
using ::boost::unordered::swap;
|
||||||
unordered_multimap<K, T, H, P, A>&);
|
using ::boost::unordered::operator==;
|
||||||
|
using ::boost::unordered::operator!=;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -1,5 +1,5 @@
|
|||||||
|
|
||||||
// Copyright (C) 2008-2009 Daniel James.
|
// Copyright (C) 2008-2011 Daniel James.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -10,42 +10,38 @@
|
|||||||
# pragma once
|
# pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/config.hpp>
|
#include <boost/unordered/detail/fwd.hpp>
|
||||||
#include <memory>
|
|
||||||
#include <functional>
|
|
||||||
#include <boost/functional/hash_fwd.hpp>
|
|
||||||
|
|
||||||
namespace boost
|
namespace boost
|
||||||
{
|
{
|
||||||
template <class T,
|
namespace unordered
|
||||||
class H = hash<T>,
|
{
|
||||||
class P = std::equal_to<T>,
|
template <class T, class H, class P, class A>
|
||||||
class A = std::allocator<T> >
|
inline bool operator==(unordered_set<T, H, P, A> const&,
|
||||||
class unordered_set;
|
unordered_set<T, H, P, A> const&);
|
||||||
template <class T, class H, class P, class A>
|
template <class T, class H, class P, class A>
|
||||||
inline bool operator==(unordered_set<T, H, P, A> const&,
|
inline bool operator!=(unordered_set<T, H, P, A> const&,
|
||||||
unordered_set<T, H, P, A> const&);
|
unordered_set<T, H, P, A> const&);
|
||||||
template <class T, class H, class P, class A>
|
template <class T, class H, class P, class A>
|
||||||
inline bool operator!=(unordered_set<T, H, P, A> const&,
|
inline void swap(unordered_set<T, H, P, A> &m1,
|
||||||
unordered_set<T, H, P, A> const&);
|
unordered_set<T, H, P, A> &m2);
|
||||||
template <class T, class H, class P, class A>
|
|
||||||
inline void swap(unordered_set<T, H, P, A> &m1,
|
|
||||||
unordered_set<T, H, P, A> &m2);
|
|
||||||
|
|
||||||
template <class T,
|
template <class T, class H, class P, class A>
|
||||||
class H = hash<T>,
|
inline bool operator==(unordered_multiset<T, H, P, A> const&,
|
||||||
class P = std::equal_to<T>,
|
unordered_multiset<T, H, P, A> const&);
|
||||||
class A = std::allocator<T> >
|
template <class T, class H, class P, class A>
|
||||||
class unordered_multiset;
|
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||||
template <class T, class H, class P, class A>
|
unordered_multiset<T, H, P, A> const&);
|
||||||
inline bool operator==(unordered_multiset<T, H, P, A> const&,
|
template <class T, class H, class P, class A>
|
||||||
unordered_multiset<T, H, P, A> const&);
|
inline void swap(unordered_multiset<T, H, P, A> &m1,
|
||||||
template <class T, class H, class P, class A>
|
unordered_multiset<T, H, P, A> &m2);
|
||||||
inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
}
|
||||||
unordered_multiset<T, H, P, A> const&);
|
|
||||||
template <class T, class H, class P, class A>
|
using ::boost::unordered::unordered_set;
|
||||||
inline void swap(unordered_multiset<T, H, P, A> &m1,
|
using ::boost::unordered::unordered_multiset;
|
||||||
unordered_multiset<T, H, P, A> &m2);
|
using ::boost::unordered::swap;
|
||||||
|
using ::boost::unordered::operator==;
|
||||||
|
using ::boost::unordered::operator!=;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,13 +27,12 @@ struct self_swap_base : public test::exception_base
|
|||||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const {
|
||||||
std::string scope(test::scope);
|
std::string scope(test::scope);
|
||||||
|
|
||||||
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||||
BOOST_TEST(
|
BOOST_TEST(
|
||||||
scope == "hash::operator(hash)" ||
|
scope == "hash::hash(hash)" ||
|
||||||
scope == "hash::operator=(hash)" ||
|
scope == "hash::operator=(hash)" ||
|
||||||
scope == "equal_to::operator(equal_to)" ||
|
scope == "equal_to::equal_to(equal_to)" ||
|
||||||
scope == "equal_to::operator=(equal_to)");
|
scope == "equal_to::operator=(equal_to)");
|
||||||
#endif
|
|
||||||
|
|
||||||
test::check_equivalent_keys(x);
|
test::check_equivalent_keys(x);
|
||||||
}
|
}
|
||||||
@ -82,13 +81,12 @@ struct swap_base : public test::exception_base
|
|||||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
|
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const {
|
||||||
std::string scope(test::scope);
|
std::string scope(test::scope);
|
||||||
|
|
||||||
#if BOOST_UNORDERED_SWAP_METHOD != 2
|
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||||
BOOST_TEST(
|
BOOST_TEST(
|
||||||
scope == "hash::operator(hash)" ||
|
scope == "hash::hash(hash)" ||
|
||||||
scope == "hash::operator=(hash)" ||
|
scope == "hash::operator=(hash)" ||
|
||||||
scope == "equal_to::operator(equal_to)" ||
|
scope == "equal_to::equal_to(equal_to)" ||
|
||||||
scope == "equal_to::operator=(equal_to)");
|
scope == "equal_to::operator=(equal_to)");
|
||||||
#endif
|
|
||||||
|
|
||||||
test::check_equivalent_keys(d.x);
|
test::check_equivalent_keys(d.x);
|
||||||
test::check_equivalent_keys(d.y);
|
test::check_equivalent_keys(d.y);
|
||||||
|
@ -75,6 +75,13 @@ namespace test {
|
|||||||
namespace {
|
namespace {
|
||||||
object_count& global_object_count = globally_counted_object::count_;
|
object_count& global_object_count = globally_counted_object::count_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct check_instances {
|
||||||
|
int instances;
|
||||||
|
|
||||||
|
check_instances() : instances(global_object_count.instances) {}
|
||||||
|
~check_instances() { BOOST_TEST(global_object_count.instances == instances); }
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -65,37 +65,32 @@ namespace test
|
|||||||
std::cerr<<x1.count(key)<<","<<count<<"\n";
|
std::cerr<<x1.count(key)<<","<<count<<"\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
// I'm not bothering with the following test for now, as the
|
// Check that the keys are in the correct bucket and are
|
||||||
// previous test is probably more enough to catch the kind of
|
// adjacent in the bucket.
|
||||||
// errors that this would catch (if an element was in the wrong
|
BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
|
||||||
// bucket it not be found by the call to count, if elements are not
|
BOOST_DEDUCED_TYPENAME X::const_local_iterator
|
||||||
// adjacent then they would be caught when checking against
|
lit = x1.begin(bucket), lend = x1.end(bucket);
|
||||||
// found_.
|
for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
||||||
|
if(lit == lend)
|
||||||
// // Check that the keys are in the correct bucket and are
|
BOOST_ERROR("Unable to find element with a local_iterator");
|
||||||
// // adjacent in the bucket.
|
unsigned int count2 = 0;
|
||||||
// BOOST_DEDUCED_TYPENAME X::size_type bucket = x1.bucket(key);
|
for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
|
||||||
// BOOST_DEDUCED_TYPENAME X::const_local_iterator
|
if(count != count2)
|
||||||
// lit = x1.begin(bucket), lend = x1.end(bucket);
|
BOOST_ERROR("Element count doesn't match local_iterator.");
|
||||||
// for(; lit != lend && !eq(get_key<X>(*lit), key); ++lit) continue;
|
for(; lit != lend; ++lit) {
|
||||||
// if(lit == lend)
|
if(eq(get_key<X>(*lit), key)) {
|
||||||
// BOOST_ERROR("Unable to find element with a local_iterator");
|
BOOST_ERROR("Non-adjacent element with equivalent key "
|
||||||
// unsigned int count2 = 0;
|
"in bucket.");
|
||||||
// for(; lit != lend && eq(get_key<X>(*lit), key); ++lit) ++count2;
|
break;
|
||||||
// if(count != count2)
|
}
|
||||||
// BOOST_ERROR("Element count doesn't match local_iterator.");
|
}
|
||||||
// for(; lit != lend; ++lit) {
|
|
||||||
// if(eq(get_key<X>(*lit), key)) {
|
|
||||||
// BOOST_ERROR("Non-adjacent element with equivalent key "
|
|
||||||
// "in bucket.");
|
|
||||||
// break;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Finally, check that size matches up.
|
// Finally, check that size matches up.
|
||||||
if(x1.size() != size)
|
if(x1.size() != size) {
|
||||||
BOOST_ERROR("x1.size() doesn't match actual size.");
|
BOOST_ERROR("x1.size() doesn't match actual size.");
|
||||||
|
std::cout<<x1.size()<<"/"<<size<<std::endl;
|
||||||
|
}
|
||||||
float load_factor =
|
float load_factor =
|
||||||
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
|
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -70,7 +70,7 @@ namespace test
|
|||||||
template <class Alloc = std::allocator<int> >
|
template <class Alloc = std::allocator<int> >
|
||||||
struct memory_tracker {
|
struct memory_tracker {
|
||||||
typedef BOOST_DEDUCED_TYPENAME
|
typedef BOOST_DEDUCED_TYPENAME
|
||||||
boost::unordered_detail::rebind_wrap<Alloc,
|
::boost::unordered::detail::rebind_wrap<Alloc,
|
||||||
std::pair<memory_area const, memory_track> >::type
|
std::pair<memory_area const, memory_track> >::type
|
||||||
allocator_type;
|
allocator_type;
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ namespace test
|
|||||||
}
|
}
|
||||||
|
|
||||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
|
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
|
||||||
int tag)
|
int tag, bool check_tag_ = true)
|
||||||
{
|
{
|
||||||
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
|
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
|
||||||
allocated_memory.find(
|
allocated_memory.find(
|
||||||
@ -147,7 +147,7 @@ namespace test
|
|||||||
} else {
|
} else {
|
||||||
BOOST_TEST(pos->first.start == ptr);
|
BOOST_TEST(pos->first.start == ptr);
|
||||||
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
|
BOOST_TEST(pos->first.end == (char*) ptr + n * size);
|
||||||
BOOST_TEST(pos->second.tag_ == tag);
|
if (check_tag_) BOOST_TEST(pos->second.tag_ == tag);
|
||||||
allocated_memory.erase(pos);
|
allocated_memory.erase(pos);
|
||||||
}
|
}
|
||||||
BOOST_TEST(count_allocations > 0);
|
BOOST_TEST(count_allocations > 0);
|
||||||
@ -168,6 +168,37 @@ namespace test
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace detail
|
||||||
|
{
|
||||||
|
// This won't be a problem as I'm only using a single compile unit
|
||||||
|
// in each test (this is actually required by the minimal test
|
||||||
|
// framework).
|
||||||
|
//
|
||||||
|
// boostinspect:nounnamed
|
||||||
|
namespace {
|
||||||
|
test::detail::memory_tracker<std::allocator<int> > tracker;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <int Value>
|
||||||
|
struct bool_type {
|
||||||
|
enum { value = (Value ? true : false) };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct true_type {
|
||||||
|
enum { value = true };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct false_type {
|
||||||
|
enum { value = false };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Alloc>
|
||||||
|
int selected_count(Alloc const&)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
294
test/objects/cxx11_allocator.hpp
Normal file
294
test/objects/cxx11_allocator.hpp
Normal file
@ -0,0 +1,294 @@
|
|||||||
|
|
||||||
|
// Copyright 2006-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)
|
||||||
|
|
||||||
|
#if !defined(BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER)
|
||||||
|
#define BOOST_UNORDERED_TEST_CXX11_ALLOCATOR_HEADER
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/limits.hpp>
|
||||||
|
#include <cstddef>
|
||||||
|
|
||||||
|
#include "../helpers/fwd.hpp"
|
||||||
|
#include "../helpers/memory.hpp"
|
||||||
|
|
||||||
|
namespace test
|
||||||
|
{
|
||||||
|
struct allocator_false
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
is_select_on_copy = 0,
|
||||||
|
is_propagate_on_swap = 0,
|
||||||
|
is_propagate_on_assign = 0,
|
||||||
|
is_propagate_on_move = 0
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct allocator_flags_all
|
||||||
|
{
|
||||||
|
enum {
|
||||||
|
is_select_on_copy = 1,
|
||||||
|
is_propagate_on_swap = 1,
|
||||||
|
is_propagate_on_assign = 1,
|
||||||
|
is_propagate_on_move = 1
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
struct select_copy : allocator_false
|
||||||
|
{ enum { is_select_on_copy = 1 }; };
|
||||||
|
struct propagate_swap : allocator_false
|
||||||
|
{ enum { is_propagate_on_swap = 1 }; };
|
||||||
|
struct propagate_assign : allocator_false
|
||||||
|
{ enum { is_propagate_on_assign = 1 }; };
|
||||||
|
struct propagate_move : allocator_false
|
||||||
|
{ enum { is_propagate_on_move = 1 }; };
|
||||||
|
|
||||||
|
struct no_select_copy : allocator_flags_all
|
||||||
|
{ enum { is_select_on_copy = 0 }; };
|
||||||
|
struct no_propagate_swap : allocator_flags_all
|
||||||
|
{ enum { is_propagate_on_swap = 0 }; };
|
||||||
|
struct no_propagate_assign : allocator_flags_all
|
||||||
|
{ enum { is_propagate_on_assign = 0 }; };
|
||||||
|
struct no_propagate_move : allocator_flags_all
|
||||||
|
{ enum { is_propagate_on_move = 0 }; };
|
||||||
|
|
||||||
|
template <typename Flag>
|
||||||
|
struct swap_allocator_base
|
||||||
|
{
|
||||||
|
struct propagate_on_container_swap {
|
||||||
|
enum { value = Flag::is_propagate_on_swap }; };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Flag>
|
||||||
|
struct assign_allocator_base
|
||||||
|
{
|
||||||
|
struct propagate_on_container_copy_assignment {
|
||||||
|
enum { value = Flag::is_propagate_on_assign }; };
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Flag>
|
||||||
|
struct move_allocator_base
|
||||||
|
{
|
||||||
|
struct propagate_on_container_move_assignment {
|
||||||
|
enum { value = Flag::is_propagate_on_move }; };
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
// boostinspect:nounnamed
|
||||||
|
bool force_equal_allocator_value = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct force_equal_allocator
|
||||||
|
{
|
||||||
|
bool old_value_;
|
||||||
|
|
||||||
|
explicit force_equal_allocator(bool value)
|
||||||
|
: old_value_(force_equal_allocator_value)
|
||||||
|
{ force_equal_allocator_value = value; }
|
||||||
|
|
||||||
|
~force_equal_allocator()
|
||||||
|
{ force_equal_allocator_value = old_value_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
struct cxx11_allocator_base
|
||||||
|
{
|
||||||
|
int tag_;
|
||||||
|
int selected_;
|
||||||
|
|
||||||
|
typedef std::size_t size_type;
|
||||||
|
typedef std::ptrdiff_t difference_type;
|
||||||
|
typedef T* pointer;
|
||||||
|
typedef T const* const_pointer;
|
||||||
|
typedef T& reference;
|
||||||
|
typedef T const& const_reference;
|
||||||
|
typedef T value_type;
|
||||||
|
|
||||||
|
explicit cxx11_allocator_base(int t)
|
||||||
|
: tag_(t), selected_(0)
|
||||||
|
{
|
||||||
|
detail::tracker.allocator_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Y> cxx11_allocator_base(
|
||||||
|
cxx11_allocator_base<Y> const& x)
|
||||||
|
: tag_(x.tag_), selected_(x.selected_)
|
||||||
|
{
|
||||||
|
detail::tracker.allocator_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
cxx11_allocator_base(cxx11_allocator_base const& x)
|
||||||
|
: tag_(x.tag_), selected_(x.selected_)
|
||||||
|
{
|
||||||
|
detail::tracker.allocator_ref();
|
||||||
|
}
|
||||||
|
|
||||||
|
~cxx11_allocator_base()
|
||||||
|
{
|
||||||
|
detail::tracker.allocator_unref();
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer address(reference r)
|
||||||
|
{
|
||||||
|
return pointer(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
const_pointer address(const_reference r)
|
||||||
|
{
|
||||||
|
return const_pointer(&r);
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer allocate(size_type n) {
|
||||||
|
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||||
|
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
pointer allocate(size_type n, void const* u)
|
||||||
|
{
|
||||||
|
pointer ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||||
|
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(pointer p, size_type n)
|
||||||
|
{
|
||||||
|
// Only checking tags when propagating swap.
|
||||||
|
// Note that tags will be tested
|
||||||
|
// properly in the normal allocator.
|
||||||
|
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_,
|
||||||
|
!force_equal_allocator_value);
|
||||||
|
::operator delete((void*) p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct(T* p, T const& t) {
|
||||||
|
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||||
|
new(p) T(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
|
template<typename... Args> void construct(T* p, Args&&... args) {
|
||||||
|
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||||
|
new(p) T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void destroy(T* p) {
|
||||||
|
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||||
|
p->~T();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_type max_size() const {
|
||||||
|
return (std::numeric_limits<size_type>::max)();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Flags = propagate_swap,
|
||||||
|
bool SelectCopy = Flags::is_select_on_copy ? true : false>
|
||||||
|
struct cxx11_allocator :
|
||||||
|
public cxx11_allocator_base<T>,
|
||||||
|
public swap_allocator_base<Flags>,
|
||||||
|
public assign_allocator_base<Flags>,
|
||||||
|
public move_allocator_base<Flags>,
|
||||||
|
Flags
|
||||||
|
{
|
||||||
|
template <typename U> struct rebind {
|
||||||
|
typedef cxx11_allocator<U, Flags> other;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit cxx11_allocator(int t = 0)
|
||||||
|
: cxx11_allocator_base<T>(t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Y> cxx11_allocator(
|
||||||
|
cxx11_allocator<Y, Flags> const& x)
|
||||||
|
: cxx11_allocator_base<T>(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cxx11_allocator(cxx11_allocator const& x)
|
||||||
|
: cxx11_allocator_base<T>(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// When not propagating swap, allocators are always equal
|
||||||
|
// to avoid undefined behaviour.
|
||||||
|
bool operator==(cxx11_allocator const& x) const
|
||||||
|
{
|
||||||
|
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(cxx11_allocator const& x) const
|
||||||
|
{
|
||||||
|
return !(*this == x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Flags>
|
||||||
|
struct cxx11_allocator<T, Flags, true> :
|
||||||
|
public cxx11_allocator_base<T>,
|
||||||
|
public swap_allocator_base<Flags>,
|
||||||
|
public assign_allocator_base<Flags>,
|
||||||
|
public move_allocator_base<Flags>,
|
||||||
|
Flags
|
||||||
|
{
|
||||||
|
cxx11_allocator select_on_container_copy_construction() const
|
||||||
|
{
|
||||||
|
cxx11_allocator tmp(*this);
|
||||||
|
++tmp.selected_;
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename U> struct rebind {
|
||||||
|
typedef cxx11_allocator<U, Flags> other;
|
||||||
|
};
|
||||||
|
|
||||||
|
explicit cxx11_allocator(int t = 0)
|
||||||
|
: cxx11_allocator_base<T>(t)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename Y> cxx11_allocator(
|
||||||
|
cxx11_allocator<Y, Flags> const& x)
|
||||||
|
: cxx11_allocator_base<T>(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
cxx11_allocator(cxx11_allocator const& x)
|
||||||
|
: cxx11_allocator_base<T>(x)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// When not propagating swap, allocators are always equal
|
||||||
|
// to avoid undefined behaviour.
|
||||||
|
bool operator==(cxx11_allocator const& x) const
|
||||||
|
{
|
||||||
|
return force_equal_allocator_value || (this->tag_ == x.tag_);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool operator!=(cxx11_allocator const& x) const
|
||||||
|
{
|
||||||
|
return !(*this == x);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename T, typename Flags>
|
||||||
|
bool equivalent_impl(
|
||||||
|
cxx11_allocator<T, Flags> const& x,
|
||||||
|
cxx11_allocator<T, Flags> const& y,
|
||||||
|
test::derived_type)
|
||||||
|
{
|
||||||
|
return x.tag_ == y.tag_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T, typename Flags>
|
||||||
|
int selected_count(cxx11_allocator<T, Flags> const& x)
|
||||||
|
{
|
||||||
|
return x.selected_;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
@ -34,6 +34,16 @@ namespace exception
|
|||||||
template <class T> class allocator;
|
template <class T> class allocator;
|
||||||
object generate(object const*);
|
object generate(object const*);
|
||||||
|
|
||||||
|
struct true_type
|
||||||
|
{
|
||||||
|
enum { value = true };
|
||||||
|
};
|
||||||
|
|
||||||
|
struct false_type
|
||||||
|
{
|
||||||
|
enum { value = false };
|
||||||
|
};
|
||||||
|
|
||||||
class object
|
class object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -340,15 +350,15 @@ namespace exception
|
|||||||
}
|
}
|
||||||
|
|
||||||
void construct(pointer p, T const& t) {
|
void construct(pointer p, T const& t) {
|
||||||
UNORDERED_SCOPE(allocator::construct(pointer, T)) {
|
UNORDERED_SCOPE(allocator::construct(T*, T)) {
|
||||||
UNORDERED_EPOINT("Mock allocator construct function.");
|
UNORDERED_EPOINT("Mock allocator construct function.");
|
||||||
new(p) T(t);
|
new(p) T(t);
|
||||||
}
|
}
|
||||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
template<class... Args> void construct(T* p, Args&&... args) {
|
||||||
UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
|
UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
|
||||||
UNORDERED_EPOINT("Mock allocator construct function.");
|
UNORDERED_EPOINT("Mock allocator construct function.");
|
||||||
new(p) T(std::forward<Args>(args)...);
|
new(p) T(std::forward<Args>(args)...);
|
||||||
@ -357,7 +367,7 @@ namespace exception
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void destroy(pointer p) {
|
void destroy(T* p) {
|
||||||
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||||
p->~T();
|
p->~T();
|
||||||
}
|
}
|
||||||
@ -368,6 +378,10 @@ namespace exception
|
|||||||
}
|
}
|
||||||
return (std::numeric_limits<std::size_t>::max)();
|
return (std::numeric_limits<std::size_t>::max)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
typedef true_type propagate_on_container_copy_assignment;
|
||||||
|
typedef true_type propagate_on_container_move_assignment;
|
||||||
|
typedef true_type propagate_on_container_swap;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
|
#define BOOST_UNORDERED_OBJECTS_MINIMAL_HEADER
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <boost/move/move.hpp>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#if defined(BOOST_MSVC)
|
#if defined(BOOST_MSVC)
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
@ -21,6 +23,7 @@ namespace test
|
|||||||
{
|
{
|
||||||
namespace minimal
|
namespace minimal
|
||||||
{
|
{
|
||||||
|
class destructible;
|
||||||
class copy_constructible;
|
class copy_constructible;
|
||||||
class copy_constructible_equality_comparable;
|
class copy_constructible_equality_comparable;
|
||||||
class default_copy_constructible;
|
class default_copy_constructible;
|
||||||
@ -33,11 +36,27 @@ namespace minimal
|
|||||||
template <class T> class ptr;
|
template <class T> class ptr;
|
||||||
template <class T> class const_ptr;
|
template <class T> class const_ptr;
|
||||||
template <class T> class allocator;
|
template <class T> class allocator;
|
||||||
|
template <class T> class cxx11_allocator;
|
||||||
|
|
||||||
|
struct constructor_param
|
||||||
|
{
|
||||||
|
operator int() const { return 0; }
|
||||||
|
};
|
||||||
|
|
||||||
|
class destructible
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
destructible(constructor_param const&) {}
|
||||||
|
~destructible() {}
|
||||||
|
private:
|
||||||
|
destructible(destructible const&);
|
||||||
|
destructible& operator=(destructible const&);
|
||||||
|
};
|
||||||
|
|
||||||
class copy_constructible
|
class copy_constructible
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static copy_constructible create() { return copy_constructible(); }
|
copy_constructible(constructor_param const&) {}
|
||||||
copy_constructible(copy_constructible const&) {}
|
copy_constructible(copy_constructible const&) {}
|
||||||
~copy_constructible() {}
|
~copy_constructible() {}
|
||||||
private:
|
private:
|
||||||
@ -48,9 +67,7 @@ namespace minimal
|
|||||||
class copy_constructible_equality_comparable
|
class copy_constructible_equality_comparable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static copy_constructible_equality_comparable create() {
|
copy_constructible_equality_comparable(constructor_param const&) {}
|
||||||
return copy_constructible_equality_comparable();
|
|
||||||
}
|
|
||||||
|
|
||||||
copy_constructible_equality_comparable(
|
copy_constructible_equality_comparable(
|
||||||
copy_constructible_equality_comparable const&)
|
copy_constructible_equality_comparable const&)
|
||||||
@ -85,10 +102,7 @@ namespace minimal
|
|||||||
class default_copy_constructible
|
class default_copy_constructible
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static default_copy_constructible create()
|
default_copy_constructible(constructor_param const&) {}
|
||||||
{
|
|
||||||
return default_copy_constructible();
|
|
||||||
}
|
|
||||||
|
|
||||||
default_copy_constructible()
|
default_copy_constructible()
|
||||||
{
|
{
|
||||||
@ -105,13 +119,14 @@ namespace minimal
|
|||||||
private:
|
private:
|
||||||
default_copy_constructible& operator=(
|
default_copy_constructible& operator=(
|
||||||
default_copy_constructible const&);
|
default_copy_constructible const&);
|
||||||
ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
ampersand_operator_used operator&() const {
|
||||||
|
return ampersand_operator_used(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
class assignable
|
class assignable
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static assignable create() { return assignable(); }
|
assignable(constructor_param const&) {}
|
||||||
assignable(assignable const&) {}
|
assignable(assignable const&) {}
|
||||||
assignable& operator=(assignable const&) { return *this; }
|
assignable& operator=(assignable const&) { return *this; }
|
||||||
~assignable() {}
|
~assignable() {}
|
||||||
@ -122,11 +137,43 @@ namespace minimal
|
|||||||
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
//ampersand_operator_used operator&() const { return ampersand_operator_used(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct movable_init {};
|
||||||
|
|
||||||
|
class movable1
|
||||||
|
{
|
||||||
|
BOOST_MOVABLE_BUT_NOT_COPYABLE(movable1)
|
||||||
|
|
||||||
|
public:
|
||||||
|
movable1(constructor_param const&) {}
|
||||||
|
movable1() {}
|
||||||
|
explicit movable1(movable_init) {}
|
||||||
|
movable1(BOOST_RV_REF(movable1)) {}
|
||||||
|
movable1& operator=(BOOST_RV_REF(movable1));
|
||||||
|
~movable1() {}
|
||||||
|
};
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||||
|
class movable2
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
movable2(constructor_param const&) {}
|
||||||
|
explicit movable2(movable_init) {}
|
||||||
|
movable2(movable2&&) {}
|
||||||
|
~movable2() {}
|
||||||
|
private:
|
||||||
|
movable2() {}
|
||||||
|
movable2(movable2 const&);
|
||||||
|
movable2& operator=(movable2 const&);
|
||||||
|
};
|
||||||
|
#else
|
||||||
|
typedef movable1 movable2;
|
||||||
|
#endif
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class hash
|
class hash
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static hash create() { return hash<T>(); }
|
hash(constructor_param const&) {}
|
||||||
hash() {}
|
hash() {}
|
||||||
hash(hash const&) {}
|
hash(hash const&) {}
|
||||||
hash& operator=(hash const&) { return *this; }
|
hash& operator=(hash const&) { return *this; }
|
||||||
@ -141,7 +188,7 @@ namespace minimal
|
|||||||
class equal_to
|
class equal_to
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static equal_to create() { return equal_to<T>(); }
|
equal_to(constructor_param const&) {}
|
||||||
equal_to() {}
|
equal_to() {}
|
||||||
equal_to(equal_to const&) {}
|
equal_to(equal_to const&) {}
|
||||||
equal_to& operator=(equal_to const&) { return *this; }
|
equal_to& operator=(equal_to const&) { return *this; }
|
||||||
@ -278,15 +325,15 @@ namespace minimal
|
|||||||
::operator delete((void*) p.ptr_);
|
::operator delete((void*) p.ptr_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void construct(pointer p, T const& t) { new((void*)p.ptr_) T(t); }
|
void construct(T* p, T const& t) { new((void*)p) T(t); }
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
template<class... Args> void construct(T* p, Args&&... args) {
|
||||||
new((void*)p.ptr_) T(std::forward<Args>(args)...);
|
new((void*)p) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void destroy(pointer p) { ((T*)p.ptr_)->~T(); }
|
void destroy(T* p) { p->~T(); }
|
||||||
|
|
||||||
size_type max_size() const { return 1000; }
|
size_type max_size() const { return 1000; }
|
||||||
|
|
||||||
@ -316,6 +363,69 @@ namespace minimal
|
|||||||
void swap(allocator<T>&, allocator<T>&)
|
void swap(allocator<T>&, allocator<T>&)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// C++11 allocator
|
||||||
|
//
|
||||||
|
// Not a fully minimal C++11 allocator, just what I support. Hopefully will
|
||||||
|
// cut down further in the future.
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
class cxx11_allocator
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef T value_type;
|
||||||
|
template <class U> struct rebind { typedef cxx11_allocator<U> other; };
|
||||||
|
|
||||||
|
cxx11_allocator() {}
|
||||||
|
template <class Y> cxx11_allocator(cxx11_allocator<Y> const&) {}
|
||||||
|
cxx11_allocator(cxx11_allocator const&) {}
|
||||||
|
~cxx11_allocator() {}
|
||||||
|
|
||||||
|
T* address(T& r) { return &r; }
|
||||||
|
T const* address(T const& r) { return &r; }
|
||||||
|
|
||||||
|
T* allocate(std::size_t n) {
|
||||||
|
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Y>
|
||||||
|
T* allocate(std::size_t n, const_ptr<Y> u) {
|
||||||
|
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T* p, std::size_t) {
|
||||||
|
::operator delete((void*) p);
|
||||||
|
}
|
||||||
|
|
||||||
|
void construct(T* p, T const& t) { new((void*)p) T(t); }
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
|
template<class... Args> void construct(T* p, Args&&... args) {
|
||||||
|
new((void*)p) T(std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void destroy(T* p) { p->~T(); }
|
||||||
|
|
||||||
|
std::size_t max_size() const { return 1000u; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline bool operator==(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
inline bool operator!=(cxx11_allocator<T> const&, cxx11_allocator<T> const&)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void swap(cxx11_allocator<T>&, cxx11_allocator<T>&)
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -9,11 +9,9 @@
|
|||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/limits.hpp>
|
#include <boost/limits.hpp>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iostream>
|
|
||||||
#include "../helpers/fwd.hpp"
|
#include "../helpers/fwd.hpp"
|
||||||
#include "../helpers/count.hpp"
|
#include "../helpers/count.hpp"
|
||||||
#include "../helpers/memory.hpp"
|
#include "../helpers/memory.hpp"
|
||||||
#include <map>
|
|
||||||
|
|
||||||
namespace test
|
namespace test
|
||||||
{
|
{
|
||||||
@ -27,7 +25,7 @@ namespace test
|
|||||||
template <class T> class allocator;
|
template <class T> class allocator;
|
||||||
object generate(object const*);
|
object generate(object const*);
|
||||||
implicitly_convertible generate(implicitly_convertible const*);
|
implicitly_convertible generate(implicitly_convertible const*);
|
||||||
|
|
||||||
class object : globally_counted_object
|
class object : globally_counted_object
|
||||||
{
|
{
|
||||||
friend class hash;
|
friend class hash;
|
||||||
@ -185,18 +183,6 @@ namespace test
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
namespace detail
|
|
||||||
{
|
|
||||||
// This won't be a problem as I'm only using a single compile unit
|
|
||||||
// in each test (this is actually require by the minimal test
|
|
||||||
// framework).
|
|
||||||
//
|
|
||||||
// boostinspect:nounnamed
|
|
||||||
namespace {
|
|
||||||
test::detail::memory_tracker<std::allocator<int> > tracker;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
class allocator
|
class allocator
|
||||||
{
|
{
|
||||||
@ -268,19 +254,19 @@ namespace test
|
|||||||
::operator delete((void*) p);
|
::operator delete((void*) p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void construct(pointer p, T const& t) {
|
void construct(T* p, T const& t) {
|
||||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||||
new(p) T(t);
|
new(p) T(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(BOOST_UNORDERED_STD_FORWARD)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template<class... Args> void construct(pointer p, Args&&... args) {
|
template<class... Args> void construct(T* p, Args&&... args) {
|
||||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||||
new(p) T(std::forward<Args>(args)...);
|
new(p) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void destroy(pointer p) {
|
void destroy(T* p) {
|
||||||
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||||
p->~T();
|
p->~T();
|
||||||
}
|
}
|
||||||
@ -298,6 +284,13 @@ namespace test
|
|||||||
{
|
{
|
||||||
return tag_ != x.tag_;
|
return tag_ != x.tag_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum {
|
||||||
|
is_select_on_copy = false,
|
||||||
|
is_propagate_on_swap = false,
|
||||||
|
is_propagate_on_assign = false,
|
||||||
|
is_propagate_on_move = false
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
|
@ -43,5 +43,5 @@ test-suite unordered
|
|||||||
[ run load_factor_tests.cpp ]
|
[ run load_factor_tests.cpp ]
|
||||||
[ run rehash_tests.cpp ]
|
[ run rehash_tests.cpp ]
|
||||||
[ run equality_tests.cpp ]
|
[ run equality_tests.cpp ]
|
||||||
[ run swap_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ]
|
[ run swap_tests.cpp ]
|
||||||
;
|
;
|
||||||
|
@ -9,12 +9,17 @@
|
|||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include "../helpers/test.hpp"
|
#include "../helpers/test.hpp"
|
||||||
#include "../objects/test.hpp"
|
#include "../objects/test.hpp"
|
||||||
|
#include "../objects/cxx11_allocator.hpp"
|
||||||
#include "../helpers/random_values.hpp"
|
#include "../helpers/random_values.hpp"
|
||||||
#include "../helpers/tracker.hpp"
|
#include "../helpers/tracker.hpp"
|
||||||
#include "../helpers/equivalent.hpp"
|
#include "../helpers/equivalent.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(disable:4127) // conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace assign_tests {
|
namespace assign_tests {
|
||||||
|
|
||||||
test::seed_t seed(96785);
|
test::seed_t seed(96785);
|
||||||
@ -28,6 +33,8 @@ void assign_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"assign_tests1.1\n";
|
std::cerr<<"assign_tests1.1\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x;
|
T x;
|
||||||
x = x;
|
x = x;
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
@ -37,6 +44,8 @@ void assign_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"assign_tests1.2\n";
|
std::cerr<<"assign_tests1.2\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
T x(v.begin(), v.end());
|
T x(v.begin(), v.end());
|
||||||
|
|
||||||
@ -64,9 +73,13 @@ void assign_tests2(T*,
|
|||||||
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
|
BOOST_DEDUCED_TYPENAME T::key_equal eq2(2);
|
||||||
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
||||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||||
|
|
||||||
std::cerr<<"assign_tests2.1\n";
|
std::cerr<<"assign_tests2.1\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||||
T x2(0, hf2, eq2);
|
T x2(0, hf2, eq2);
|
||||||
@ -78,13 +91,22 @@ void assign_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"assign_tests2.2\n";
|
std::cerr<<"assign_tests2.2\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v1(100, generator), v2(100, generator);
|
test::random_values<T> v1(100, generator), v2(100, generator);
|
||||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||||
x2 = x1;
|
x2 = x1;
|
||||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
if (allocator_type::is_propagate_on_assign) {
|
||||||
|
BOOST_TEST(test::equivalent(x2.get_allocator(), al1));
|
||||||
|
BOOST_TEST(!test::equivalent(x2.get_allocator(), al2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||||
|
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||||
|
}
|
||||||
test::check_container(x2, v1);
|
test::check_container(x2, v1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -102,16 +124,69 @@ boost::unordered_multimap<test::object, test::object,
|
|||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_multimap;
|
test::allocator<test::object> >* test_multimap;
|
||||||
|
|
||||||
|
boost::unordered_set<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||||
|
test_set_prop_assign;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||||
|
test_multiset_prop_assign;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||||
|
test_map_prop_assign;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||||
|
test_multimap_prop_assign;
|
||||||
|
|
||||||
|
boost::unordered_set<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||||
|
test_set_no_prop_assign;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||||
|
test_multiset_no_prop_assign;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||||
|
test_map_no_prop_assign;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||||
|
test_multimap_no_prop_assign;
|
||||||
|
|
||||||
using test::default_generator;
|
using test::default_generator;
|
||||||
using test::generate_collisions;
|
using test::generate_collisions;
|
||||||
|
|
||||||
UNORDERED_TEST(assign_tests1,
|
template <typename T>
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
bool is_propagate(T*)
|
||||||
|
{
|
||||||
|
return T::allocator_type::is_propagate_on_assign;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST(check_traits)
|
||||||
|
{
|
||||||
|
BOOST_TEST(!is_propagate(test_set));
|
||||||
|
BOOST_TEST(is_propagate(test_set_prop_assign));
|
||||||
|
BOOST_TEST(!is_propagate(test_set_no_prop_assign));
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_TEST(assign_tests1, (
|
||||||
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
|
||||||
|
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
|
||||||
|
)
|
||||||
((default_generator)(generate_collisions))
|
((default_generator)(generate_collisions))
|
||||||
)
|
)
|
||||||
|
|
||||||
UNORDERED_TEST(assign_tests2,
|
UNORDERED_TEST(assign_tests2, (
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_assign)(test_multiset_prop_assign)(test_map_prop_assign)(test_multimap_prop_assign)
|
||||||
|
(test_set_no_prop_assign)(test_multiset_no_prop_assign)(test_map_no_prop_assign)(test_multimap_no_prop_assign)
|
||||||
|
)
|
||||||
((default_generator)(generate_collisions))
|
((default_generator)(generate_collisions))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -25,6 +25,8 @@ test::seed_t seed(54635);
|
|||||||
template <class X>
|
template <class X>
|
||||||
void tests(X* = 0, test::random_generator generator = test::default_generator)
|
void tests(X* = 0, test::random_generator generator = test::default_generator)
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
|
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
|
typedef BOOST_DEDUCED_TYPENAME X::const_local_iterator const_local_iterator;
|
||||||
test::random_values<X> v(1000, generator);
|
test::random_values<X> v(1000, generator);
|
||||||
|
@ -17,6 +17,19 @@
|
|||||||
|
|
||||||
// Explicit instantiation to catch compile-time errors
|
// Explicit instantiation to catch compile-time errors
|
||||||
|
|
||||||
|
template class boost::unordered_map<
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
boost::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
test::minimal::allocator<std::pair<int const, int> > >;
|
||||||
|
template class boost::unordered_multimap<
|
||||||
|
int,
|
||||||
|
int,
|
||||||
|
boost::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
test::minimal::allocator<std::pair<int const, int> > >;
|
||||||
|
|
||||||
template class boost::unordered_map<
|
template class boost::unordered_map<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
test::minimal::default_copy_constructible,
|
test::minimal::default_copy_constructible,
|
||||||
@ -32,16 +45,21 @@ template class boost::unordered_multimap<
|
|||||||
|
|
||||||
UNORDERED_AUTO_TEST(test0)
|
UNORDERED_AUTO_TEST(test0)
|
||||||
{
|
{
|
||||||
|
test::minimal::constructor_param x;
|
||||||
|
|
||||||
typedef std::pair<test::minimal::assignable const,
|
typedef std::pair<test::minimal::assignable const,
|
||||||
test::minimal::copy_constructible> value_type;
|
test::minimal::copy_constructible> value_type;
|
||||||
value_type value(
|
value_type value(x, x);
|
||||||
test::minimal::assignable::create(),
|
|
||||||
test::minimal::copy_constructible::create());
|
|
||||||
|
|
||||||
std::cout<<"Test unordered_map.\n";
|
std::cout<<"Test unordered_map.\n";
|
||||||
|
|
||||||
boost::unordered_map<int, int> int_map;
|
boost::unordered_map<int, int> int_map;
|
||||||
|
|
||||||
|
boost::unordered_map<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||||
|
> int_map2;
|
||||||
|
|
||||||
boost::unordered_map<
|
boost::unordered_map<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
test::minimal::copy_constructible,
|
test::minimal::copy_constructible,
|
||||||
@ -50,12 +68,18 @@ UNORDERED_AUTO_TEST(test0)
|
|||||||
test::minimal::allocator<value_type> > map;
|
test::minimal::allocator<value_type> > map;
|
||||||
|
|
||||||
container_test(int_map, std::pair<int const, int>(0, 0));
|
container_test(int_map, std::pair<int const, int>(0, 0));
|
||||||
|
container_test(int_map2, std::pair<int const, int>(0, 0));
|
||||||
container_test(map, value);
|
container_test(map, value);
|
||||||
|
|
||||||
std::cout<<"Test unordered_multimap.\n";
|
std::cout<<"Test unordered_multimap.\n";
|
||||||
|
|
||||||
boost::unordered_multimap<int, int> int_multimap;
|
boost::unordered_multimap<int, int> int_multimap;
|
||||||
|
|
||||||
|
boost::unordered_multimap<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||||
|
> int_multimap2;
|
||||||
|
|
||||||
boost::unordered_multimap<
|
boost::unordered_multimap<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
test::minimal::copy_constructible,
|
test::minimal::copy_constructible,
|
||||||
@ -64,35 +88,49 @@ UNORDERED_AUTO_TEST(test0)
|
|||||||
test::minimal::allocator<value_type> > multimap;
|
test::minimal::allocator<value_type> > multimap;
|
||||||
|
|
||||||
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
||||||
|
container_test(int_multimap2, std::pair<int const, int>(0, 0));
|
||||||
container_test(multimap, value);
|
container_test(multimap, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(equality_tests) {
|
UNORDERED_AUTO_TEST(equality_tests) {
|
||||||
typedef std::pair<test::minimal::assignable const,
|
typedef std::pair<
|
||||||
|
test::minimal::copy_constructible_equality_comparable const,
|
||||||
test::minimal::copy_constructible> value_type;
|
test::minimal::copy_constructible> value_type;
|
||||||
|
|
||||||
boost::unordered_map<int, int> int_map;
|
boost::unordered_map<int, int> int_map;
|
||||||
|
|
||||||
|
boost::unordered_map<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||||
|
> int_map2;
|
||||||
|
|
||||||
boost::unordered_map<
|
boost::unordered_map<
|
||||||
test::minimal::assignable,
|
|
||||||
test::minimal::copy_constructible_equality_comparable,
|
test::minimal::copy_constructible_equality_comparable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::copy_constructible_equality_comparable,
|
||||||
test::minimal::equal_to<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||||
|
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||||
test::minimal::allocator<value_type> > map;
|
test::minimal::allocator<value_type> > map;
|
||||||
|
|
||||||
equality_test(int_map);
|
equality_test(int_map);
|
||||||
|
equality_test(int_map2);
|
||||||
equality_test(map);
|
equality_test(map);
|
||||||
|
|
||||||
boost::unordered_multimap<int, int> int_multimap;
|
boost::unordered_multimap<int, int> int_multimap;
|
||||||
|
|
||||||
|
boost::unordered_multimap<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||||
|
> int_multimap2;
|
||||||
|
|
||||||
boost::unordered_multimap<
|
boost::unordered_multimap<
|
||||||
test::minimal::assignable,
|
|
||||||
test::minimal::copy_constructible_equality_comparable,
|
test::minimal::copy_constructible_equality_comparable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::copy_constructible_equality_comparable,
|
||||||
test::minimal::equal_to<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||||
|
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||||
test::minimal::allocator<value_type> > multimap;
|
test::minimal::allocator<value_type> > multimap;
|
||||||
|
|
||||||
equality_test(int_multimap);
|
equality_test(int_multimap);
|
||||||
|
equality_test(int_multimap2);
|
||||||
equality_test(multimap);
|
equality_test(multimap);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -106,30 +144,47 @@ UNORDERED_AUTO_TEST(test1) {
|
|||||||
|
|
||||||
boost::unordered_map<int, int> map;
|
boost::unordered_map<int, int> map;
|
||||||
|
|
||||||
|
boost::unordered_map<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||||
|
> map2;
|
||||||
|
|
||||||
unordered_unique_test(map, map_value);
|
unordered_unique_test(map, map_value);
|
||||||
unordered_map_test(map, value, value);
|
unordered_map_test(map, value, value);
|
||||||
unordered_test(map, value, map_value, hash, equal_to);
|
unordered_copyable_test(map, value, map_value, hash, equal_to);
|
||||||
unordered_map_functions(map, value, value);
|
unordered_map_functions(map, value, value);
|
||||||
|
|
||||||
|
unordered_unique_test(map2, map_value);
|
||||||
|
unordered_map_test(map2, value, value);
|
||||||
|
unordered_copyable_test(map2, value, map_value, hash, equal_to);
|
||||||
|
unordered_map_functions(map2, value, value);
|
||||||
|
|
||||||
std::cout<<"Test unordered_multimap.\n";
|
std::cout<<"Test unordered_multimap.\n";
|
||||||
|
|
||||||
boost::unordered_multimap<int, int> multimap;
|
boost::unordered_multimap<int, int> multimap;
|
||||||
|
|
||||||
|
boost::unordered_multimap<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<std::pair<int const, int> >
|
||||||
|
> multimap2;
|
||||||
|
|
||||||
unordered_equivalent_test(multimap, map_value);
|
unordered_equivalent_test(multimap, map_value);
|
||||||
unordered_map_test(multimap, value, value);
|
unordered_map_test(multimap, value, value);
|
||||||
unordered_test(multimap, value, map_value, hash, equal_to);
|
unordered_copyable_test(multimap, value, map_value, hash, equal_to);
|
||||||
|
|
||||||
|
unordered_equivalent_test(multimap2, map_value);
|
||||||
|
unordered_map_test(multimap2, value, value);
|
||||||
|
unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(test2)
|
UNORDERED_AUTO_TEST(test2)
|
||||||
{
|
{
|
||||||
test::minimal::assignable assignable
|
test::minimal::constructor_param x;
|
||||||
= test::minimal::assignable::create();
|
|
||||||
test::minimal::copy_constructible copy_constructible
|
test::minimal::assignable assignable(x);
|
||||||
= test::minimal::copy_constructible::create();
|
test::minimal::copy_constructible copy_constructible(x);
|
||||||
test::minimal::hash<test::minimal::assignable> hash
|
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||||
= test::minimal::hash<test::minimal::assignable>::create();
|
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||||
test::minimal::equal_to<test::minimal::assignable> equal_to
|
|
||||||
= test::minimal::equal_to<test::minimal::assignable>::create();
|
|
||||||
|
|
||||||
typedef std::pair<test::minimal::assignable const,
|
typedef std::pair<test::minimal::assignable const,
|
||||||
test::minimal::copy_constructible> map_value_type;
|
test::minimal::copy_constructible> map_value_type;
|
||||||
@ -146,8 +201,7 @@ UNORDERED_AUTO_TEST(test2)
|
|||||||
|
|
||||||
unordered_unique_test(map, map_value);
|
unordered_unique_test(map, map_value);
|
||||||
unordered_map_test(map, assignable, copy_constructible);
|
unordered_map_test(map, assignable, copy_constructible);
|
||||||
unordered_test(map, assignable, map_value, hash, equal_to);
|
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||||
|
|
||||||
|
|
||||||
boost::unordered_map<
|
boost::unordered_map<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
@ -171,7 +225,7 @@ UNORDERED_AUTO_TEST(test2)
|
|||||||
|
|
||||||
unordered_equivalent_test(multimap, map_value);
|
unordered_equivalent_test(multimap, map_value);
|
||||||
unordered_map_test(multimap, assignable, copy_constructible);
|
unordered_map_test(multimap, assignable, copy_constructible);
|
||||||
unordered_test(multimap, assignable, map_value, hash, equal_to);
|
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -16,7 +16,18 @@
|
|||||||
#include "./compile_tests.hpp"
|
#include "./compile_tests.hpp"
|
||||||
|
|
||||||
// Explicit instantiation to catch compile-time errors
|
// Explicit instantiation to catch compile-time errors
|
||||||
|
/*
|
||||||
|
template class boost::unordered_set<
|
||||||
|
int,
|
||||||
|
boost::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
test::minimal::allocator<int> >;
|
||||||
|
template class boost::unordered_multiset<
|
||||||
|
int,
|
||||||
|
boost::hash<int>,
|
||||||
|
std::equal_to<int>,
|
||||||
|
test::minimal::allocator<int> >;
|
||||||
|
*/
|
||||||
template class boost::unordered_set<
|
template class boost::unordered_set<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::assignable>,
|
||||||
@ -30,10 +41,19 @@ template class boost::unordered_multiset<
|
|||||||
|
|
||||||
UNORDERED_AUTO_TEST(test0)
|
UNORDERED_AUTO_TEST(test0)
|
||||||
{
|
{
|
||||||
test::minimal::assignable assignable = test::minimal::assignable::create();
|
test::minimal::constructor_param x;
|
||||||
|
|
||||||
|
test::minimal::assignable assignable(x);
|
||||||
|
|
||||||
std::cout<<"Test unordered_set.\n";
|
std::cout<<"Test unordered_set.\n";
|
||||||
|
|
||||||
boost::unordered_set<int> int_set;
|
boost::unordered_set<int> int_set;
|
||||||
|
|
||||||
|
boost::unordered_set<int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<int>
|
||||||
|
> int_set2;
|
||||||
|
|
||||||
boost::unordered_set<
|
boost::unordered_set<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::assignable>,
|
||||||
@ -41,10 +61,18 @@ UNORDERED_AUTO_TEST(test0)
|
|||||||
test::minimal::allocator<test::minimal::assignable> > set;
|
test::minimal::allocator<test::minimal::assignable> > set;
|
||||||
|
|
||||||
container_test(int_set, 0);
|
container_test(int_set, 0);
|
||||||
|
container_test(int_set2, 0);
|
||||||
container_test(set, assignable);
|
container_test(set, assignable);
|
||||||
|
|
||||||
std::cout<<"Test unordered_multiset.\n";
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
|
||||||
boost::unordered_multiset<int> int_multiset;
|
boost::unordered_multiset<int> int_multiset;
|
||||||
|
|
||||||
|
boost::unordered_multiset<int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<int>
|
||||||
|
> int_multiset2;
|
||||||
|
|
||||||
boost::unordered_multiset<
|
boost::unordered_multiset<
|
||||||
test::minimal::assignable,
|
test::minimal::assignable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::assignable>,
|
||||||
@ -52,32 +80,45 @@ UNORDERED_AUTO_TEST(test0)
|
|||||||
test::minimal::allocator<test::minimal::assignable> > multiset;
|
test::minimal::allocator<test::minimal::assignable> > multiset;
|
||||||
|
|
||||||
container_test(int_multiset, 0);
|
container_test(int_multiset, 0);
|
||||||
|
container_test(int_multiset2, 0);
|
||||||
container_test(multiset, assignable);
|
container_test(multiset, assignable);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(equality_tests) {
|
UNORDERED_AUTO_TEST(equality_tests) {
|
||||||
typedef test::minimal::assignable value_type;
|
typedef test::minimal::copy_constructible_equality_comparable value_type;
|
||||||
|
|
||||||
boost::unordered_set<int> int_set;
|
boost::unordered_set<int> int_set;
|
||||||
|
|
||||||
|
boost::unordered_set<int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<int>
|
||||||
|
> int_set2;
|
||||||
|
|
||||||
boost::unordered_set<
|
boost::unordered_set<
|
||||||
test::minimal::assignable,
|
test::minimal::copy_constructible_equality_comparable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||||
test::minimal::equal_to<test::minimal::assignable>,
|
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||||
test::minimal::allocator<value_type> > set;
|
test::minimal::allocator<value_type> > set;
|
||||||
|
|
||||||
equality_test(int_set);
|
equality_test(int_set);
|
||||||
|
equality_test(int_set2);
|
||||||
equality_test(set);
|
equality_test(set);
|
||||||
|
|
||||||
boost::unordered_multiset<int> int_multiset;
|
boost::unordered_multiset<int> int_multiset;
|
||||||
|
|
||||||
|
boost::unordered_multiset<int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<int>
|
||||||
|
> int_multiset2;
|
||||||
|
|
||||||
boost::unordered_multiset<
|
boost::unordered_multiset<
|
||||||
test::minimal::assignable,
|
test::minimal::copy_constructible_equality_comparable,
|
||||||
test::minimal::hash<test::minimal::assignable>,
|
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||||
test::minimal::equal_to<test::minimal::assignable>,
|
test::minimal::equal_to<test::minimal::copy_constructible_equality_comparable>,
|
||||||
test::minimal::allocator<value_type> > multiset;
|
test::minimal::allocator<value_type> > multiset;
|
||||||
|
|
||||||
equality_test(int_multiset);
|
equality_test(int_multiset);
|
||||||
|
equality_test(int_multiset2);
|
||||||
equality_test(multiset);
|
equality_test(multiset);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -91,29 +132,45 @@ UNORDERED_AUTO_TEST(test1)
|
|||||||
|
|
||||||
boost::unordered_set<int> set;
|
boost::unordered_set<int> set;
|
||||||
|
|
||||||
|
boost::unordered_set<int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<int>
|
||||||
|
> set2;
|
||||||
|
|
||||||
unordered_unique_test(set, value);
|
unordered_unique_test(set, value);
|
||||||
unordered_set_test(set, value);
|
unordered_set_test(set, value);
|
||||||
unordered_test(set, value, value, hash, equal_to);
|
unordered_copyable_test(set, value, value, hash, equal_to);
|
||||||
|
|
||||||
|
unordered_unique_test(set2, value);
|
||||||
|
unordered_set_test(set2, value);
|
||||||
|
unordered_copyable_test(set2, value, value, hash, equal_to);
|
||||||
|
|
||||||
std::cout<<"Test unordered_multiset.\n";
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
|
||||||
boost::unordered_multiset<int> multiset;
|
boost::unordered_multiset<int> multiset;
|
||||||
|
|
||||||
|
boost::unordered_multiset<int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
test::minimal::cxx11_allocator<int>
|
||||||
|
> multiset2;
|
||||||
|
|
||||||
unordered_equivalent_test(multiset, value);
|
unordered_equivalent_test(multiset, value);
|
||||||
unordered_set_test(multiset, value);
|
unordered_set_test(multiset, value);
|
||||||
unordered_test(multiset, value, value, hash, equal_to);
|
unordered_copyable_test(multiset, value, value, hash, equal_to);
|
||||||
|
|
||||||
|
unordered_equivalent_test(multiset2, value);
|
||||||
|
unordered_set_test(multiset2, value);
|
||||||
|
unordered_copyable_test(multiset2, value, value, hash, equal_to);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(test2)
|
UNORDERED_AUTO_TEST(test2)
|
||||||
{
|
{
|
||||||
test::minimal::assignable assignable
|
test::minimal::constructor_param x;
|
||||||
= test::minimal::assignable::create();
|
|
||||||
test::minimal::copy_constructible copy_constructible
|
test::minimal::assignable assignable(x);
|
||||||
= test::minimal::copy_constructible::create();
|
test::minimal::copy_constructible copy_constructible(x);
|
||||||
test::minimal::hash<test::minimal::assignable> hash
|
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||||
= test::minimal::hash<test::minimal::assignable>::create();
|
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||||
test::minimal::equal_to<test::minimal::assignable> equal_to
|
|
||||||
= test::minimal::equal_to<test::minimal::assignable>::create();
|
|
||||||
|
|
||||||
std::cout<<"Test unordered_set.\n";
|
std::cout<<"Test unordered_set.\n";
|
||||||
|
|
||||||
@ -125,7 +182,7 @@ UNORDERED_AUTO_TEST(test2)
|
|||||||
|
|
||||||
unordered_unique_test(set, assignable);
|
unordered_unique_test(set, assignable);
|
||||||
unordered_set_test(set, assignable);
|
unordered_set_test(set, assignable);
|
||||||
unordered_test(set, assignable, assignable, hash, equal_to);
|
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
|
||||||
|
|
||||||
std::cout<<"Test unordered_multiset.\n";
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
|
||||||
@ -137,7 +194,100 @@ UNORDERED_AUTO_TEST(test2)
|
|||||||
|
|
||||||
unordered_equivalent_test(multiset, assignable);
|
unordered_equivalent_test(multiset, assignable);
|
||||||
unordered_set_test(multiset, assignable);
|
unordered_set_test(multiset, assignable);
|
||||||
unordered_test(multiset, assignable, assignable, hash, equal_to);
|
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST(movable1_tests)
|
||||||
|
{
|
||||||
|
test::minimal::constructor_param x;
|
||||||
|
|
||||||
|
test::minimal::movable1 movable1(x);
|
||||||
|
test::minimal::hash<test::minimal::movable1> hash(x);
|
||||||
|
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_set.\n";
|
||||||
|
|
||||||
|
boost::unordered_set<
|
||||||
|
test::minimal::movable1,
|
||||||
|
test::minimal::hash<test::minimal::movable1>,
|
||||||
|
test::minimal::equal_to<test::minimal::movable1>,
|
||||||
|
test::minimal::allocator<test::minimal::movable1> > set;
|
||||||
|
|
||||||
|
//unordered_unique_test(set, movable1);
|
||||||
|
unordered_set_test(set, movable1);
|
||||||
|
unordered_movable_test(set, movable1, movable1, hash, equal_to);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
|
||||||
|
boost::unordered_multiset<
|
||||||
|
test::minimal::movable1,
|
||||||
|
test::minimal::hash<test::minimal::movable1>,
|
||||||
|
test::minimal::equal_to<test::minimal::movable1>,
|
||||||
|
test::minimal::allocator<test::minimal::movable1> > multiset;
|
||||||
|
|
||||||
|
//unordered_equivalent_test(multiset, movable1);
|
||||||
|
unordered_set_test(multiset, movable1);
|
||||||
|
unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST(movable2_tests)
|
||||||
|
{
|
||||||
|
test::minimal::constructor_param x;
|
||||||
|
|
||||||
|
test::minimal::movable2 movable2(x);
|
||||||
|
test::minimal::hash<test::minimal::movable2> hash(x);
|
||||||
|
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_set.\n";
|
||||||
|
|
||||||
|
boost::unordered_set<
|
||||||
|
test::minimal::movable2,
|
||||||
|
test::minimal::hash<test::minimal::movable2>,
|
||||||
|
test::minimal::equal_to<test::minimal::movable2>,
|
||||||
|
test::minimal::allocator<test::minimal::movable2> > set;
|
||||||
|
|
||||||
|
//unordered_unique_test(set, movable2);
|
||||||
|
unordered_set_test(set, movable2);
|
||||||
|
unordered_movable_test(set, movable2, movable2, hash, equal_to);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
|
||||||
|
boost::unordered_multiset<
|
||||||
|
test::minimal::movable2,
|
||||||
|
test::minimal::hash<test::minimal::movable2>,
|
||||||
|
test::minimal::equal_to<test::minimal::movable2>,
|
||||||
|
test::minimal::allocator<test::minimal::movable2> > multiset;
|
||||||
|
|
||||||
|
//unordered_equivalent_test(multiset, movable2);
|
||||||
|
unordered_set_test(multiset, movable2);
|
||||||
|
unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST(destructible_tests)
|
||||||
|
{
|
||||||
|
test::minimal::constructor_param x;
|
||||||
|
|
||||||
|
test::minimal::destructible destructible(x);
|
||||||
|
test::minimal::hash<test::minimal::destructible> hash(x);
|
||||||
|
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_set.\n";
|
||||||
|
|
||||||
|
boost::unordered_set<
|
||||||
|
test::minimal::destructible,
|
||||||
|
test::minimal::hash<test::minimal::destructible>,
|
||||||
|
test::minimal::equal_to<test::minimal::destructible> > set;
|
||||||
|
|
||||||
|
unordered_destructible_test(set);
|
||||||
|
|
||||||
|
std::cout<<"Test unordered_multiset.\n";
|
||||||
|
|
||||||
|
boost::unordered_multiset<
|
||||||
|
test::minimal::destructible,
|
||||||
|
test::minimal::hash<test::minimal::destructible>,
|
||||||
|
test::minimal::equal_to<test::minimal::destructible> > multiset;
|
||||||
|
|
||||||
|
unordered_destructible_test(multiset);
|
||||||
}
|
}
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -28,6 +28,7 @@ typedef long double comparison_type;
|
|||||||
|
|
||||||
template <class T> void sink(T const&) {}
|
template <class T> void sink(T const&) {}
|
||||||
template <class T> T rvalue(T const& v) { return v; }
|
template <class T> T rvalue(T const& v) { return v; }
|
||||||
|
template <class T> T rvalue_default() { return T(); }
|
||||||
|
|
||||||
template <class X, class T>
|
template <class X, class T>
|
||||||
void container_test(X& r, T const&)
|
void container_test(X& r, T const&)
|
||||||
@ -109,30 +110,15 @@ void container_test(X& r, T const&)
|
|||||||
BOOST_TEST(X().size() == 0);
|
BOOST_TEST(X().size() == 0);
|
||||||
|
|
||||||
X a,b;
|
X a,b;
|
||||||
|
X a_const;
|
||||||
|
|
||||||
sink(X(a));
|
sink(X(a));
|
||||||
X u2(a);
|
X u2(a);
|
||||||
X u3 = a;
|
X u3 = a;
|
||||||
|
|
||||||
X* ptr = new X();
|
|
||||||
X& a1 = *ptr;
|
|
||||||
(&a1)->~X();
|
|
||||||
|
|
||||||
X const a_const;
|
|
||||||
test::check_return_type<iterator>::equals(a.begin());
|
|
||||||
test::check_return_type<const_iterator>::equals(a_const.begin());
|
|
||||||
test::check_return_type<const_iterator>::equals(a.cbegin());
|
|
||||||
test::check_return_type<const_iterator>::equals(a_const.cbegin());
|
|
||||||
test::check_return_type<iterator>::equals(a.end());
|
|
||||||
test::check_return_type<const_iterator>::equals(a_const.end());
|
|
||||||
test::check_return_type<const_iterator>::equals(a.cend());
|
|
||||||
test::check_return_type<const_iterator>::equals(a_const.cend());
|
|
||||||
|
|
||||||
a.swap(b);
|
a.swap(b);
|
||||||
|
boost::swap(a, b);
|
||||||
test::check_return_type<X>::equals_ref(r = a);
|
test::check_return_type<X>::equals_ref(r = a);
|
||||||
test::check_return_type<size_type>::equals(a.size());
|
|
||||||
test::check_return_type<size_type>::equals(a.max_size());
|
|
||||||
test::check_return_type<bool>::convertible(a.empty());
|
|
||||||
|
|
||||||
// Allocator
|
// Allocator
|
||||||
|
|
||||||
@ -146,6 +132,51 @@ void container_test(X& r, T const&)
|
|||||||
sink(u3);
|
sink(u3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void unordered_destructible_test(X&)
|
||||||
|
{
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::size_type size_type;
|
||||||
|
|
||||||
|
X x1;
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||||
|
X x2(rvalue_default<X>());
|
||||||
|
X x3 = rvalue_default<X>();
|
||||||
|
// This can only be done if propagate_on_container_move_assignment::value
|
||||||
|
// is true.
|
||||||
|
// x2 = rvalue_default<X>();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
X* ptr = new X();
|
||||||
|
X& a1 = *ptr;
|
||||||
|
(&a1)->~X();
|
||||||
|
|
||||||
|
X a,b;
|
||||||
|
X const a_const;
|
||||||
|
test::check_return_type<iterator>::equals(a.begin());
|
||||||
|
test::check_return_type<const_iterator>::equals(a_const.begin());
|
||||||
|
test::check_return_type<const_iterator>::equals(a.cbegin());
|
||||||
|
test::check_return_type<const_iterator>::equals(a_const.cbegin());
|
||||||
|
test::check_return_type<iterator>::equals(a.end());
|
||||||
|
test::check_return_type<const_iterator>::equals(a_const.end());
|
||||||
|
test::check_return_type<const_iterator>::equals(a.cend());
|
||||||
|
test::check_return_type<const_iterator>::equals(a_const.cend());
|
||||||
|
|
||||||
|
a.swap(b);
|
||||||
|
boost::swap(a, b);
|
||||||
|
|
||||||
|
test::check_return_type<size_type>::equals(a.size());
|
||||||
|
test::check_return_type<size_type>::equals(a.max_size());
|
||||||
|
test::check_return_type<bool>::convertible(a.empty());
|
||||||
|
|
||||||
|
// Allocator
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
|
||||||
|
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
|
||||||
|
}
|
||||||
|
|
||||||
template <class X, class Key>
|
template <class X, class Key>
|
||||||
void unordered_set_test(X&, Key const&)
|
void unordered_set_test(X&, Key const&)
|
||||||
{
|
{
|
||||||
@ -160,6 +191,7 @@ void unordered_map_test(X& r, Key const& k, T const& v)
|
|||||||
{
|
{
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||||
|
|
||||||
BOOST_MPL_ASSERT((
|
BOOST_MPL_ASSERT((
|
||||||
boost::is_same<value_type, std::pair<key_type const, T> >));
|
boost::is_same<value_type, std::pair<key_type const, T> >));
|
||||||
|
|
||||||
@ -180,6 +212,8 @@ void equality_test(X& r)
|
|||||||
|
|
||||||
test::check_return_type<bool>::equals(a == b);
|
test::check_return_type<bool>::equals(a == b);
|
||||||
test::check_return_type<bool>::equals(a != b);
|
test::check_return_type<bool>::equals(a != b);
|
||||||
|
test::check_return_type<bool>::equals(boost::operator==(a, b));
|
||||||
|
test::check_return_type<bool>::equals(boost::operator!=(a, b));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class T>
|
template <class X, class T>
|
||||||
@ -211,9 +245,11 @@ void unordered_map_functions(X&, Key const& k, T const&)
|
|||||||
test::check_return_type<mapped_type const>::equals_ref(b.at(k));
|
test::check_return_type<mapped_type const>::equals_ref(b.at(k));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class Key, class T, class Hash, class Pred>
|
template <class X, class Key, class Hash, class Pred>
|
||||||
void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
|
||||||
{
|
{
|
||||||
|
unordered_destructible_test(x);
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::hasher hasher;
|
typedef BOOST_DEDUCED_TYPENAME X::hasher hasher;
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::key_equal key_equal;
|
typedef BOOST_DEDUCED_TYPENAME X::key_equal key_equal;
|
||||||
@ -277,8 +313,8 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
|||||||
const_local_iterator_reference;
|
const_local_iterator_reference;
|
||||||
|
|
||||||
BOOST_MPL_ASSERT((boost::is_same<Key, key_type>));
|
BOOST_MPL_ASSERT((boost::is_same<Key, key_type>));
|
||||||
boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
|
//boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
|
||||||
boost::function_requires<boost::AssignableConcept<key_type> >();
|
//boost::function_requires<boost::AssignableConcept<key_type> >();
|
||||||
|
|
||||||
BOOST_MPL_ASSERT((boost::is_same<Hash, hasher>));
|
BOOST_MPL_ASSERT((boost::is_same<Hash, hasher>));
|
||||||
test::check_return_type<std::size_t>::equals(hf(k));
|
test::check_return_type<std::size_t>::equals(hf(k));
|
||||||
@ -316,45 +352,18 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
|||||||
X();
|
X();
|
||||||
X a4;
|
X a4;
|
||||||
|
|
||||||
BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
|
|
||||||
BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
|
|
||||||
|
|
||||||
X(i, j, 10, hf, eq);
|
|
||||||
X a5(i, j, 10, hf, eq);
|
|
||||||
X(i, j, 10, hf);
|
|
||||||
X a6(i, j, 10, hf);
|
|
||||||
X(i, j, 10);
|
|
||||||
X a7(i, j, 10);
|
|
||||||
X(i, j);
|
|
||||||
X a8(i, j);
|
|
||||||
|
|
||||||
X const b;
|
|
||||||
sink(X(b));
|
|
||||||
X a9(b);
|
|
||||||
a = b;
|
|
||||||
|
|
||||||
test::check_return_type<hasher>::equals(b.hash_function());
|
|
||||||
test::check_return_type<key_equal>::equals(b.key_eq());
|
|
||||||
|
|
||||||
const_iterator q = a.cbegin();
|
|
||||||
test::check_return_type<iterator>::equals(a.insert(q, t));
|
|
||||||
test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
|
|
||||||
|
|
||||||
a.insert(i, j);
|
|
||||||
test::check_return_type<size_type>::equals(a.erase(k));
|
test::check_return_type<size_type>::equals(a.erase(k));
|
||||||
|
|
||||||
BOOST_TEST(a.empty());
|
|
||||||
if(a.empty()) {
|
|
||||||
a.insert(t);
|
|
||||||
q = a.cbegin();
|
|
||||||
test::check_return_type<iterator>::equals(a.erase(q));
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator q1 = a.cbegin(), q2 = a.cend();
|
const_iterator q1 = a.cbegin(), q2 = a.cend();
|
||||||
test::check_return_type<iterator>::equals(a.erase(q1, q2));
|
test::check_return_type<iterator>::equals(a.erase(q1, q2));
|
||||||
|
|
||||||
a.clear();
|
a.clear();
|
||||||
|
|
||||||
|
X const b;
|
||||||
|
|
||||||
|
test::check_return_type<hasher>::equals(b.hash_function());
|
||||||
|
test::check_return_type<key_equal>::equals(b.key_eq());
|
||||||
|
|
||||||
test::check_return_type<iterator>::equals(a.find(k));
|
test::check_return_type<iterator>::equals(a.find(k));
|
||||||
test::check_return_type<const_iterator>::equals(b.find(k));
|
test::check_return_type<const_iterator>::equals(b.find(k));
|
||||||
test::check_return_type<size_type>::equals(b.count(k));
|
test::check_return_type<size_type>::equals(b.count(k));
|
||||||
@ -388,9 +397,117 @@ void unordered_test(X&, Key& k, T& t, Hash& hf, Pred& eq)
|
|||||||
sink(a2);
|
sink(a2);
|
||||||
sink(a3);
|
sink(a3);
|
||||||
sink(a4);
|
sink(a4);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X, class Key, class T, class Hash, class Pred>
|
||||||
|
void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
|
||||||
|
{
|
||||||
|
unordered_test(x, k, hf, eq);
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
|
||||||
|
|
||||||
|
X a;
|
||||||
|
|
||||||
|
BOOST_DEDUCED_TYPENAME X::value_type* i = 0;
|
||||||
|
BOOST_DEDUCED_TYPENAME X::value_type* j = 0;
|
||||||
|
|
||||||
|
X(i, j, 10, hf, eq);
|
||||||
|
X a5(i, j, 10, hf, eq);
|
||||||
|
X(i, j, 10, hf);
|
||||||
|
X a6(i, j, 10, hf);
|
||||||
|
X(i, j, 10);
|
||||||
|
X a7(i, j, 10);
|
||||||
|
X(i, j);
|
||||||
|
X a8(i, j);
|
||||||
|
|
||||||
|
X const b;
|
||||||
|
sink(X(b));
|
||||||
|
X a9(b);
|
||||||
|
a = b;
|
||||||
|
|
||||||
|
const_iterator q = a.cbegin();
|
||||||
|
|
||||||
|
test::check_return_type<iterator>::equals(a.insert(q, t));
|
||||||
|
test::check_return_type<iterator>::equals(a.emplace_hint(q, t));
|
||||||
|
|
||||||
|
a.insert(i, j);
|
||||||
|
|
||||||
|
X a10;
|
||||||
|
a10.insert(t);
|
||||||
|
q = a10.cbegin();
|
||||||
|
test::check_return_type<iterator>::equals(a10.erase(q));
|
||||||
|
|
||||||
|
// Avoid unused variable warnings:
|
||||||
|
|
||||||
|
sink(a);
|
||||||
sink(a5);
|
sink(a5);
|
||||||
sink(a6);
|
sink(a6);
|
||||||
sink(a7);
|
sink(a7);
|
||||||
sink(a8);
|
sink(a8);
|
||||||
sink(a9);
|
sink(a9);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class X, class Key, class T, class Hash, class Pred>
|
||||||
|
void unordered_movable_test(X& x, Key& k, T& /* t */, Hash& hf, Pred& eq)
|
||||||
|
{
|
||||||
|
unordered_test(x, k, hf, eq);
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME X::const_iterator const_iterator;
|
||||||
|
|
||||||
|
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||||
|
X x1(rvalue_default<X>());
|
||||||
|
X x2(boost::move(x1));
|
||||||
|
x1 = rvalue_default<X>();
|
||||||
|
x2 = boost::move(x1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
test::minimal::constructor_param* i = 0;
|
||||||
|
test::minimal::constructor_param* j = 0;
|
||||||
|
|
||||||
|
X(i, j, 10, hf, eq);
|
||||||
|
X a5(i, j, 10, hf, eq);
|
||||||
|
X(i, j, 10, hf);
|
||||||
|
X a6(i, j, 10, hf);
|
||||||
|
X(i, j, 10);
|
||||||
|
X a7(i, j, 10);
|
||||||
|
X(i, j);
|
||||||
|
X a8(i, j);
|
||||||
|
|
||||||
|
X a;
|
||||||
|
|
||||||
|
const_iterator q = a.cbegin();
|
||||||
|
|
||||||
|
test::minimal::constructor_param v;
|
||||||
|
a.emplace(v);
|
||||||
|
test::check_return_type<iterator>::equals(a.emplace_hint(q, v));
|
||||||
|
|
||||||
|
T v1(v);
|
||||||
|
a.emplace(boost::move(v1));
|
||||||
|
T v2(v);
|
||||||
|
a.insert(boost::move(v2));
|
||||||
|
T v3(v);
|
||||||
|
test::check_return_type<iterator>::equals(
|
||||||
|
a.emplace_hint(q, boost::move(v3)));
|
||||||
|
T v4(v);
|
||||||
|
test::check_return_type<iterator>::equals(
|
||||||
|
a.insert(q, boost::move(v4)));
|
||||||
|
|
||||||
|
a.insert(i, j);
|
||||||
|
|
||||||
|
X a10;
|
||||||
|
T v5(v);
|
||||||
|
a10.insert(boost::move(v5));
|
||||||
|
q = a10.cbegin();
|
||||||
|
test::check_return_type<iterator>::equals(a10.erase(q));
|
||||||
|
|
||||||
|
// Avoid unused variable warnings:
|
||||||
|
|
||||||
|
sink(a);
|
||||||
|
sink(a5);
|
||||||
|
sink(a6);
|
||||||
|
sink(a7);
|
||||||
|
sink(a8);
|
||||||
|
sink(a10);
|
||||||
|
}
|
||||||
|
@ -31,6 +31,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 1\n";
|
std::cerr<<"Construct 1\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(0, hf, eq);
|
T x(0, hf, eq);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
@ -41,6 +43,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 2\n";
|
std::cerr<<"Construct 2\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(100, hf);
|
T x(100, hf);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 100);
|
BOOST_TEST(x.bucket_count() >= 100);
|
||||||
@ -52,6 +56,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 3\n";
|
std::cerr<<"Construct 3\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(2000);
|
T x(2000);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 2000);
|
BOOST_TEST(x.bucket_count() >= 2000);
|
||||||
@ -63,6 +69,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 4\n";
|
std::cerr<<"Construct 4\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x;
|
T x;
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
@ -73,6 +81,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 5\n";
|
std::cerr<<"Construct 5\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
T x(v.begin(), v.end(), 10000, hf, eq);
|
T x(v.begin(), v.end(), 10000, hf, eq);
|
||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
@ -85,6 +95,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 6\n";
|
std::cerr<<"Construct 6\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(10, generator);
|
test::random_values<T> v(10, generator);
|
||||||
T x(v.begin(), v.end(), 10000, hf);
|
T x(v.begin(), v.end(), 10000, hf);
|
||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
@ -97,6 +109,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 7\n";
|
std::cerr<<"Construct 7\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(v.begin(), v.end(), 100);
|
T x(v.begin(), v.end(), 100);
|
||||||
BOOST_TEST(x.bucket_count() >= 100);
|
BOOST_TEST(x.bucket_count() >= 100);
|
||||||
@ -109,6 +123,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 8\n";
|
std::cerr<<"Construct 8\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1, generator);
|
test::random_values<T> v(1, generator);
|
||||||
T x(v.begin(), v.end());
|
T x(v.begin(), v.end());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
@ -120,6 +136,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 9\n";
|
std::cerr<<"Construct 9\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(0, hf, eq, al);
|
T x(0, hf, eq, al);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
@ -130,6 +148,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 10\n";
|
std::cerr<<"Construct 10\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
T x(v.begin(), v.end(), 10000, hf, eq, al);
|
||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
@ -142,6 +162,8 @@ void constructor_tests1(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 11\n";
|
std::cerr<<"Construct 11\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(al);
|
T x(al);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
@ -167,6 +189,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 1\n";
|
std::cerr<<"Construct 1\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
T x(10000, hf1, eq1);
|
T x(10000, hf1, eq1);
|
||||||
BOOST_TEST(x.bucket_count() >= 10000);
|
BOOST_TEST(x.bucket_count() >= 10000);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||||
@ -177,6 +200,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 2\n";
|
std::cerr<<"Construct 2\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
T x(100, hf1);
|
T x(100, hf1);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 100);
|
BOOST_TEST(x.bucket_count() >= 100);
|
||||||
@ -188,6 +212,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 3\n";
|
std::cerr<<"Construct 3\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||||
@ -199,6 +224,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 4\n";
|
std::cerr<<"Construct 4\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(5, generator);
|
test::random_values<T> v(5, generator);
|
||||||
T x(v.begin(), v.end(), 1000, hf1);
|
T x(v.begin(), v.end(), 1000, hf1);
|
||||||
BOOST_TEST(x.bucket_count() >= 1000);
|
BOOST_TEST(x.bucket_count() >= 1000);
|
||||||
@ -212,6 +238,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 5\n";
|
std::cerr<<"Construct 5\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
T x(v.begin(), v.end(), 0, hf, eq, al1);
|
||||||
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
T y(x.begin(), x.end(), 0, hf1, eq1, al2);
|
||||||
@ -223,6 +250,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 6\n";
|
std::cerr<<"Construct 6\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||||
T y(x.begin(), x.end(), 0, hf, eq);
|
T y(x.begin(), x.end(), 0, hf, eq);
|
||||||
@ -234,6 +262,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 7\n";
|
std::cerr<<"Construct 7\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(v.begin(), v.end(), 0, hf1, eq1);
|
T x(v.begin(), v.end(), 0, hf1, eq1);
|
||||||
T y(x.begin(), x.end(), 0, hf2, eq2);
|
T y(x.begin(), x.end(), 0, hf2, eq2);
|
||||||
@ -245,6 +274,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 8 - from input iterator\n";
|
std::cerr<<"Construct 8 - from input iterator\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
BOOST_DEDUCED_TYPENAME test::random_values<T>::const_iterator
|
||||||
v_begin = v.begin(), v_end = v.end();
|
v_begin = v.begin(), v_end = v.end();
|
||||||
@ -262,6 +292,7 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 8.5 - from copy iterator\n";
|
std::cerr<<"Construct 8.5 - from copy iterator\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(test::copy_iterator(v.begin()),
|
T x(test::copy_iterator(v.begin()),
|
||||||
test::copy_iterator(v.end()), 0, hf1, eq1);
|
test::copy_iterator(v.end()), 0, hf1, eq1);
|
||||||
@ -275,6 +306,8 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Construct 9\n";
|
std::cerr<<"Construct 9\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(100, generator);
|
test::random_values<T> v(100, generator);
|
||||||
T x(50);
|
T x(50);
|
||||||
BOOST_TEST(x.bucket_count() >= 50);
|
BOOST_TEST(x.bucket_count() >= 50);
|
||||||
@ -291,6 +324,8 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Initializer list construct 1\n";
|
std::cerr<<"Initializer list construct 1\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(list);
|
T x(list);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||||
@ -300,6 +335,8 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Initializer list construct 2\n";
|
std::cerr<<"Initializer list construct 2\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(list, 1000);
|
T x(list, 1000);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 1000);
|
BOOST_TEST(x.bucket_count() >= 1000);
|
||||||
@ -310,6 +347,8 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Initializer list construct 3\n";
|
std::cerr<<"Initializer list construct 3\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(list, 10, hf1);
|
T x(list, 10, hf1);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 10);
|
BOOST_TEST(x.bucket_count() >= 10);
|
||||||
@ -320,6 +359,8 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Initializer list construct 4\n";
|
std::cerr<<"Initializer list construct 4\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(list, 10, hf1, eq1);
|
T x(list, 10, hf1, eq1);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 10);
|
BOOST_TEST(x.bucket_count() >= 10);
|
||||||
@ -330,6 +371,8 @@ void constructor_tests2(T*,
|
|||||||
|
|
||||||
std::cerr<<"Initializer list construct 5\n";
|
std::cerr<<"Initializer list construct 5\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(list, 10, hf1, eq1, al1);
|
T x(list, 10, hf1, eq1, al1);
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST(x.bucket_count() >= 10);
|
BOOST_TEST(x.bucket_count() >= 10);
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include "../helpers/test.hpp"
|
#include "../helpers/test.hpp"
|
||||||
#include "../objects/test.hpp"
|
#include "../objects/test.hpp"
|
||||||
|
#include "../objects/cxx11_allocator.hpp"
|
||||||
#include "../helpers/random_values.hpp"
|
#include "../helpers/random_values.hpp"
|
||||||
#include "../helpers/tracker.hpp"
|
#include "../helpers/tracker.hpp"
|
||||||
#include "../helpers/equivalent.hpp"
|
#include "../helpers/equivalent.hpp"
|
||||||
@ -23,11 +24,15 @@ template <class T>
|
|||||||
void copy_construct_tests1(T*,
|
void copy_construct_tests1(T*,
|
||||||
test::random_generator const& generator = test::default_generator)
|
test::random_generator const& generator = test::default_generator)
|
||||||
{
|
{
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||||
|
|
||||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x;
|
T x;
|
||||||
T y(x);
|
T y(x);
|
||||||
BOOST_TEST(y.empty());
|
BOOST_TEST(y.empty());
|
||||||
@ -35,20 +40,28 @@ void copy_construct_tests1(T*,
|
|||||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||||
|
(allocator_type::is_select_on_copy));
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
|
|
||||||
T x(v.begin(), v.end());
|
T x(v.begin(), v.end());
|
||||||
T y(x);
|
T y(x);
|
||||||
test::unordered_equivalence_tester<T> equivalent(x);
|
test::unordered_equivalence_tester<T> equivalent(x);
|
||||||
BOOST_TEST(equivalent(y));
|
BOOST_TEST(equivalent(y));
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||||
|
(allocator_type::is_select_on_copy));
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
// In this test I drop the original containers max load factor, so it
|
// In this test I drop the original containers max load factor, so it
|
||||||
// is much lower than the load factor. The hash table is not allowed
|
// is much lower than the load factor. The hash table is not allowed
|
||||||
// to rehash, but the destination container should probably allocate
|
// to rehash, but the destination container should probably allocate
|
||||||
@ -61,6 +74,8 @@ void copy_construct_tests1(T*,
|
|||||||
BOOST_TEST(equivalent(y));
|
BOOST_TEST(equivalent(y));
|
||||||
// This isn't guaranteed:
|
// This isn't guaranteed:
|
||||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||||
|
(allocator_type::is_select_on_copy));
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,8 +90,12 @@ void copy_construct_tests2(T* ptr,
|
|||||||
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
||||||
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
|
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
|
||||||
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||||
|
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(10000, hf, eq, al);
|
T x(10000, hf, eq, al);
|
||||||
T y(x);
|
T y(x);
|
||||||
BOOST_TEST(y.empty());
|
BOOST_TEST(y.empty());
|
||||||
@ -84,10 +103,14 @@ void copy_construct_tests2(T* ptr,
|
|||||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||||
|
(allocator_type::is_select_on_copy));
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T x(1000, hf, eq, al);
|
T x(1000, hf, eq, al);
|
||||||
T y(x, al2);
|
T y(x, al2);
|
||||||
BOOST_TEST(y.empty());
|
BOOST_TEST(y.empty());
|
||||||
@ -95,10 +118,13 @@ void copy_construct_tests2(T* ptr,
|
|||||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
|
|
||||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||||
@ -106,10 +132,14 @@ void copy_construct_tests2(T* ptr,
|
|||||||
test::unordered_equivalence_tester<T> equivalent(x);
|
test::unordered_equivalence_tester<T> equivalent(x);
|
||||||
BOOST_TEST(equivalent(y));
|
BOOST_TEST(equivalent(y));
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) ==
|
||||||
|
(allocator_type::is_select_on_copy));
|
||||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(500, generator);
|
test::random_values<T> v(500, generator);
|
||||||
|
|
||||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||||
@ -117,6 +147,7 @@ void copy_construct_tests2(T* ptr,
|
|||||||
test::unordered_equivalence_tester<T> equivalent(x);
|
test::unordered_equivalence_tester<T> equivalent(x);
|
||||||
BOOST_TEST(equivalent(y));
|
BOOST_TEST(equivalent(y));
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
|
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||||
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -134,15 +165,55 @@ boost::unordered_multimap<test::object, test::object,
|
|||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_multimap;
|
test::allocator<test::object> >* test_multimap;
|
||||||
|
|
||||||
|
boost::unordered_set<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||||
|
test_set_select_copy;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||||
|
test_multiset_select_copy;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||||
|
test_map_select_copy;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||||
|
test_multimap_select_copy;
|
||||||
|
|
||||||
|
boost::unordered_set<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||||
|
test_set_no_select_copy;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||||
|
test_multiset_no_select_copy;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||||
|
test_map_no_select_copy;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||||
|
test_multimap_no_select_copy;
|
||||||
|
|
||||||
using test::default_generator;
|
using test::default_generator;
|
||||||
using test::generate_collisions;
|
using test::generate_collisions;
|
||||||
|
|
||||||
UNORDERED_TEST(copy_construct_tests1,
|
UNORDERED_TEST(copy_construct_tests1, (
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
|
||||||
|
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
UNORDERED_TEST(copy_construct_tests2,
|
UNORDERED_TEST(copy_construct_tests2, (
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)
|
||||||
|
(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy)
|
||||||
|
)
|
||||||
((default_generator)(generate_collisions))
|
((default_generator)(generate_collisions))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -136,15 +136,17 @@ namespace equality_tests
|
|||||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||||
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
((1)(1))((1)(1)), !=, ((1)(1))((1)(2)))
|
||||||
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||||
((1)(2))((1)(1)), !=, ((1)(1))((1)(2)))
|
((1)(2))((1)(1)), ==, ((1)(1))((1)(2)))
|
||||||
|
UNORDERED_EQUALITY_MULTIMAP_TEST(
|
||||||
|
((1)(2))((1)(1)), !=, ((1)(1))((1)(3)))
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(equality_predicate_test)
|
UNORDERED_AUTO_TEST(equality_predicate_test)
|
||||||
{
|
{
|
||||||
UNORDERED_EQUALITY_SET_TEST(
|
UNORDERED_EQUALITY_SET_TEST(
|
||||||
(1), ==, (1001))
|
(1), !=, (1001))
|
||||||
UNORDERED_EQUALITY_MAP_TEST(
|
UNORDERED_EQUALITY_MAP_TEST(
|
||||||
((1)(2))((1001)(1)), ==, ((1001)(2))((1)(1)))
|
((1)(2))((1001)(1)), !=, ((1001)(2))((1)(1)))
|
||||||
}
|
}
|
||||||
|
|
||||||
// Test that equality still works when the two containers have
|
// Test that equality still works when the two containers have
|
||||||
|
@ -28,6 +28,8 @@ void erase_tests1(Container*,
|
|||||||
{
|
{
|
||||||
std::cerr<<"Erase by key.\n";
|
std::cerr<<"Erase by key.\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(1000, generator);
|
test::random_values<Container> v(1000, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
|
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
|
||||||
@ -44,6 +46,8 @@ void erase_tests1(Container*,
|
|||||||
|
|
||||||
std::cerr<<"erase(begin()).\n";
|
std::cerr<<"erase(begin()).\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(1000, generator);
|
test::random_values<Container> v(1000, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
std::size_t size = x.size();
|
std::size_t size = x.size();
|
||||||
@ -64,6 +68,8 @@ void erase_tests1(Container*,
|
|||||||
|
|
||||||
std::cerr<<"erase(random position).\n";
|
std::cerr<<"erase(random position).\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(1000, generator);
|
test::random_values<Container> v(1000, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
std::size_t size = x.size();
|
std::size_t size = x.size();
|
||||||
@ -96,6 +102,8 @@ void erase_tests1(Container*,
|
|||||||
|
|
||||||
std::cerr<<"erase(ranges).\n";
|
std::cerr<<"erase(ranges).\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(500, generator);
|
test::random_values<Container> v(500, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
|
|
||||||
@ -118,6 +126,8 @@ void erase_tests1(Container*,
|
|||||||
|
|
||||||
std::cerr<<"quick_erase(begin()).\n";
|
std::cerr<<"quick_erase(begin()).\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(1000, generator);
|
test::random_values<Container> v(1000, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
std::size_t size = x.size();
|
std::size_t size = x.size();
|
||||||
@ -136,6 +146,8 @@ void erase_tests1(Container*,
|
|||||||
|
|
||||||
std::cerr<<"quick_erase(random position).\n";
|
std::cerr<<"quick_erase(random position).\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(1000, generator);
|
test::random_values<Container> v(1000, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
std::size_t size = x.size();
|
std::size_t size = x.size();
|
||||||
@ -169,6 +181,8 @@ void erase_tests1(Container*,
|
|||||||
|
|
||||||
std::cerr<<"clear().\n";
|
std::cerr<<"clear().\n";
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<Container> v(500, generator);
|
test::random_values<Container> v(500, generator);
|
||||||
Container x(v.begin(), v.end());
|
Container x(v.begin(), v.end());
|
||||||
x.clear();
|
x.clear();
|
||||||
|
@ -24,6 +24,8 @@ void find_tests1(X*, test::random_generator generator = test::default_generator)
|
|||||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> v(500, generator);
|
test::random_values<X> v(500, generator);
|
||||||
X x(v.begin(), v.end());
|
X x(v.begin(), v.end());
|
||||||
X const& x_const = x;
|
X const& x_const = x;
|
||||||
@ -69,6 +71,8 @@ void find_tests1(X*, test::random_generator generator = test::default_generator)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
|
|
||||||
test::random_values<X> v2(5, generator);
|
test::random_values<X> v2(5, generator);
|
||||||
|
@ -26,6 +26,8 @@ template <class X>
|
|||||||
void unique_insert_tests1(X*,
|
void unique_insert_tests1(X*,
|
||||||
test::random_generator generator = test::default_generator)
|
test::random_generator generator = test::default_generator)
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||||
typedef test::ordered<X> ordered;
|
typedef test::ordered<X> ordered;
|
||||||
|
|
||||||
@ -65,6 +67,9 @@ void equivalent_insert_tests1(X*,
|
|||||||
{
|
{
|
||||||
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
||||||
|
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
test::ordered<X> tracker = test::create_ordered(x);
|
test::ordered<X> tracker = test::create_ordered(x);
|
||||||
|
|
||||||
@ -102,6 +107,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert(begin(), value) tests.\n";
|
std::cerr<<"insert(begin(), value) tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
|
|
||||||
@ -128,6 +135,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert(end(), value) tests.\n";
|
std::cerr<<"insert(end(), value) tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
X const& x_const = x;
|
X const& x_const = x;
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
@ -155,6 +164,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert(pos, value) tests.\n";
|
std::cerr<<"insert(pos, value) tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
const_iterator pos = x.begin();
|
const_iterator pos = x.begin();
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
@ -182,6 +193,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert single item range tests.\n";
|
std::cerr<<"insert single item range tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
tracker_type tracker = test::create_ordered(x);
|
tracker_type tracker = test::create_ordered(x);
|
||||||
|
|
||||||
@ -207,6 +220,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert range tests.\n";
|
std::cerr<<"insert range tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
|
|
||||||
test::random_values<X> v(1000, generator);
|
test::random_values<X> v(1000, generator);
|
||||||
@ -219,6 +234,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert input iterator range tests.\n";
|
std::cerr<<"insert input iterator range tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
|
|
||||||
test::random_values<X> v(1000, generator);
|
test::random_values<X> v(1000, generator);
|
||||||
@ -233,6 +250,8 @@ void insert_tests2(X*,
|
|||||||
std::cerr<<"insert copy iterator range tests.\n";
|
std::cerr<<"insert copy iterator range tests.\n";
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
|
|
||||||
test::random_values<X> v(1000, generator);
|
test::random_values<X> v(1000, generator);
|
||||||
@ -351,6 +370,8 @@ void map_insert_range_test1(X*,
|
|||||||
{
|
{
|
||||||
std::cerr<<"map_insert_range_test1\n";
|
std::cerr<<"map_insert_range_test1\n";
|
||||||
|
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
typedef test::list<
|
typedef test::list<
|
||||||
std::pair<
|
std::pair<
|
||||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||||
@ -371,6 +392,8 @@ void map_insert_range_test2(X*,
|
|||||||
{
|
{
|
||||||
std::cerr<<"map_insert_range_test2\n";
|
std::cerr<<"map_insert_range_test2\n";
|
||||||
|
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
typedef test::list<
|
typedef test::list<
|
||||||
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, test::implicitly_convertible>
|
std::pair<BOOST_DEDUCED_TYPENAME X::key_type const, test::implicitly_convertible>
|
||||||
> list;
|
> list;
|
||||||
|
@ -9,11 +9,16 @@
|
|||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include "../helpers/test.hpp"
|
#include "../helpers/test.hpp"
|
||||||
#include "../objects/test.hpp"
|
#include "../objects/test.hpp"
|
||||||
|
#include "../objects/cxx11_allocator.hpp"
|
||||||
#include "../helpers/random_values.hpp"
|
#include "../helpers/random_values.hpp"
|
||||||
#include "../helpers/tracker.hpp"
|
#include "../helpers/tracker.hpp"
|
||||||
#include "../helpers/equivalent.hpp"
|
#include "../helpers/equivalent.hpp"
|
||||||
#include "../helpers/invariants.hpp"
|
#include "../helpers/invariants.hpp"
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(disable:4127) // conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace move_tests
|
namespace move_tests
|
||||||
{
|
{
|
||||||
test::seed_t seed(98624);
|
test::seed_t seed(98624);
|
||||||
@ -54,6 +59,8 @@ namespace move_tests
|
|||||||
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
BOOST_DEDUCED_TYPENAME T::allocator_type al;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
T y(empty(ptr));
|
T y(empty(ptr));
|
||||||
BOOST_TEST(y.empty());
|
BOOST_TEST(y.empty());
|
||||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||||
@ -64,6 +71,8 @@ namespace move_tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(1000, generator);
|
test::random_values<T> v(1000, generator);
|
||||||
test::object_count count;
|
test::object_count count;
|
||||||
T y(create(v, count));
|
T y(create(v, count));
|
||||||
@ -80,6 +89,8 @@ namespace move_tests
|
|||||||
test::random_generator const& generator = test::default_generator)
|
test::random_generator const& generator = test::default_generator)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(500, generator);
|
test::random_values<T> v(500, generator);
|
||||||
test::object_count count;
|
test::object_count count;
|
||||||
T y;
|
T y;
|
||||||
@ -104,6 +115,8 @@ namespace move_tests
|
|||||||
test::object_count count;
|
test::object_count count;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(500, generator);
|
test::random_values<T> v(500, generator);
|
||||||
T y(create(v, count, hf, eq, al, 0.5));
|
T y(create(v, count, hf, eq, al, 0.5));
|
||||||
#if defined(BOOST_HAS_NRVO)
|
#if defined(BOOST_HAS_NRVO)
|
||||||
@ -118,6 +131,8 @@ namespace move_tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
// TODO: To do this correctly requires the fancy new allocator
|
// TODO: To do this correctly requires the fancy new allocator
|
||||||
// stuff.
|
// stuff.
|
||||||
test::random_values<T> v(500, generator);
|
test::random_values<T> v(500, generator);
|
||||||
@ -130,17 +145,24 @@ namespace move_tests
|
|||||||
BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
|
BOOST_TEST(y.max_load_factor() == 2.0); // Not necessarily required.
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<T> v(25, generator);
|
test::random_values<T> v(25, generator);
|
||||||
T y(create(v, count, hf, eq, al, 1.0), al);
|
T y(create(v, count, hf, eq, al, 1.0), al);
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||||
BOOST_TEST(count == test::global_object_count);
|
BOOST_TEST(count == test::global_object_count);
|
||||||
#else
|
#elif defined(BOOST_HAS_NRVO)
|
||||||
BOOST_TEST(
|
BOOST_TEST(
|
||||||
test::global_object_count.constructions - count.constructions <=
|
test::global_object_count.constructions - count.constructions <=
|
||||||
(test::is_map<T>::value ? 50 : 25));
|
(test::is_map<T>::value ? 50 : 25));
|
||||||
BOOST_TEST(count.instances == test::global_object_count.instances);
|
BOOST_TEST(count.instances == test::global_object_count.instances);
|
||||||
|
#else
|
||||||
|
BOOST_TEST(
|
||||||
|
test::global_object_count.constructions - count.constructions <=
|
||||||
|
(test::is_map<T>::value ? 100 : 50));
|
||||||
|
BOOST_TEST(count.instances == test::global_object_count.instances);
|
||||||
#endif
|
#endif
|
||||||
test::check_container(y, v);
|
test::check_container(y, v);
|
||||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||||
@ -149,7 +171,57 @@ namespace move_tests
|
|||||||
BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required.
|
BOOST_TEST(y.max_load_factor() == 1.0); // Not necessarily required.
|
||||||
test::check_equivalent_keys(y);
|
test::check_equivalent_keys(y);
|
||||||
}
|
}
|
||||||
*/ }
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void move_assign_tests2(T*,
|
||||||
|
test::random_generator const& generator = test::default_generator)
|
||||||
|
{
|
||||||
|
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
|
||||||
|
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
||||||
|
BOOST_DEDUCED_TYPENAME T::allocator_type al1(1);
|
||||||
|
BOOST_DEDUCED_TYPENAME T::allocator_type al2(2);
|
||||||
|
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<T> v(500, generator);
|
||||||
|
test::random_values<T> v2(0, generator);
|
||||||
|
T y(v.begin(), v.end(), 0, hf, eq, al1);
|
||||||
|
test::object_count count;
|
||||||
|
y = create(v2, count, hf, eq, al2, 2.0);
|
||||||
|
BOOST_TEST(y.empty());
|
||||||
|
test::check_container(y, v2);
|
||||||
|
test::check_equivalent_keys(y);
|
||||||
|
BOOST_TEST(y.max_load_factor() == 2.0);
|
||||||
|
if (allocator_type::is_propagate_on_move) {
|
||||||
|
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
test::random_values<T> v(500, generator);
|
||||||
|
test::object_count count;
|
||||||
|
T y(0, hf, eq, al1);
|
||||||
|
y = create(v, count, hf, eq, al2, 0.5);
|
||||||
|
#if defined(BOOST_HAS_NRVO)
|
||||||
|
if (allocator_type::is_propagate_on_move) {
|
||||||
|
BOOST_TEST(count == test::global_object_count);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
test::check_container(y, v);
|
||||||
|
test::check_equivalent_keys(y);
|
||||||
|
BOOST_TEST(y.max_load_factor() == 0.5);
|
||||||
|
if (allocator_type::is_propagate_on_move) {
|
||||||
|
BOOST_TEST(test::equivalent(y.get_allocator(), al2));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_TEST(test::equivalent(y.get_allocator(), al1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
boost::unordered_set<test::object,
|
boost::unordered_set<test::object,
|
||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
@ -164,19 +236,68 @@ namespace move_tests
|
|||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_multimap;
|
test::allocator<test::object> >* test_multimap;
|
||||||
|
|
||||||
|
boost::unordered_set<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||||
|
test_set_prop_move;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||||
|
test_multiset_prop_move;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||||
|
test_map_prop_move;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||||
|
test_multimap_prop_move;
|
||||||
|
|
||||||
|
boost::unordered_set<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||||
|
test_set_no_prop_move;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||||
|
test_multiset_no_prop_move;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||||
|
test_map_no_prop_move;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||||
|
test_multimap_no_prop_move;
|
||||||
|
|
||||||
using test::default_generator;
|
using test::default_generator;
|
||||||
using test::generate_collisions;
|
using test::generate_collisions;
|
||||||
|
|
||||||
UNORDERED_TEST(move_construct_tests1,
|
UNORDERED_TEST(move_construct_tests1, (
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
|
||||||
|
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
UNORDERED_TEST(move_assign_tests1,
|
UNORDERED_TEST(move_assign_tests1, (
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
|
||||||
|
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
|
||||||
|
)
|
||||||
)
|
)
|
||||||
UNORDERED_TEST(move_construct_tests2,
|
UNORDERED_TEST(move_construct_tests2, (
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
|
||||||
|
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
|
||||||
|
)
|
||||||
((default_generator)(generate_collisions))
|
((default_generator)(generate_collisions))
|
||||||
)
|
)
|
||||||
|
UNORDERED_TEST(move_assign_tests2, (
|
||||||
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_move)(test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)
|
||||||
|
(test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(test_multimap_no_prop_move)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -12,10 +12,15 @@
|
|||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include "../helpers/test.hpp"
|
#include "../helpers/test.hpp"
|
||||||
#include "../objects/test.hpp"
|
#include "../objects/test.hpp"
|
||||||
|
#include "../objects/cxx11_allocator.hpp"
|
||||||
#include "../helpers/random_values.hpp"
|
#include "../helpers/random_values.hpp"
|
||||||
#include "../helpers/tracker.hpp"
|
#include "../helpers/tracker.hpp"
|
||||||
#include "../helpers/invariants.hpp"
|
#include "../helpers/invariants.hpp"
|
||||||
|
|
||||||
|
#if defined(BOOST_MSVC)
|
||||||
|
#pragma warning(disable:4127) // conditional expression is constant
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace swap_tests
|
namespace swap_tests
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -37,16 +42,22 @@ template <class X>
|
|||||||
void swap_tests1(X*, test::random_generator generator = test::default_generator)
|
void swap_tests1(X*, test::random_generator generator = test::default_generator)
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x;
|
X x;
|
||||||
swap_test_impl(x, x);
|
swap_test_impl(x, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x,y;
|
X x,y;
|
||||||
swap_test_impl(x, y);
|
swap_test_impl(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> v(1000, generator);
|
test::random_values<X> v(1000, generator);
|
||||||
X x, y(v.begin(), v.end());
|
X x, y(v.begin(), v.end());
|
||||||
swap_test_impl(x, y);
|
swap_test_impl(x, y);
|
||||||
@ -54,6 +65,8 @@ void swap_tests1(X*, test::random_generator generator = test::default_generator)
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> vx(1000, generator), vy(1000, generator);
|
test::random_values<X> vx(1000, generator), vy(1000, generator);
|
||||||
X x(vx.begin(), vx.end()), y(vy.begin(), vy.end());
|
X x(vx.begin(), vx.end()), y(vy.begin(), vy.end());
|
||||||
swap_test_impl(x, y);
|
swap_test_impl(x, y);
|
||||||
@ -72,12 +85,16 @@ void swap_tests2(X* ptr = 0,
|
|||||||
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
|
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
X x(0, hasher(1), key_equal(1));
|
X x(0, hasher(1), key_equal(1));
|
||||||
X y(0, hasher(2), key_equal(2));
|
X y(0, hasher(2), key_equal(2));
|
||||||
swap_test_impl(x, y);
|
swap_test_impl(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> v(1000, generator);
|
test::random_values<X> v(1000, generator);
|
||||||
X x(v.begin(), v.end(), 0, hasher(1), key_equal(1));
|
X x(v.begin(), v.end(), 0, hasher(1), key_equal(1));
|
||||||
X y(0, hasher(2), key_equal(2));
|
X y(0, hasher(2), key_equal(2));
|
||||||
@ -85,6 +102,8 @@ void swap_tests2(X* ptr = 0,
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> vx(100, generator), vy(50, generator);
|
test::random_values<X> vx(100, generator), vy(50, generator);
|
||||||
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1));
|
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1));
|
||||||
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2));
|
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2));
|
||||||
@ -92,57 +111,113 @@ void swap_tests2(X* ptr = 0,
|
|||||||
swap_test_impl(x, y);
|
swap_test_impl(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if BOOST_UNORDERED_SWAP_METHOD == 1
|
|
||||||
{
|
|
||||||
test::random_values<X> vx(100, generator), vy(50, generator);
|
|
||||||
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
|
|
||||||
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
|
|
||||||
try {
|
|
||||||
swap_test_impl(x, y);
|
|
||||||
BOOST_ERROR("Using swap method 1, "
|
|
||||||
"swapping with unequal allocators didn't throw.");
|
|
||||||
} catch (std::runtime_error) {}
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
{
|
||||||
|
test::force_equal_allocator force_(
|
||||||
|
!allocator_type::is_propagate_on_swap);
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> vx(50, generator), vy(100, generator);
|
test::random_values<X> vx(50, generator), vy(100, generator);
|
||||||
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
|
X x(vx.begin(), vx.end(), 0, hasher(), key_equal(), allocator_type(1));
|
||||||
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
|
X y(vy.begin(), vy.end(), 0, hasher(), key_equal(), allocator_type(2));
|
||||||
swap_test_impl(x, y);
|
|
||||||
|
if (allocator_type::is_propagate_on_swap ||
|
||||||
|
x.get_allocator() == y.get_allocator())
|
||||||
|
{
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
test::force_equal_allocator force_(
|
||||||
|
!allocator_type::is_propagate_on_swap);
|
||||||
|
test::check_instances check_;
|
||||||
|
|
||||||
test::random_values<X> vx(100, generator), vy(100, generator);
|
test::random_values<X> vx(100, generator), vy(100, generator);
|
||||||
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1),
|
X x(vx.begin(), vx.end(), 0, hasher(1), key_equal(1),
|
||||||
allocator_type(1));
|
allocator_type(1));
|
||||||
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2),
|
X y(vy.begin(), vy.end(), 0, hasher(2), key_equal(2),
|
||||||
allocator_type(2));
|
allocator_type(2));
|
||||||
swap_test_impl(x, y);
|
|
||||||
swap_test_impl(x, y);
|
if (allocator_type::is_propagate_on_swap ||
|
||||||
|
x.get_allocator() == y.get_allocator())
|
||||||
|
{
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
swap_test_impl(x, y);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
boost::unordered_set<test::object,
|
boost::unordered_set<test::object,
|
||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_set;
|
test::allocator<test::object> >* test_set;
|
||||||
boost::unordered_multiset<test::object,
|
boost::unordered_multiset<test::object,
|
||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_multiset;
|
test::allocator<test::object> >* test_multiset;
|
||||||
boost::unordered_map<test::object, test::object,
|
boost::unordered_map<test::object, test::object,
|
||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_map;
|
test::allocator<test::object> >* test_map;
|
||||||
boost::unordered_multimap<test::object, test::object,
|
boost::unordered_multimap<test::object, test::object,
|
||||||
test::hash, test::equal_to,
|
test::hash, test::equal_to,
|
||||||
test::allocator<test::object> >* test_multimap;
|
test::allocator<test::object> >* test_multimap;
|
||||||
|
|
||||||
UNORDERED_TEST(swap_tests1,
|
boost::unordered_set<test::object,
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
test::hash, test::equal_to,
|
||||||
)
|
test::cxx11_allocator<test::object, test::propagate_swap> >*
|
||||||
|
test_set_prop_swap;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_swap> >*
|
||||||
|
test_multiset_prop_swap;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_swap> >*
|
||||||
|
test_map_prop_swap;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::propagate_swap> >*
|
||||||
|
test_multimap_prop_swap;
|
||||||
|
|
||||||
UNORDERED_TEST(swap_tests2,
|
boost::unordered_set<test::object,
|
||||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
test::hash, test::equal_to,
|
||||||
)
|
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||||
|
test_set_no_prop_swap;
|
||||||
|
boost::unordered_multiset<test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||||
|
test_multiset_no_prop_swap;
|
||||||
|
boost::unordered_map<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||||
|
test_map_no_prop_swap;
|
||||||
|
boost::unordered_multimap<test::object, test::object,
|
||||||
|
test::hash, test::equal_to,
|
||||||
|
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||||
|
test_multimap_no_prop_swap;
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
bool is_propagate(T*)
|
||||||
|
{
|
||||||
|
return T::allocator_type::is_propagate_on_swap;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_AUTO_TEST(check_traits)
|
||||||
|
{
|
||||||
|
BOOST_TEST(!is_propagate(test_set));
|
||||||
|
BOOST_TEST(is_propagate(test_set_prop_swap));
|
||||||
|
BOOST_TEST(!is_propagate(test_set_no_prop_swap));
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_TEST(swap_tests1, (
|
||||||
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
|
||||||
|
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
|
||||||
|
))
|
||||||
|
|
||||||
|
UNORDERED_TEST(swap_tests2, (
|
||||||
|
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||||
|
(test_set_prop_swap)(test_multiset_prop_swap)(test_map_prop_swap)(test_multimap_prop_swap)
|
||||||
|
(test_set_no_prop_swap)(test_multiset_no_prop_swap)(test_map_no_prop_swap)(test_multimap_no_prop_swap)
|
||||||
|
))
|
||||||
|
|
||||||
}
|
}
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -13,6 +13,9 @@ namespace unnecessary_copy_tests
|
|||||||
{
|
{
|
||||||
struct count_copies
|
struct count_copies
|
||||||
{
|
{
|
||||||
|
private:
|
||||||
|
BOOST_COPYABLE_AND_MOVABLE(count_copies)
|
||||||
|
public:
|
||||||
static int copies;
|
static int copies;
|
||||||
static int moves;
|
static int moves;
|
||||||
count_copies() : tag_(0) { ++copies; }
|
count_copies() : tag_(0) { ++copies; }
|
||||||
@ -31,14 +34,25 @@ namespace unnecessary_copy_tests
|
|||||||
: tag_(x.tag_) { ++copies; }
|
: tag_(x.tag_) { ++copies; }
|
||||||
|
|
||||||
count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
|
count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
count_copies(BOOST_RV_REF(count_copies) x) : tag_(x.tag_) {
|
||||||
count_copies(count_copies&& x) : tag_(x.tag_) {
|
|
||||||
x.tag_ = -1; ++moves;
|
x.tag_ = -1; ++moves;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
int tag_;
|
count_copies& operator=(BOOST_COPY_ASSIGN_REF(count_copies) p) // Copy assignment
|
||||||
private:
|
{
|
||||||
count_copies& operator=(count_copies const&);
|
tag_ = p.tag_;
|
||||||
|
++copies;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
count_copies& operator=(BOOST_RV_REF(count_copies) p) //Move assignment
|
||||||
|
{
|
||||||
|
tag_ = p.tag_;
|
||||||
|
++moves;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tag_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool operator==(count_copies const& x, count_copies const& y) {
|
bool operator==(count_copies const& x, count_copies const& y) {
|
||||||
@ -68,31 +82,37 @@ namespace unnecessary_copy_tests
|
|||||||
}
|
}
|
||||||
|
|
||||||
#define COPY_COUNT(n) \
|
#define COPY_COUNT(n) \
|
||||||
if(count_copies::copies != n) { \
|
if(::unnecessary_copy_tests::count_copies::copies != n) { \
|
||||||
BOOST_ERROR("Wrong number of copies."); \
|
BOOST_ERROR("Wrong number of copies."); \
|
||||||
std::cerr \
|
std::cerr \
|
||||||
<< "Number of copies: " << count_copies::copies \
|
<< "Number of copies: " \
|
||||||
|
<< ::unnecessary_copy_tests::count_copies::copies \
|
||||||
<< " expecting: " << n << std::endl; \
|
<< " expecting: " << n << std::endl; \
|
||||||
}
|
}
|
||||||
#define MOVE_COUNT(n) \
|
#define MOVE_COUNT(n) \
|
||||||
if(count_copies::moves != n) { \
|
if(::unnecessary_copy_tests::count_copies::moves != n) { \
|
||||||
BOOST_ERROR("Wrong number of moves."); \
|
BOOST_ERROR("Wrong number of moves."); \
|
||||||
std::cerr \
|
std::cerr \
|
||||||
<< "Number of moves: " << count_copies::moves \
|
<< "Number of moves: " \
|
||||||
|
<< ::unnecessary_copy_tests::count_copies::moves \
|
||||||
<< " expecting: " <<n << std::endl; \
|
<< " expecting: " <<n << std::endl; \
|
||||||
}
|
}
|
||||||
#define COPY_COUNT_RANGE(a, b) \
|
#define COPY_COUNT_RANGE(a, b) \
|
||||||
if(count_copies::copies < a || count_copies::copies > b) { \
|
if(::unnecessary_copy_tests::count_copies::copies < a || \
|
||||||
|
::unnecessary_copy_tests::count_copies::copies > b) { \
|
||||||
BOOST_ERROR("Wrong number of copies."); \
|
BOOST_ERROR("Wrong number of copies."); \
|
||||||
std::cerr \
|
std::cerr \
|
||||||
<< "Number of copies: " << count_copies::copies \
|
<< "Number of copies: " \
|
||||||
|
<< ::unnecessary_copy_tests::count_copies::copies \
|
||||||
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
|
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
|
||||||
}
|
}
|
||||||
#define MOVE_COUNT_RANGE(a, b) \
|
#define MOVE_COUNT_RANGE(a, b) \
|
||||||
if(count_copies::moves < a || count_copies::moves > b) { \
|
if(::unnecessary_copy_tests::count_copies::moves < a || \
|
||||||
|
::unnecessary_copy_tests::count_copies::moves > b) { \
|
||||||
BOOST_ERROR("Wrong number of moves."); \
|
BOOST_ERROR("Wrong number of moves."); \
|
||||||
std::cerr \
|
std::cerr \
|
||||||
<< "Number of moves: " << count_copies::copies \
|
<< "Number of moves: " \
|
||||||
|
<< ::unnecessary_copy_tests::count_copies::copies \
|
||||||
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
|
<< " expecting: [" << a << ", " << b << "]" << std::endl; \
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -136,7 +156,7 @@ namespace unnecessary_copy_tests
|
|||||||
reset();
|
reset();
|
||||||
T x;
|
T x;
|
||||||
x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
|
x.emplace(source<BOOST_DEDUCED_TYPENAME T::value_type>());
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||||
COPY_COUNT(1);
|
COPY_COUNT(1);
|
||||||
#else
|
#else
|
||||||
COPY_COUNT(2);
|
COPY_COUNT(2);
|
||||||
@ -148,7 +168,7 @@ namespace unnecessary_copy_tests
|
|||||||
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
|
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
|
||||||
((set)(multiset)(map)(multimap)))
|
((set)(multiset)(map)(multimap)))
|
||||||
|
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
template <class T>
|
template <class T>
|
||||||
void unnecessary_copy_emplace_move_test(T*)
|
void unnecessary_copy_emplace_move_test(T*)
|
||||||
{
|
{
|
||||||
@ -162,11 +182,51 @@ namespace unnecessary_copy_tests
|
|||||||
|
|
||||||
UNORDERED_TEST(unnecessary_copy_emplace_move_test,
|
UNORDERED_TEST(unnecessary_copy_emplace_move_test,
|
||||||
((set)(multiset)(map)(multimap)))
|
((set)(multiset)(map)(multimap)))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void unnecessary_copy_emplace_boost_move_set_test(T*)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
T x;
|
||||||
|
BOOST_DEDUCED_TYPENAME T::value_type a;
|
||||||
|
COPY_COUNT(1); MOVE_COUNT(0);
|
||||||
|
x.emplace(boost::move(a));
|
||||||
|
COPY_COUNT(1); MOVE_COUNT(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_TEST(unnecessary_copy_emplace_boost_move_set_test,
|
||||||
|
((set)(multiset)))
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void unnecessary_copy_emplace_boost_move_map_test(T*)
|
||||||
|
{
|
||||||
|
reset();
|
||||||
|
T x;
|
||||||
|
BOOST_DEDUCED_TYPENAME T::value_type a;
|
||||||
|
COPY_COUNT(1); MOVE_COUNT(0);
|
||||||
|
x.emplace(boost::move(a));
|
||||||
|
#if defined(BOOST_NO_RVALUE_REFERENCES)
|
||||||
|
COPY_COUNT(2); MOVE_COUNT(0);
|
||||||
|
#else
|
||||||
|
COPY_COUNT(1); MOVE_COUNT(1);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
UNORDERED_TEST(unnecessary_copy_emplace_boost_move_map_test,
|
||||||
|
((map)(multimap)))
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
|
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_set_test)
|
||||||
{
|
{
|
||||||
|
// When calling 'source' the object is moved on some compilers, but not
|
||||||
|
// others. So count that here to adjust later.
|
||||||
|
|
||||||
|
reset();
|
||||||
|
source<count_copies>();
|
||||||
|
int source_cost = ::unnecessary_copy_tests::count_copies::moves;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
boost::unordered_set<count_copies> x;
|
boost::unordered_set<count_copies> x;
|
||||||
count_copies a;
|
count_copies a;
|
||||||
@ -181,7 +241,12 @@ namespace unnecessary_copy_tests
|
|||||||
// the existing element.
|
// the existing element.
|
||||||
reset();
|
reset();
|
||||||
x.emplace();
|
x.emplace();
|
||||||
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
COPY_COUNT(1); MOVE_COUNT(0);
|
COPY_COUNT(1); MOVE_COUNT(0);
|
||||||
|
#else
|
||||||
|
// source_cost doesn't make much sense here, but it seems to fit.
|
||||||
|
COPY_COUNT(1); MOVE_COUNT(source_cost);
|
||||||
|
#endif
|
||||||
|
|
||||||
//
|
//
|
||||||
// 1 argument
|
// 1 argument
|
||||||
@ -197,9 +262,9 @@ namespace unnecessary_copy_tests
|
|||||||
// copied.
|
// copied.
|
||||||
reset();
|
reset();
|
||||||
x.emplace(source<count_copies>());
|
x.emplace(source<count_copies>());
|
||||||
COPY_COUNT(1); MOVE_COUNT(0);
|
COPY_COUNT(1); MOVE_COUNT(source_cost);
|
||||||
|
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
// No move should take place.
|
// No move should take place.
|
||||||
reset();
|
reset();
|
||||||
x.emplace(std::move(a));
|
x.emplace(std::move(a));
|
||||||
@ -233,6 +298,19 @@ namespace unnecessary_copy_tests
|
|||||||
|
|
||||||
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
|
UNORDERED_AUTO_TEST(unnecessary_copy_emplace_map_test)
|
||||||
{
|
{
|
||||||
|
// When calling 'source' the object is moved on some compilers, but not
|
||||||
|
// others. So count that here to adjust later.
|
||||||
|
|
||||||
|
reset();
|
||||||
|
source<count_copies>();
|
||||||
|
int source_cost = ::unnecessary_copy_tests::count_copies::moves;
|
||||||
|
|
||||||
|
reset();
|
||||||
|
source<std::pair<count_copies, count_copies> >();
|
||||||
|
int source_pair_cost = ::unnecessary_copy_tests::count_copies::moves;
|
||||||
|
|
||||||
|
//
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
boost::unordered_map<count_copies, count_copies> x;
|
boost::unordered_map<count_copies, count_copies> x;
|
||||||
// TODO: Run tests for pairs without const etc.
|
// TODO: Run tests for pairs without const etc.
|
||||||
@ -261,17 +339,17 @@ namespace unnecessary_copy_tests
|
|||||||
// copied.
|
// copied.
|
||||||
reset();
|
reset();
|
||||||
x.emplace(source<std::pair<count_copies, count_copies> >());
|
x.emplace(source<std::pair<count_copies, count_copies> >());
|
||||||
COPY_COUNT(2); MOVE_COUNT_RANGE(0,2);
|
COPY_COUNT(2); MOVE_COUNT(source_pair_cost);
|
||||||
|
|
||||||
// TODO: This doesn't work on older versions of gcc.
|
#if !defined(__GNUC__) || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ > 2)
|
||||||
//count_copies part;
|
count_copies part;
|
||||||
std::pair<count_copies const, count_copies> b;
|
reset();
|
||||||
//reset();
|
std::pair<count_copies const&, count_copies const&> a_ref(part, part);
|
||||||
//std::pair<count_copies const&, count_copies const&> a_ref(part, part);
|
x.emplace(a_ref);
|
||||||
//x.emplace(a_ref);
|
COPY_COUNT(2); MOVE_COUNT(0);
|
||||||
//COPY_COUNT(0); MOVE_COUNT(0);
|
#endif
|
||||||
|
|
||||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||||
// No move should take place.
|
// No move should take place.
|
||||||
// (since a is already in the container)
|
// (since a is already in the container)
|
||||||
reset();
|
reset();
|
||||||
@ -279,23 +357,24 @@ namespace unnecessary_copy_tests
|
|||||||
COPY_COUNT(0); MOVE_COUNT(0);
|
COPY_COUNT(0); MOVE_COUNT(0);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// 2 arguments
|
// 2 arguments
|
||||||
//
|
//
|
||||||
|
|
||||||
|
std::pair<count_copies const, count_copies> b;
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
x.emplace(b.first, b.second);
|
x.emplace(b.first, b.second);
|
||||||
COPY_COUNT(0); MOVE_COUNT(0);
|
COPY_COUNT(0); MOVE_COUNT(0);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
x.emplace(source<count_copies>(), source<count_copies>());
|
x.emplace(source<count_copies>(), source<count_copies>());
|
||||||
COPY_COUNT(2); MOVE_COUNT(0);
|
COPY_COUNT(2); MOVE_COUNT(source_cost * 2);
|
||||||
|
|
||||||
// source<count_copies> creates a single copy.
|
// source<count_copies> creates a single copy.
|
||||||
reset();
|
reset();
|
||||||
x.emplace(b.first, source<count_copies>());
|
x.emplace(b.first, source<count_copies>());
|
||||||
COPY_COUNT(1); MOVE_COUNT(0);
|
COPY_COUNT(1); MOVE_COUNT(source_cost);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
|
x.emplace(count_copies(b.first.tag_), count_copies(b.second.tag_));
|
||||||
|
Reference in New Issue
Block a user