forked from boostorg/unordered
Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
251c4608d0 |
@@ -3,9 +3,6 @@
|
||||
/ Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
/ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) ]
|
||||
|
||||
[template ticket[number]'''<ulink
|
||||
url="https://svn.boost.org/trac/boost/ticket/'''[number]'''">'''#[number]'''</ulink>''']
|
||||
|
||||
[section:changes Change Log]
|
||||
|
||||
[h2 Review Version]
|
||||
@@ -202,22 +199,4 @@ C++11 support has resulted in some breaking changes:
|
||||
for 64 bit values.
|
||||
* Some internal changes.
|
||||
|
||||
[h2 Boost 1.51.0]
|
||||
|
||||
* Fix construction/destruction issue when using a C++11 compiler with a
|
||||
C++03 allocator ([ticket 7100]).
|
||||
* Remove a `try..catch` to support compiling without exceptions.
|
||||
* Adjust SFINAE use to try to supprt g++ 3.4 ([ticket 7175]).
|
||||
* Updated to use the new config macros.
|
||||
|
||||
[h2 Boost 1.52.0]
|
||||
|
||||
* Faster assign, which assigns to existing nodes where possible, rather than
|
||||
creating entirely new nodes and copy constructing.
|
||||
* Fixed bug in `erase_range` ([ticket 7471]).
|
||||
* Reverted some of the internal changes to how nodes are created, especially
|
||||
for C++11 compilers. 'construct' and 'destroy' should work a little better
|
||||
for C++11 allocators.
|
||||
* Simplified the implementation a bit. Hopefully more robust.
|
||||
|
||||
[endsect]
|
||||
|
||||
+3
-104
@@ -67,20 +67,14 @@ EOL;
|
||||
<?php if ($map): ?>
|
||||
<row>
|
||||
<entry><emphasis>Key</emphasis></entry>
|
||||
<entry><code>Key</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Key must be Assignable and CopyConstructible.</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Mapped</emphasis></entry>
|
||||
<entry><code>Mapped</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Mapped must be CopyConstructible</entry></row>
|
||||
<?php else: ?>
|
||||
<row>
|
||||
<entry><emphasis>Value</emphasis></entry>
|
||||
<entry><code>Value</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Value must be Assignable and CopyConstructible</entry></row>
|
||||
<?php endif ?>
|
||||
<row>
|
||||
<entry><emphasis>Hash</emphasis></entry>
|
||||
@@ -212,11 +206,6 @@ EOL;
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
@@ -248,11 +237,6 @@ EOL;
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter>
|
||||
@@ -424,11 +408,6 @@ EOL;
|
||||
' if and only if there is no element in the container with an equivalent '.$key_name. '.';
|
||||
?></para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
@@ -474,11 +453,6 @@ EOL;
|
||||
?></para>
|
||||
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
@@ -516,39 +490,6 @@ EOL;
|
||||
' if and only if there is no element in the container with an equivalent '.$key_name. '.';
|
||||
?></para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
<?php else: ?>
|
||||
<para>The bool component of the return type is true if an insert took place.</para>
|
||||
<para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent <?php echo $key_name; ?>.</para>
|
||||
<?php endif; ?>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type><?php echo $equivalent_keys ? 'iterator' : 'std::pair<iterator, bool>' ?></type>
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container<?php
|
||||
echo $equivalent_keys ? '.' :
|
||||
' if and only if there is no element in the container with an equivalent '.$key_name. '.';
|
||||
?></para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
@@ -581,44 +522,6 @@ EOL;
|
||||
<?php endif; ?>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
<?php else: ?>
|
||||
<para>If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent <?php echo $key_name; ?>.</para>
|
||||
<?php endif; ?>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same <?php echo $key_name; ?>. </para>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
<?php else: ?>
|
||||
<para>Inserts <code>obj</code> in the container if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.</para>
|
||||
<?php endif; ?>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
@@ -650,10 +553,6 @@ EOL;
|
||||
<description>
|
||||
<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 <?php echo $key_name; ?>.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</throws>
|
||||
|
||||
+6
-336
@@ -29,9 +29,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><emphasis>Value</emphasis></entry>
|
||||
<entry><code>Value</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Value must be Assignable and CopyConstructible</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Hash</emphasis></entry>
|
||||
<entry>A unary function object type that acts a hash function for a <code>Value</code>. It takes a single argument of type <code>Value</code> and returns a value of type std::size_t.</entry></row>
|
||||
@@ -153,11 +151,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
@@ -189,11 +182,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter>
|
||||
@@ -362,11 +350,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<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>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>The bool component of the return type is true if an insert took place.</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>
|
||||
@@ -405,11 +388,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<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><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<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>
|
||||
</returns>
|
||||
@@ -440,32 +418,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>The bool component of the return type is true if an insert took place.</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>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>std::pair<iterator, bool></type>
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>The bool component of the return type is true if an insert took place.</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>
|
||||
@@ -490,36 +442,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<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>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same value. </para>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<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>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</returns>
|
||||
@@ -547,10 +469,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</throws>
|
||||
@@ -1076,9 +994,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><emphasis>Value</emphasis></entry>
|
||||
<entry><code>Value</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Value must be Assignable and CopyConstructible</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Hash</emphasis></entry>
|
||||
<entry>A unary function object type that acts a hash function for a <code>Value</code>. It takes a single argument of type <code>Value</code> and returns a value of type std::size_t.</entry></row>
|
||||
@@ -1200,11 +1116,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
@@ -1236,11 +1147,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter>
|
||||
@@ -1409,11 +1315,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -1451,11 +1352,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
||||
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -1486,31 +1382,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -1534,36 +1405,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same value. </para>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -1591,10 +1432,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</throws>
|
||||
@@ -2126,14 +1963,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><emphasis>Key</emphasis></entry>
|
||||
<entry><code>Key</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Key must be Assignable and CopyConstructible.</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Mapped</emphasis></entry>
|
||||
<entry><code>Mapped</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Mapped must be CopyConstructible</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Hash</emphasis></entry>
|
||||
<entry>A unary function object type that acts a hash function for a <code>Key</code>. It takes a single argument of type <code>Key</code> and returns a value of type std::size_t.</entry></row>
|
||||
@@ -2258,11 +2091,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
@@ -2294,11 +2122,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter>
|
||||
@@ -2467,11 +2290,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<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>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>The bool component of the return type is true if an insert took place.</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>
|
||||
@@ -2510,11 +2328,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<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><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<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>
|
||||
</returns>
|
||||
@@ -2545,32 +2358,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>The bool component of the return type is true if an insert took place.</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>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>std::pair<iterator, bool></type>
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>The bool component of the return type is true if an insert took place.</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>
|
||||
@@ -2595,36 +2382,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<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>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. </para>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<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>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</returns>
|
||||
@@ -2652,10 +2409,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</throws>
|
||||
@@ -3220,14 +2973,10 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><emphasis>Key</emphasis></entry>
|
||||
<entry><code>Key</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Key must be Assignable and CopyConstructible.</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Mapped</emphasis></entry>
|
||||
<entry><code>Mapped</code> must be <code>Erasable</code> from the container
|
||||
(i.e. <code>allocator_traits</code> can <code>destroy</code> it).
|
||||
</entry></row>
|
||||
<entry>Mapped must be CopyConstructible</entry></row>
|
||||
<row>
|
||||
<entry><emphasis>Hash</emphasis></entry>
|
||||
<entry>A unary function object type that acts a hash function for a <code>Key</code>. It takes a single argument of type <code>Key</code> and returns a value of type std::size_t.</entry></row>
|
||||
@@ -3352,11 +3101,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<template>
|
||||
@@ -3388,11 +3132,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Constructs an empty container with at least n buckets, using hf as the hash function, eq as the key equality predicate, a as the allocator and a maximum load factor of 1.0 and inserts the elements from [f, l) into it.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para>If the defaults are used, <code>hasher</code>, <code>key_equal</code> and
|
||||
<code>allocator_type</code> need to be <code>DefaultConstructible</code>.
|
||||
</para>
|
||||
</requires>
|
||||
</constructor>
|
||||
<constructor>
|
||||
<parameter>
|
||||
@@ -3561,11 +3300,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -3603,11 +3337,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Inserts an object, constructed with the arguments <code>args</code>, in the container.</para>
|
||||
<para><code>hint</code> is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>args</code>.
|
||||
</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -3638,31 +3367,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -3686,36 +3390,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>CopyInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>If an exception is thrown by an operation other than a call to <code>hasher</code> the function has no effect.</para>
|
||||
</throws>
|
||||
<notes>
|
||||
<para>The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. </para>
|
||||
<para>Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor.</para>
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="obj">
|
||||
<paramtype>value_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>Inserts <code>obj</code> in the container.</para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>MoveInsertable</code>.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>An iterator pointing to the inserted element.</para>
|
||||
</returns>
|
||||
@@ -3743,10 +3417,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<description>
|
||||
<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>
|
||||
<requires>
|
||||
<para><code>value_type</code> is <code>EmplaceConstructible</code> into
|
||||
<code>X</code> from <code>*first</code>.</para>
|
||||
</requires>
|
||||
<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>
|
||||
</throws>
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,723 @@
|
||||
|
||||
// Copyright 2005-2011 Daniel James.
|
||||
// Copyright 2009 Pablo Halpern.
|
||||
//
|
||||
// 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)
|
||||
//
|
||||
// Allocator traits written by Daniel James based on Pablo Halpern's
|
||||
// implementation.
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_DETAIL_ALLOCATOR_UTILITIES_HPP_INCLUDED
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/emplace_args.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/utility/addressof.hpp>
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Pick which version of allocator_traits to use
|
||||
//
|
||||
// 0 = Own partial implementation
|
||||
// 1 = std::allocator_traits
|
||||
// 2 = boost::container::allocator_traits
|
||||
|
||||
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
|
||||
# if defined(__GXX_EXPERIMENTAL_CXX0X__) && \
|
||||
(__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 7))
|
||||
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 1
|
||||
# elif defined(BOOST_MSVC)
|
||||
# if BOOST_MSVC < 1400
|
||||
// Use container's allocator_traits for older versions of Visual
|
||||
// C++ as I don't test with them.
|
||||
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 2
|
||||
# endif
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_UNORDERED_USE_ALLOCATOR_TRAITS)
|
||||
# define BOOST_UNORDERED_USE_ALLOCATOR_TRAITS 0
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Some utilities for implementing allocator_traits, but useful elsewhere so
|
||||
// they're always defined.
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
|
||||
# include <type_traits>
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Integral_constrant, true_type, false_type
|
||||
//
|
||||
// Uses the standard versions if available.
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TYPE_TRAITS)
|
||||
|
||||
using std::integral_constant;
|
||||
using std::true_type;
|
||||
using std::false_type;
|
||||
|
||||
#else
|
||||
|
||||
template <typename T, T Value>
|
||||
struct integral_constant { enum { value = Value }; };
|
||||
|
||||
typedef boost::unordered::detail::integral_constant<bool, true> true_type;
|
||||
typedef boost::unordered::detail::integral_constant<bool, false> false_type;
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// 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
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Expression test mechanism
|
||||
//
|
||||
// When SFINAE expressions are available, define
|
||||
// BOOST_UNORDERED_HAS_FUNCTION which can check if a function call is
|
||||
// supported by a class, otherwise define BOOST_UNORDERED_HAS_MEMBER which
|
||||
// can detect if a class has the specified member, but not that it has the
|
||||
// correct type, this is good enough for a passable impression of
|
||||
// allocator_traits.
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE_EXPR)
|
||||
|
||||
template <typename T, unsigned int> struct expr_test;
|
||||
template <typename T> struct expr_test<T, sizeof(char)> : T {};
|
||||
template <typename U> static char for_expr_test(U const&);
|
||||
|
||||
# define BOOST_UNORDERED_CHECK_EXPRESSION(count, result, expression) \
|
||||
template <typename U> \
|
||||
static typename boost::unordered::detail::expr_test< \
|
||||
BOOST_PP_CAT(choice, result), \
|
||||
sizeof(boost::unordered::detail::for_expr_test(( \
|
||||
(expression), \
|
||||
0)))>::type test( \
|
||||
BOOST_PP_CAT(choice, count))
|
||||
|
||||
# define BOOST_UNORDERED_DEFAULT_EXPRESSION(count, result) \
|
||||
template <typename U> \
|
||||
static BOOST_PP_CAT(choice, result)::type test( \
|
||||
BOOST_PP_CAT(choice, count))
|
||||
|
||||
# define BOOST_UNORDERED_HAS_FUNCTION(name, thing, args, _) \
|
||||
struct BOOST_PP_CAT(has_, name) \
|
||||
{ \
|
||||
BOOST_UNORDERED_CHECK_EXPRESSION(1, 1, \
|
||||
boost::unordered::detail::make< thing >().name args); \
|
||||
BOOST_UNORDERED_DEFAULT_EXPRESSION(2, 2); \
|
||||
\
|
||||
enum { value = sizeof(test<T>(choose())) == sizeof(choice1::type) };\
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename T> struct identity { typedef T type; };
|
||||
|
||||
# define BOOST_UNORDERED_CHECK_MEMBER(count, result, name, member) \
|
||||
\
|
||||
typedef typename boost::unordered::detail::identity<member>::type \
|
||||
BOOST_PP_CAT(check, count); \
|
||||
\
|
||||
template <BOOST_PP_CAT(check, count) e> \
|
||||
struct BOOST_PP_CAT(test, count) { \
|
||||
typedef BOOST_PP_CAT(choice, result) type; \
|
||||
}; \
|
||||
\
|
||||
template <class U> static typename \
|
||||
BOOST_PP_CAT(test, count)<&U::name>::type \
|
||||
test(BOOST_PP_CAT(choice, count))
|
||||
|
||||
# define BOOST_UNORDERED_DEFAULT_MEMBER(count, result) \
|
||||
template <class U> static BOOST_PP_CAT(choice, result)::type \
|
||||
test(BOOST_PP_CAT(choice, count))
|
||||
|
||||
# define BOOST_UNORDERED_HAS_MEMBER(name) \
|
||||
struct BOOST_PP_CAT(has_, name) \
|
||||
{ \
|
||||
struct impl { \
|
||||
struct base_mixin { int name; }; \
|
||||
struct base : public T, public base_mixin {}; \
|
||||
\
|
||||
BOOST_UNORDERED_CHECK_MEMBER(1, 1, name, int base_mixin::*); \
|
||||
BOOST_UNORDERED_DEFAULT_MEMBER(2, 2); \
|
||||
\
|
||||
enum { value = sizeof(choice2::type) == \
|
||||
sizeof(test<base>(choose())) \
|
||||
}; \
|
||||
}; \
|
||||
\
|
||||
enum { value = impl::value }; \
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
}}}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Allocator traits
|
||||
//
|
||||
// First our implementation, then later light wrappers around the alternatives
|
||||
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 0
|
||||
|
||||
# include <boost/limits.hpp>
|
||||
# include <boost/utility/enable_if.hpp>
|
||||
# include <boost/pointer_to_other.hpp>
|
||||
# if defined(BOOST_NO_SFINAE_EXPR)
|
||||
# include <boost/type_traits/is_same.hpp>
|
||||
# endif
|
||||
|
||||
# if defined(BOOST_UNORDERED_VARIADIC_MOVE) && \
|
||||
!defined(BOOST_NO_SFINAE_EXPR)
|
||||
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
|
||||
# else
|
||||
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
|
||||
# endif
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
// TODO: Does this match std::allocator_traits<Alloc>::rebind_alloc<T>?
|
||||
template <typename Alloc, typename T>
|
||||
struct rebind_wrap
|
||||
{
|
||||
typedef typename Alloc::BOOST_NESTED_TEMPLATE rebind<T>::other type;
|
||||
};
|
||||
|
||||
# if defined(BOOST_MSVC) && BOOST_MSVC <= 1400
|
||||
|
||||
# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
|
||||
template <typename Tp, typename Default> \
|
||||
struct default_type_ ## tname { \
|
||||
\
|
||||
template <typename X> \
|
||||
static choice1::type test(choice1, typename X::tname* = 0); \
|
||||
\
|
||||
template <typename X> \
|
||||
static choice2::type test(choice2, void* = 0); \
|
||||
\
|
||||
struct DefaultWrap { typedef Default tname; }; \
|
||||
\
|
||||
enum { value = (1 == sizeof(test<Tp>(choose()))) }; \
|
||||
\
|
||||
typedef typename boost::detail::if_true<value>:: \
|
||||
BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
|
||||
::type::tname type; \
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
template <typename T, typename T2>
|
||||
struct sfinae : T2 {};
|
||||
|
||||
# define BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(tname) \
|
||||
template <typename Tp, typename Default> \
|
||||
struct default_type_ ## tname { \
|
||||
\
|
||||
template <typename X> \
|
||||
static typename boost::unordered::detail::sfinae< \
|
||||
typename X::tname, choice1>::type \
|
||||
test(choice1); \
|
||||
\
|
||||
template <typename X> \
|
||||
static choice2::type test(choice2); \
|
||||
\
|
||||
struct DefaultWrap { typedef Default tname; }; \
|
||||
\
|
||||
enum { value = (1 == sizeof(test<Tp>(choose()))) }; \
|
||||
\
|
||||
typedef typename boost::detail::if_true<value>:: \
|
||||
BOOST_NESTED_TEMPLATE then<Tp, DefaultWrap> \
|
||||
::type::tname type; \
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
# define BOOST_UNORDERED_DEFAULT_TYPE(T,tname, arg) \
|
||||
typename default_type_ ## tname<T, arg>::type
|
||||
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(void_pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(const_void_pointer);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(difference_type);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(size_type);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_copy_assignment);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_move_assignment);
|
||||
BOOST_UNORDERED_DEFAULT_TYPE_TMPLT(propagate_on_container_swap);
|
||||
|
||||
# if !defined(BOOST_NO_SFINAE_EXPR)
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
select_on_container_copy_construction, U const, (), 0
|
||||
);
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
max_size, U const, (), 0
|
||||
);
|
||||
|
||||
# if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
|
||||
template <typename T, typename ValueType, typename... Args>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
construct, U, (
|
||||
boost::unordered::detail::make<ValueType*>(),
|
||||
boost::unordered::detail::make<Args const>()...), 2
|
||||
);
|
||||
|
||||
# else
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
construct, U, (
|
||||
boost::unordered::detail::make<ValueType*>(),
|
||||
boost::unordered::detail::make<ValueType const>()), 2
|
||||
);
|
||||
|
||||
# endif
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_FUNCTION(
|
||||
destroy, U, (boost::unordered::detail::make<ValueType*>()), 1
|
||||
);
|
||||
|
||||
# else
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_MEMBER(select_on_container_copy_construction);
|
||||
|
||||
template <typename T>
|
||||
BOOST_UNORDERED_HAS_MEMBER(max_size);
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_MEMBER(construct);
|
||||
|
||||
template <typename T, typename ValueType>
|
||||
BOOST_UNORDERED_HAS_MEMBER(destroy);
|
||||
|
||||
# endif
|
||||
|
||||
template <typename Alloc>
|
||||
inline typename boost::enable_if_c<
|
||||
boost::unordered::detail::
|
||||
has_select_on_container_copy_construction<Alloc>::value, Alloc
|
||||
>::type call_select_on_container_copy_construction(const Alloc& rhs)
|
||||
{
|
||||
return rhs.select_on_container_copy_construction();
|
||||
}
|
||||
|
||||
template <typename Alloc>
|
||||
inline typename boost::disable_if_c<
|
||||
boost::unordered::detail::
|
||||
has_select_on_container_copy_construction<Alloc>::value, Alloc
|
||||
>::type call_select_on_container_copy_construction(const Alloc& rhs)
|
||||
{
|
||||
return rhs;
|
||||
}
|
||||
|
||||
template <typename SizeType, typename Alloc>
|
||||
inline typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_max_size<Alloc>::value, SizeType
|
||||
>::type call_max_size(const Alloc& a)
|
||||
{
|
||||
return a.max_size();
|
||||
}
|
||||
|
||||
template <typename SizeType, typename Alloc>
|
||||
inline typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_max_size<Alloc>::value, SizeType
|
||||
>::type call_max_size(const Alloc&)
|
||||
{
|
||||
return (std::numeric_limits<SizeType>::max)();
|
||||
}
|
||||
|
||||
template <typename Alloc>
|
||||
struct allocator_traits
|
||||
{
|
||||
typedef Alloc allocator_type;
|
||||
typedef typename Alloc::value_type value_type;
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, pointer, value_type*)
|
||||
pointer;
|
||||
|
||||
template <typename T>
|
||||
struct pointer_to_other : boost::pointer_to_other<pointer, T> {};
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_pointer,
|
||||
typename pointer_to_other<const value_type>::type)
|
||||
const_pointer;
|
||||
|
||||
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, void_pointer,
|
||||
// typename pointer_to_other<void>::type)
|
||||
// void_pointer;
|
||||
//
|
||||
//typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, const_void_pointer,
|
||||
// typename pointer_to_other<const void>::type)
|
||||
// const_void_pointer;
|
||||
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(Alloc, difference_type,
|
||||
std::ptrdiff_t) difference_type;
|
||||
|
||||
typedef BOOST_UNORDERED_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); }
|
||||
|
||||
public:
|
||||
|
||||
# if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T, Args...>
|
||||
::value>::type
|
||||
construct(Alloc& a, T* p, Args&&... x)
|
||||
{
|
||||
a.construct(p, boost::forward<Args>(x)...);
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T, Args...>
|
||||
::value>::type
|
||||
construct(Alloc&, T* p, Args&&... x)
|
||||
{
|
||||
new ((void*) p) T(boost::forward<Args>(x)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc& a, T* p)
|
||||
{
|
||||
a.destroy(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc&, T* p)
|
||||
{
|
||||
boost::unordered::detail::destroy(p);
|
||||
}
|
||||
|
||||
# elif !defined(BOOST_NO_SFINAE_EXPR)
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value>::type
|
||||
construct(Alloc& a, T* p, T const& x)
|
||||
{
|
||||
a.construct(p, x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value>::type
|
||||
construct(Alloc&, T* p, T const& x)
|
||||
{
|
||||
new ((void*) p) T(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc& a, T* p)
|
||||
{
|
||||
a.destroy(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value>::type
|
||||
destroy(Alloc&, T* p)
|
||||
{
|
||||
boost::unordered::detail::destroy(p);
|
||||
}
|
||||
|
||||
# else
|
||||
|
||||
// If we don't have SFINAE expressions, only call construct for the
|
||||
// copy constructor for the allocator's value_type - as that's
|
||||
// the only construct method that old fashioned allocators support.
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value
|
||||
>::type
|
||||
construct(Alloc& a, T* p, T const& x)
|
||||
{
|
||||
a.construct(p, x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_construct<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value
|
||||
>::type
|
||||
construct(Alloc&, T* p, T const& x)
|
||||
{
|
||||
new ((void*) p) T(x);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::enable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value
|
||||
>::type
|
||||
destroy(Alloc& a, T* p)
|
||||
{
|
||||
a.destroy(p);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
static typename boost::disable_if_c<
|
||||
boost::unordered::detail::has_destroy<Alloc, T>::value &&
|
||||
boost::is_same<T, value_type>::value
|
||||
>::type
|
||||
destroy(Alloc&, T* p)
|
||||
{
|
||||
boost::unordered::detail::destroy(p);
|
||||
}
|
||||
|
||||
# endif
|
||||
|
||||
static size_type max_size(const Alloc& a)
|
||||
{
|
||||
return boost::unordered::detail::call_max_size<size_type>(a);
|
||||
}
|
||||
|
||||
// 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_UNORDERED_DEFAULT_TYPE(
|
||||
Alloc, propagate_on_container_copy_assignment, false_type)
|
||||
propagate_on_container_copy_assignment;
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(
|
||||
Alloc,propagate_on_container_move_assignment, false_type)
|
||||
propagate_on_container_move_assignment;
|
||||
typedef BOOST_UNORDERED_DEFAULT_TYPE(
|
||||
Alloc,propagate_on_container_swap,false_type)
|
||||
propagate_on_container_swap;
|
||||
};
|
||||
}}}
|
||||
|
||||
# undef BOOST_UNORDERED_DEFAULT_TYPE_TMPLT
|
||||
# undef BOOST_UNORDERED_DEFAULT_TYPE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// std::allocator_traits
|
||||
|
||||
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
|
||||
# include <memory>
|
||||
|
||||
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 1
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename Alloc>
|
||||
struct allocator_traits : std::allocator_traits<Alloc> {};
|
||||
|
||||
template <typename Alloc, typename T>
|
||||
struct rebind_wrap
|
||||
{
|
||||
typedef typename std::allocator_traits<Alloc>::
|
||||
template rebind_alloc<T> type;
|
||||
};
|
||||
}}}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// boost::container::allocator_traits
|
||||
|
||||
#elif BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 2
|
||||
|
||||
# include <boost/container/allocator_traits.hpp>
|
||||
|
||||
# define BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT 0
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename Alloc>
|
||||
struct allocator_traits :
|
||||
boost::container::allocator_traits<Alloc> {};
|
||||
|
||||
template <typename Alloc, typename T>
|
||||
struct rebind_wrap :
|
||||
boost::container::allocator_traits<Alloc>::
|
||||
template portable_rebind_alloc<T>
|
||||
{};
|
||||
|
||||
}}}
|
||||
|
||||
#else
|
||||
|
||||
#error "Invalid BOOST_UNORDERED_USE_ALLOCATOR_TRAITS value."
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Some helper functions for allocating & constructing
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// construct_node/destroy_node
|
||||
//
|
||||
// Construct a node using the best available method.
|
||||
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
|
||||
template <typename Alloc, typename T, BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(
|
||||
a, p, BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
}
|
||||
|
||||
template <typename Alloc, typename T>
|
||||
inline void destroy_node(Alloc& a, T* p)
|
||||
{
|
||||
boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <typename Alloc, typename T, BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
inline void construct_node(Alloc& a, T* p, BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
boost::unordered::detail::allocator_traits<Alloc>::construct(a, p, T());
|
||||
try {
|
||||
boost::unordered::detail::construct_impl(
|
||||
p->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
} catch(...) {
|
||||
boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Alloc, typename T>
|
||||
inline void destroy_node(Alloc& a, T* p)
|
||||
{
|
||||
boost::unordered::detail::destroy(p->value_ptr());
|
||||
boost::unordered::detail::allocator_traits<Alloc>::destroy(a, p);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// array_constructor
|
||||
//
|
||||
// Allocate and construct an array in an exception safe manner, and
|
||||
// clean up if an exception is thrown before the container takes charge
|
||||
// of it.
|
||||
|
||||
template <typename Allocator>
|
||||
struct array_constructor
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<Allocator> traits;
|
||||
typedef typename traits::pointer pointer;
|
||||
|
||||
Allocator& alloc_;
|
||||
pointer ptr_;
|
||||
pointer constructed_;
|
||||
std::size_t length_;
|
||||
|
||||
array_constructor(Allocator& a)
|
||||
: alloc_(a), ptr_(), constructed_(), length_(0)
|
||||
{
|
||||
constructed_ = pointer();
|
||||
ptr_ = pointer();
|
||||
}
|
||||
|
||||
~array_constructor() {
|
||||
if (ptr_) {
|
||||
for(pointer p = ptr_; p != constructed_; ++p)
|
||||
traits::destroy(alloc_, boost::addressof(*p));
|
||||
|
||||
traits::deallocate(alloc_, ptr_, length_);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename V>
|
||||
void construct(V const& v, std::size_t l)
|
||||
{
|
||||
BOOST_ASSERT(!ptr_);
|
||||
length_ = l;
|
||||
ptr_ = traits::allocate(alloc_, length_);
|
||||
pointer end = ptr_ + static_cast<std::ptrdiff_t>(length_);
|
||||
for(constructed_ = ptr_; constructed_ != end; ++constructed_)
|
||||
traits::construct(alloc_, boost::addressof(*constructed_), v);
|
||||
}
|
||||
|
||||
pointer get() const
|
||||
{
|
||||
return ptr_;
|
||||
}
|
||||
|
||||
pointer release()
|
||||
{
|
||||
pointer p(ptr_);
|
||||
ptr_ = pointer();
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
array_constructor(array_constructor const&);
|
||||
array_constructor& operator=(array_constructor const&);
|
||||
};
|
||||
}}}
|
||||
|
||||
#endif
|
||||
@@ -12,7 +12,7 @@
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
#include <boost/unordered/detail/allocate.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <boost/swap.hpp>
|
||||
@@ -20,14 +20,175 @@
|
||||
#include <boost/limits.hpp>
|
||||
#include <boost/iterator.hpp>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename Types> struct table;
|
||||
template <typename NodePointer> struct bucket;
|
||||
struct ptr_bucket;
|
||||
template <typename A, typename Bucket, typename Node, typename Policy>
|
||||
struct buckets;
|
||||
template <typename Types> struct table_impl;
|
||||
template <typename Types> struct grouped_table_impl;
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Node construction
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct node_constructor
|
||||
{
|
||||
private:
|
||||
|
||||
typedef NodeAlloc node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::value_type node;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
typedef typename node::value_type value_type;
|
||||
|
||||
node_allocator& alloc_;
|
||||
node_pointer node_;
|
||||
bool constructed_;
|
||||
|
||||
public:
|
||||
|
||||
node_constructor(node_allocator& n) :
|
||||
alloc_(n),
|
||||
node_(),
|
||||
constructed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
~node_constructor();
|
||||
|
||||
void construct_node();
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
void construct_value(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
BOOST_ASSERT(node_ && !constructed_);
|
||||
boost::unordered::detail::construct_node(alloc_,
|
||||
boost::addressof(*node_), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
node_->init(static_cast<typename node::link_pointer>(node_));
|
||||
constructed_ = true;
|
||||
}
|
||||
|
||||
template <typename A0>
|
||||
void construct_value2(BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
BOOST_ASSERT(node_ && !constructed_);
|
||||
# if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
boost::unordered::detail::construct_node(alloc_,
|
||||
boost::addressof(*node_), boost::forward<A0>(a0));
|
||||
# else
|
||||
boost::unordered::detail::construct_node(alloc_,
|
||||
boost::addressof(*node_),
|
||||
boost::unordered::detail::create_emplace_args(
|
||||
boost::forward<A0>(a0)));
|
||||
# endif
|
||||
constructed_ = true;
|
||||
node_->init(static_cast<typename node::link_pointer>(node_));
|
||||
}
|
||||
|
||||
value_type const& value() const {
|
||||
BOOST_ASSERT(node_ && constructed_);
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
node_pointer get()
|
||||
{
|
||||
return node_;
|
||||
}
|
||||
|
||||
// no throw
|
||||
node_pointer release()
|
||||
{
|
||||
node_pointer p = node_;
|
||||
node_ = node_pointer();
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
node_constructor(node_constructor const&);
|
||||
node_constructor& operator=(node_constructor const&);
|
||||
};
|
||||
|
||||
template <typename Alloc>
|
||||
node_constructor<Alloc>::~node_constructor()
|
||||
{
|
||||
if (node_) {
|
||||
if (constructed_) {
|
||||
boost::unordered::detail::destroy_node(alloc_,
|
||||
boost::addressof(*node_));
|
||||
}
|
||||
|
||||
node_allocator_traits::deallocate(alloc_, node_, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Alloc>
|
||||
void node_constructor<Alloc>::construct_node()
|
||||
{
|
||||
if(!node_) {
|
||||
constructed_ = false;
|
||||
node_ = node_allocator_traits::allocate(alloc_, 1);
|
||||
}
|
||||
else if (constructed_) {
|
||||
boost::unordered::detail::destroy_node(alloc_,
|
||||
boost::addressof(*node_));
|
||||
constructed_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bucket
|
||||
|
||||
template <typename NodePointer>
|
||||
struct bucket
|
||||
{
|
||||
typedef NodePointer previous_pointer;
|
||||
previous_pointer next_;
|
||||
|
||||
bucket() : next_() {}
|
||||
|
||||
previous_pointer first_from_start()
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
enum { extra_node = true };
|
||||
};
|
||||
|
||||
struct ptr_bucket
|
||||
{
|
||||
typedef ptr_bucket* previous_pointer;
|
||||
previous_pointer next_;
|
||||
|
||||
ptr_bucket() : next_(0) {}
|
||||
|
||||
previous_pointer first_from_start()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
enum { extra_node = false };
|
||||
};
|
||||
|
||||
template <typename LinkPointer>
|
||||
struct node_base
|
||||
{
|
||||
typedef LinkPointer link_pointer;
|
||||
link_pointer next_;
|
||||
|
||||
node_base() : next_() {}
|
||||
};
|
||||
|
||||
}}}
|
||||
|
||||
namespace boost { namespace unordered { namespace iterator_detail {
|
||||
@@ -183,6 +344,8 @@ namespace boost { namespace unordered { namespace iterator_detail {
|
||||
friend struct boost::unordered::iterator_detail::cl_iterator;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table;
|
||||
template <typename, typename, typename, typename>
|
||||
friend struct boost::unordered::detail::buckets;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table_impl;
|
||||
template <typename>
|
||||
@@ -238,6 +401,8 @@ namespace boost { namespace unordered { namespace iterator_detail {
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table;
|
||||
template <typename, typename, typename, typename>
|
||||
friend struct boost::unordered::detail::buckets;
|
||||
template <typename>
|
||||
friend struct boost::unordered::detail::table_impl;
|
||||
template <typename>
|
||||
@@ -291,285 +456,11 @@ namespace boost { namespace unordered { namespace iterator_detail {
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Node construction
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct node_constructor
|
||||
{
|
||||
private:
|
||||
|
||||
typedef NodeAlloc node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::value_type node;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
typedef typename node::value_type value_type;
|
||||
|
||||
protected:
|
||||
|
||||
node_allocator& alloc_;
|
||||
|
||||
private:
|
||||
|
||||
node_pointer node_;
|
||||
bool node_constructed_;
|
||||
bool value_constructed_;
|
||||
|
||||
public:
|
||||
|
||||
node_constructor(node_allocator& n) :
|
||||
alloc_(n),
|
||||
node_(),
|
||||
node_constructed_(false),
|
||||
value_constructed_(false)
|
||||
{
|
||||
}
|
||||
|
||||
~node_constructor();
|
||||
|
||||
void construct();
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
void construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
construct();
|
||||
boost::unordered::detail::construct_value_impl(
|
||||
alloc_, node_->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
value_constructed_ = true;
|
||||
}
|
||||
|
||||
template <typename A0>
|
||||
void construct_with_value2(BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
construct();
|
||||
boost::unordered::detail::construct_value_impl(
|
||||
alloc_, node_->value_ptr(),
|
||||
BOOST_UNORDERED_EMPLACE_ARGS1(boost::forward<A0>(a0)));
|
||||
value_constructed_ = true;
|
||||
}
|
||||
|
||||
value_type const& value() const {
|
||||
BOOST_ASSERT(node_ && node_constructed_ && value_constructed_);
|
||||
return node_->value();
|
||||
}
|
||||
|
||||
// no throw
|
||||
node_pointer release()
|
||||
{
|
||||
BOOST_ASSERT(node_ && node_constructed_);
|
||||
node_pointer p = node_;
|
||||
node_ = node_pointer();
|
||||
return p;
|
||||
}
|
||||
|
||||
private:
|
||||
node_constructor(node_constructor const&);
|
||||
node_constructor& operator=(node_constructor const&);
|
||||
};
|
||||
|
||||
template <typename Alloc>
|
||||
node_constructor<Alloc>::~node_constructor()
|
||||
{
|
||||
if (node_) {
|
||||
if (value_constructed_) {
|
||||
boost::unordered::detail::destroy_value_impl(alloc_,
|
||||
node_->value_ptr());
|
||||
}
|
||||
|
||||
if (node_constructed_) {
|
||||
node_allocator_traits::destroy(alloc_,
|
||||
boost::addressof(*node_));
|
||||
}
|
||||
|
||||
node_allocator_traits::deallocate(alloc_, node_, 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Alloc>
|
||||
void node_constructor<Alloc>::construct()
|
||||
{
|
||||
if(!node_) {
|
||||
node_constructed_ = false;
|
||||
value_constructed_ = false;
|
||||
|
||||
node_ = node_allocator_traits::allocate(alloc_, 1);
|
||||
|
||||
node_allocator_traits::construct(alloc_,
|
||||
boost::addressof(*node_), node());
|
||||
node_->init(static_cast<typename node::link_pointer>(node_));
|
||||
node_constructed_ = true;
|
||||
}
|
||||
else {
|
||||
BOOST_ASSERT(node_constructed_);
|
||||
|
||||
if (value_constructed_)
|
||||
{
|
||||
boost::unordered::detail::destroy_value_impl(alloc_,
|
||||
node_->value_ptr());
|
||||
value_constructed_ = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Node Holder
|
||||
//
|
||||
// Temporary store for nodes. Deletes any that aren't used.
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct node_holder : private node_constructor<NodeAlloc>
|
||||
{
|
||||
private:
|
||||
typedef node_constructor<NodeAlloc> base;
|
||||
|
||||
typedef NodeAlloc node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::value_type node;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
typedef typename node::value_type value_type;
|
||||
typedef typename node::link_pointer link_pointer;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
iterator<node_pointer, value_type> iterator;
|
||||
|
||||
node_pointer nodes_;
|
||||
|
||||
public:
|
||||
|
||||
template <typename Table>
|
||||
explicit node_holder(Table& b) :
|
||||
base(b.node_alloc()),
|
||||
nodes_()
|
||||
{
|
||||
if (b.size_) {
|
||||
typename Table::previous_pointer prev = b.get_previous_start();
|
||||
nodes_ = static_cast<node_pointer>(prev->next_);
|
||||
prev->next_ = link_pointer();
|
||||
b.size_ = 0;
|
||||
}
|
||||
}
|
||||
|
||||
~node_holder();
|
||||
|
||||
template <typename T>
|
||||
inline void assign_impl(T const& v) {
|
||||
nodes_->value() = v;
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline void assign_impl(std::pair<T1 const, T2> const& v) {
|
||||
const_cast<T1&>(nodes_->value().first) = v.first;
|
||||
nodes_->value().second = v.second;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline void move_assign_impl(T& v) {
|
||||
nodes_->value() = boost::move(v);
|
||||
}
|
||||
|
||||
template <typename T1, typename T2>
|
||||
inline void move_assign_impl(std::pair<T1 const, T2>& v) {
|
||||
// TODO: Move key as well?
|
||||
const_cast<T1&>(nodes_->value().first) =
|
||||
boost::move(const_cast<T1&>(v.first));
|
||||
nodes_->value().second = boost::move(v.second);
|
||||
}
|
||||
|
||||
node_pointer copy_of(value_type const& v)
|
||||
{
|
||||
if (nodes_) {
|
||||
assign_impl(v);
|
||||
node_pointer p = nodes_;
|
||||
nodes_ = static_cast<node_pointer>(p->next_);
|
||||
p->init(static_cast<typename node::link_pointer>(p));
|
||||
p->next_ = link_pointer();
|
||||
return p;
|
||||
}
|
||||
else {
|
||||
this->construct_with_value2(v);
|
||||
return base::release();
|
||||
}
|
||||
}
|
||||
|
||||
node_pointer move_copy_of(value_type& v)
|
||||
{
|
||||
if (nodes_) {
|
||||
move_assign_impl(v);
|
||||
node_pointer p = nodes_;
|
||||
nodes_ = static_cast<node_pointer>(p->next_);
|
||||
p->init(static_cast<typename node::link_pointer>(p));
|
||||
p->next_ = link_pointer();
|
||||
return p;
|
||||
}
|
||||
else {
|
||||
this->construct_with_value2(boost::move(v));
|
||||
return base::release();
|
||||
}
|
||||
}
|
||||
|
||||
iterator begin() const
|
||||
{
|
||||
return iterator(nodes_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Alloc>
|
||||
node_holder<Alloc>::~node_holder()
|
||||
{
|
||||
while (nodes_) {
|
||||
node_pointer p = nodes_;
|
||||
nodes_ = static_cast<node_pointer>(p->next_);
|
||||
|
||||
boost::unordered::detail::destroy_value_impl(this->alloc_,
|
||||
p->value_ptr());
|
||||
node_allocator_traits::destroy(this->alloc_, boost::addressof(*p));
|
||||
node_allocator_traits::deallocate(this->alloc_, p, 1);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Bucket
|
||||
|
||||
template <typename NodePointer>
|
||||
struct bucket
|
||||
{
|
||||
typedef NodePointer previous_pointer;
|
||||
previous_pointer next_;
|
||||
|
||||
bucket() : next_() {}
|
||||
|
||||
previous_pointer first_from_start()
|
||||
{
|
||||
return next_;
|
||||
}
|
||||
|
||||
enum { extra_node = true };
|
||||
};
|
||||
|
||||
struct ptr_bucket
|
||||
{
|
||||
typedef ptr_bucket* previous_pointer;
|
||||
previous_pointer next_;
|
||||
|
||||
ptr_bucket() : next_(0) {}
|
||||
|
||||
previous_pointer first_from_start()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
enum { extra_node = false };
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Hash Policy
|
||||
//
|
||||
// Don't really want table to derive from this, but will for now.
|
||||
// Don't really want buckets to derive from this, but will for now.
|
||||
|
||||
template <typename SizeT>
|
||||
struct prime_policy
|
||||
@@ -650,6 +541,396 @@ namespace boost { namespace unordered { namespace detail {
|
||||
std::numeric_limits<std::size_t>::digits,
|
||||
std::numeric_limits<std::size_t>::radix> {};
|
||||
|
||||
///////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Buckets
|
||||
|
||||
template <typename A, typename Bucket, typename Node, typename Policy>
|
||||
struct buckets : Policy
|
||||
{
|
||||
private:
|
||||
buckets(buckets const&);
|
||||
buckets& operator=(buckets const&);
|
||||
public:
|
||||
typedef boost::unordered::detail::allocator_traits<A> traits;
|
||||
typedef typename traits::value_type value_type;
|
||||
|
||||
typedef Policy policy;
|
||||
typedef Node node;
|
||||
typedef Bucket bucket;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
node_allocator;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, bucket>::type
|
||||
bucket_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef boost::unordered::detail::allocator_traits<bucket_allocator>
|
||||
bucket_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer
|
||||
node_pointer;
|
||||
typedef typename node_allocator_traits::const_pointer
|
||||
const_node_pointer;
|
||||
typedef typename bucket_allocator_traits::pointer
|
||||
bucket_pointer;
|
||||
typedef typename bucket::previous_pointer
|
||||
previous_pointer;
|
||||
typedef boost::unordered::detail::node_constructor<node_allocator>
|
||||
node_constructor;
|
||||
|
||||
typedef boost::unordered::iterator_detail::
|
||||
iterator<node_pointer, value_type> iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
c_iterator<const_node_pointer, node_pointer, value_type> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
l_iterator<node_pointer, value_type, policy> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
cl_iterator<const_node_pointer, node_pointer, value_type, policy>
|
||||
cl_iterator;
|
||||
|
||||
// Members
|
||||
|
||||
bucket_pointer buckets_;
|
||||
std::size_t bucket_count_;
|
||||
std::size_t size_;
|
||||
boost::unordered::detail::compressed<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 policy::prev_bucket_count(
|
||||
bucket_allocator_traits::max_size(bucket_alloc()) - 1);
|
||||
}
|
||||
|
||||
bucket_pointer get_bucket(std::size_t bucket_index) const
|
||||
{
|
||||
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
|
||||
}
|
||||
|
||||
previous_pointer get_previous_start() const
|
||||
{
|
||||
return this->get_bucket(this->bucket_count_)->first_from_start();
|
||||
}
|
||||
|
||||
previous_pointer get_previous_start(std::size_t bucket_index) const
|
||||
{
|
||||
return this->get_bucket(bucket_index)->next_;
|
||||
}
|
||||
|
||||
iterator get_start() const
|
||||
{
|
||||
return iterator(static_cast<node_pointer>(
|
||||
this->get_previous_start()->next_));
|
||||
}
|
||||
|
||||
iterator get_start(std::size_t bucket_index) const
|
||||
{
|
||||
previous_pointer prev = this->get_previous_start(bucket_index);
|
||||
return prev ? iterator(static_cast<node_pointer>(prev->next_)) :
|
||||
iterator();
|
||||
}
|
||||
|
||||
float load_factor() const
|
||||
{
|
||||
BOOST_ASSERT(this->bucket_count_ != 0);
|
||||
return static_cast<float>(this->size_)
|
||||
/ static_cast<float>(this->bucket_count_);
|
||||
}
|
||||
|
||||
std::size_t bucket_size(std::size_t index) const
|
||||
{
|
||||
if (!this->size_) return 0;
|
||||
iterator it = this->get_start(index);
|
||||
if (!it.node_) return 0;
|
||||
|
||||
std::size_t count = 0;
|
||||
while(it.node_ && policy::to_bucket(
|
||||
this->bucket_count_, it.node_->hash_) == index)
|
||||
{
|
||||
++count;
|
||||
++it;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Constructors
|
||||
|
||||
buckets(node_allocator const& a, std::size_t bucket_count) :
|
||||
buckets_(),
|
||||
bucket_count_(bucket_count),
|
||||
size_(),
|
||||
allocators_(a,a)
|
||||
{
|
||||
}
|
||||
|
||||
buckets(buckets& b, boost::unordered::detail::move_tag m) :
|
||||
buckets_(),
|
||||
bucket_count_(b.bucket_count_),
|
||||
size_(),
|
||||
allocators_(b.allocators_, m)
|
||||
{
|
||||
swap(b);
|
||||
}
|
||||
|
||||
template <typename Types>
|
||||
buckets(boost::unordered::detail::table<Types>& x,
|
||||
boost::unordered::detail::move_tag m) :
|
||||
buckets_(),
|
||||
bucket_count_(x.bucket_count_),
|
||||
size_(),
|
||||
allocators_(x.allocators_, m)
|
||||
{
|
||||
swap(x);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Create buckets
|
||||
// (never called in constructor to avoid exception issues)
|
||||
|
||||
void create_buckets()
|
||||
{
|
||||
boost::unordered::detail::array_constructor<bucket_allocator>
|
||||
constructor(bucket_alloc());
|
||||
|
||||
// Creates an extra bucket to act as the start node.
|
||||
constructor.construct(bucket(), this->bucket_count_ + 1);
|
||||
|
||||
if (bucket::extra_node)
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_node();
|
||||
|
||||
// Since this node is just to mark the beginning it doesn't
|
||||
// contain a value, so just construct node::node_base
|
||||
// which containers the pointer to the next element.
|
||||
node_allocator_traits::construct(node_alloc(),
|
||||
static_cast<typename node::node_base*>(
|
||||
boost::addressof(*a.get())),
|
||||
typename node::node_base());
|
||||
|
||||
(constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(this->bucket_count_))->next_ =
|
||||
a.release();
|
||||
}
|
||||
|
||||
this->buckets_ = constructor.release();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Swap and Move
|
||||
|
||||
void swap(buckets& other, false_type = false_type())
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
boost::swap(buckets_, other.buckets_);
|
||||
boost::swap(bucket_count_, other.bucket_count_);
|
||||
boost::swap(size_, other.size_);
|
||||
}
|
||||
|
||||
void swap(buckets& other, true_type)
|
||||
{
|
||||
allocators_.swap(other.allocators_);
|
||||
boost::swap(buckets_, other.buckets_);
|
||||
boost::swap(bucket_count_, other.bucket_count_);
|
||||
boost::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_pointer();
|
||||
other.bucket_count_ = 0;
|
||||
other.size_ = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Delete/destruct
|
||||
|
||||
inline void delete_node(c_iterator n)
|
||||
{
|
||||
boost::unordered::detail::destroy_node(
|
||||
node_alloc(), boost::addressof(*n.node_));
|
||||
node_allocator_traits::deallocate(node_alloc(), n.node_, 1);
|
||||
--size_;
|
||||
}
|
||||
|
||||
std::size_t delete_nodes(c_iterator begin, c_iterator end)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
|
||||
while(begin != end) {
|
||||
c_iterator n = begin;
|
||||
++begin;
|
||||
delete_node(n);
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
inline void delete_extra_node(bucket_pointer) {}
|
||||
|
||||
inline void delete_extra_node(node_pointer n) {
|
||||
node_allocator_traits::destroy(node_alloc(),
|
||||
static_cast<typename node::node_base*>(boost::addressof(*n)));
|
||||
node_allocator_traits::deallocate(node_alloc(), n, 1);
|
||||
}
|
||||
|
||||
inline ~buckets()
|
||||
{
|
||||
this->delete_buckets();
|
||||
}
|
||||
|
||||
void delete_buckets()
|
||||
{
|
||||
if(this->buckets_) {
|
||||
previous_pointer prev = this->get_previous_start();
|
||||
|
||||
while(prev->next_) {
|
||||
node_pointer n = static_cast<node_pointer>(prev->next_);
|
||||
prev->next_ = n->next_;
|
||||
delete_node(iterator(n));
|
||||
}
|
||||
|
||||
delete_extra_node(prev);
|
||||
|
||||
bucket_pointer end = this->get_bucket(this->bucket_count_ + 1);
|
||||
for(bucket_pointer it = this->buckets_; it != end; ++it)
|
||||
{
|
||||
bucket_allocator_traits::destroy(bucket_alloc(),
|
||||
boost::addressof(*it));
|
||||
}
|
||||
|
||||
bucket_allocator_traits::deallocate(bucket_alloc(),
|
||||
this->buckets_, this->bucket_count_ + 1);
|
||||
|
||||
this->buckets_ = bucket_pointer();
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!this->size_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if(!this->size_) return;
|
||||
|
||||
previous_pointer prev = this->get_previous_start();
|
||||
|
||||
while(prev->next_) {
|
||||
node_pointer n = static_cast<node_pointer>(prev->next_);
|
||||
prev->next_ = n->next_;
|
||||
delete_node(iterator(n));
|
||||
}
|
||||
|
||||
bucket_pointer end = this->get_bucket(this->bucket_count_);
|
||||
for(bucket_pointer it = this->buckets_; it != end; ++it)
|
||||
{
|
||||
it->next_ = node_pointer();
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!this->size_);
|
||||
}
|
||||
|
||||
// This is called after erasing a node or group of nodes to fix up
|
||||
// the bucket pointers.
|
||||
void fix_buckets(bucket_pointer this_bucket,
|
||||
previous_pointer prev, node_pointer next)
|
||||
{
|
||||
if (!next)
|
||||
{
|
||||
if (this_bucket->next_ == prev)
|
||||
this_bucket->next_ = node_pointer();
|
||||
}
|
||||
else
|
||||
{
|
||||
bucket_pointer next_bucket = this->get_bucket(
|
||||
policy::to_bucket(this->bucket_count_, next->hash_));
|
||||
|
||||
if (next_bucket != this_bucket)
|
||||
{
|
||||
next_bucket->next_ = prev;
|
||||
if (this_bucket->next_ == prev)
|
||||
this_bucket->next_ = node_pointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
previous_pointer prev, node_pointer begin, node_pointer end)
|
||||
{
|
||||
node_pointer 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 = static_cast<node_pointer>(n->next_);
|
||||
if (n == end) return;
|
||||
|
||||
std::size_t new_bucket_index =
|
||||
policy::to_bucket(this->bucket_count_, n->hash_);
|
||||
if (bucket_index != new_bucket_index) {
|
||||
bucket_index = new_bucket_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through the remaining nodes, clearing out the bucket
|
||||
// pointers.
|
||||
this->get_bucket(bucket_index)->next_ = previous_pointer();
|
||||
for(;;) {
|
||||
n = static_cast<node_pointer>(n->next_);
|
||||
if (n == end) break;
|
||||
|
||||
std::size_t new_bucket_index =
|
||||
policy::to_bucket(this->bucket_count_, n->hash_);
|
||||
if (bucket_index != new_bucket_index) {
|
||||
bucket_index = new_bucket_index;
|
||||
this->get_bucket(bucket_index)->next_ = previous_pointer();
|
||||
}
|
||||
};
|
||||
|
||||
// Finally fix the bucket containing the trailing node.
|
||||
if (n) {
|
||||
this->get_bucket(
|
||||
policy::to_bucket(this->bucket_count_, n->hash_))->next_
|
||||
= prev;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Functions
|
||||
|
||||
@@ -764,36 +1045,10 @@ namespace boost { namespace unordered { namespace detail {
|
||||
tmp_functions_ = !tmp_functions_;
|
||||
}
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
|
||||
// e.g. for int
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
|
||||
#else
|
||||
struct please_ignore_this_overload {
|
||||
typedef please_ignore_this_overload type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct rv_ref_impl {
|
||||
typedef BOOST_RV_REF(T) type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct rv_ref :
|
||||
boost::detail::if_true<
|
||||
boost::is_class<T>::value
|
||||
>::BOOST_NESTED_TEMPLATE then <
|
||||
boost::unordered::detail::rv_ref_impl<T>,
|
||||
please_ignore_this_overload
|
||||
>::type
|
||||
{};
|
||||
|
||||
# define BOOST_UNORDERED_RV_REF(T) \
|
||||
typename boost::unordered::detail::rv_ref<T>::type
|
||||
#endif
|
||||
}}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,518 @@
|
||||
|
||||
// Copyright (C) 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)
|
||||
|
||||
// See http://www.boost.org/libs/unordered for documentation
|
||||
|
||||
#ifndef BOOST_UNORDERED_EMPLACE_ARGS_HPP
|
||||
#define BOOST_UNORDERED_EMPLACE_ARGS_HPP
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER >= 1020)
|
||||
# pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/preprocessor/cat.hpp>
|
||||
#include <boost/preprocessor/inc.hpp>
|
||||
#include <boost/preprocessor/dec.hpp>
|
||||
#include <boost/preprocessor/repetition/enum.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_params.hpp>
|
||||
#include <boost/preprocessor/repetition/enum_binary_params.hpp>
|
||||
#include <boost/preprocessor/repetition/repeat_from_to.hpp>
|
||||
#include <boost/type_traits/is_class.hpp>
|
||||
#include <boost/type_traits/add_lvalue_reference.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
#include <utility>
|
||||
|
||||
#if !defined(BOOST_NO_0X_HDR_TUPLE)
|
||||
#include <tuple>
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4512) // assignment operator could not be generated.
|
||||
#pragma warning(disable:4345) // behavior change: an object of POD type
|
||||
// constructed with an initializer of the form ()
|
||||
// will be default-initialized.
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_EMPLACE_LIMIT 10
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && \
|
||||
!defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#define BOOST_UNORDERED_VARIADIC_MOVE
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Bits and pieces for implementing traits
|
||||
|
||||
template <typename T> typename boost::add_lvalue_reference<T>::type make();
|
||||
struct choice9 { typedef char (&type)[9]; };
|
||||
struct choice8 : choice9 { typedef char (&type)[8]; };
|
||||
struct choice7 : choice8 { typedef char (&type)[7]; };
|
||||
struct choice6 : choice7 { typedef char (&type)[6]; };
|
||||
struct choice5 : choice6 { typedef char (&type)[5]; };
|
||||
struct choice4 : choice5 { typedef char (&type)[4]; };
|
||||
struct choice3 : choice4 { typedef char (&type)[3]; };
|
||||
struct choice2 : choice3 { typedef char (&type)[2]; };
|
||||
struct choice1 : choice2 { typedef char (&type)[1]; };
|
||||
choice1 choose();
|
||||
|
||||
typedef choice1::type yes_type;
|
||||
typedef choice2::type no_type;
|
||||
|
||||
struct private_type
|
||||
{
|
||||
private_type const &operator,(int) const;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
no_type is_private_type(T const&);
|
||||
yes_type is_private_type(private_type const&);
|
||||
|
||||
struct convert_from_anything {
|
||||
template <typename T>
|
||||
convert_from_anything(T const&);
|
||||
};
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// emplace_args
|
||||
//
|
||||
// Either forwarding variadic arguments, or storing the arguments in
|
||||
// emplace_args##n
|
||||
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
|
||||
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename... Args
|
||||
#define BOOST_UNORDERED_EMPLACE_ARGS Args&&... args
|
||||
#define BOOST_UNORDERED_EMPLACE_FORWARD boost::forward<Args>(args)...
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_EMPLACE_TEMPLATE typename Args
|
||||
#define BOOST_UNORDERED_EMPLACE_ARGS Args const& args
|
||||
#define BOOST_UNORDERED_EMPLACE_FORWARD args
|
||||
|
||||
#define BOOST_UNORDERED_FWD_PARAM(z, n, a) \
|
||||
BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(a, n)
|
||||
|
||||
#define BOOST_UNORDERED_CALL_FORWARD(z, i, a) \
|
||||
boost::forward<BOOST_PP_CAT(A,i)>(BOOST_PP_CAT(a,i))
|
||||
|
||||
#define BOOST_UNORDERED_EARGS(z, n, _) \
|
||||
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
|
||||
struct BOOST_PP_CAT(emplace_args, n) \
|
||||
{ \
|
||||
BOOST_PP_REPEAT_##z(n, BOOST_UNORDERED_EARGS_MEMBER, _) \
|
||||
BOOST_PP_CAT(emplace_args, n) ( \
|
||||
BOOST_PP_ENUM_BINARY_PARAMS_Z(z, n, Arg, b) \
|
||||
) : BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_EARGS_INIT, _) \
|
||||
{} \
|
||||
\
|
||||
}; \
|
||||
\
|
||||
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
|
||||
inline BOOST_PP_CAT(emplace_args, n) < \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
|
||||
> create_emplace_args( \
|
||||
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_FWD_PARAM, b) \
|
||||
) \
|
||||
{ \
|
||||
BOOST_PP_CAT(emplace_args, n) < \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, n, A) \
|
||||
> e(BOOST_PP_ENUM_PARAMS_Z(z, n, b)); \
|
||||
return e; \
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
|
||||
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
|
||||
typedef BOOST_FWD_REF(BOOST_PP_CAT(A, n)) BOOST_PP_CAT(Arg, n); \
|
||||
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
|
||||
|
||||
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
|
||||
BOOST_PP_CAT(a, n)( \
|
||||
boost::forward<BOOST_PP_CAT(A,n)>(BOOST_PP_CAT(b, n)))
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_EARGS_MEMBER(z, n, _) \
|
||||
typedef typename boost::add_lvalue_reference<BOOST_PP_CAT(A, n)>::type \
|
||||
BOOST_PP_CAT(Arg, n); \
|
||||
BOOST_PP_CAT(Arg, n) BOOST_PP_CAT(a, n);
|
||||
|
||||
#define BOOST_UNORDERED_EARGS_INIT(z, n, _) \
|
||||
BOOST_PP_CAT(a, n)(BOOST_PP_CAT(b, n))
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(1, BOOST_UNORDERED_EMPLACE_LIMIT, BOOST_UNORDERED_EARGS,
|
||||
_)
|
||||
|
||||
#undef BOOST_UNORDERED_DEFINE_EMPLACE_ARGS
|
||||
#undef BOOST_UNORDERED_EARGS_MEMBER
|
||||
#undef BOOST_UNORDERED_EARGS_INIT
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// rvalue parameters when type can't be a BOOST_RV_REF(T) parameter
|
||||
// e.g. for int
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
# define BOOST_UNORDERED_RV_REF(T) BOOST_RV_REF(T)
|
||||
#else
|
||||
struct please_ignore_this_overload {
|
||||
typedef please_ignore_this_overload type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct rv_ref_impl {
|
||||
typedef BOOST_RV_REF(T) type;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct rv_ref :
|
||||
boost::detail::if_true<
|
||||
boost::is_class<T>::value
|
||||
>::BOOST_NESTED_TEMPLATE then <
|
||||
boost::unordered::detail::rv_ref_impl<T>,
|
||||
please_ignore_this_overload
|
||||
>::type
|
||||
{};
|
||||
|
||||
# define BOOST_UNORDERED_RV_REF(T) \
|
||||
typename boost::unordered::detail::rv_ref<T>::type
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Construct from tuple
|
||||
//
|
||||
// Used for piecewise construction.
|
||||
|
||||
#if !defined(__SUNPRO_CC)
|
||||
|
||||
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
|
||||
template<typename T> \
|
||||
void construct_from_tuple(T* ptr, namespace_ tuple<>) \
|
||||
{ \
|
||||
new ((void*) ptr) T(); \
|
||||
} \
|
||||
\
|
||||
BOOST_PP_REPEAT_FROM_TO(1, n, \
|
||||
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
|
||||
|
||||
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
|
||||
template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
|
||||
void construct_from_tuple(T* ptr, \
|
||||
namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
|
||||
{ \
|
||||
new ((void*) ptr) T( \
|
||||
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \
|
||||
); \
|
||||
}
|
||||
|
||||
# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
|
||||
namespace_ get<n>(x)
|
||||
|
||||
#else
|
||||
|
||||
template <int N> struct length {};
|
||||
|
||||
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(n, namespace_) \
|
||||
template<typename T> \
|
||||
void construct_from_tuple_impl( \
|
||||
boost::unordered::detail::length<0>, T* ptr, \
|
||||
namespace_ tuple<>) \
|
||||
{ \
|
||||
new ((void*) ptr) T(); \
|
||||
} \
|
||||
\
|
||||
BOOST_PP_REPEAT_FROM_TO(1, n, \
|
||||
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL, namespace_)
|
||||
|
||||
# define BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL(z, n, namespace_) \
|
||||
template<typename T, BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
|
||||
void construct_from_tuple_impl( \
|
||||
boost::unordered::detail::length<n>, T* ptr, \
|
||||
namespace_ tuple<BOOST_PP_ENUM_PARAMS_Z(z, n, A)> const& x) \
|
||||
{ \
|
||||
new ((void*) ptr) T( \
|
||||
BOOST_PP_ENUM_##z(n, BOOST_UNORDERED_GET_TUPLE_ARG, namespace_) \
|
||||
); \
|
||||
}
|
||||
|
||||
# define BOOST_UNORDERED_GET_TUPLE_ARG(z, n, namespace_) \
|
||||
namespace_ get<n>(x)
|
||||
|
||||
#endif
|
||||
|
||||
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, boost::)
|
||||
|
||||
#if !defined(__SUNPRO_CC) && !defined(BOOST_NO_0X_HDR_TUPLE)
|
||||
BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE(10, std::)
|
||||
#endif
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_FROM_TUPLE_IMPL
|
||||
#undef BOOST_UNORDERED_GET_TUPLE_ARG
|
||||
|
||||
#if defined(__SUNPRO_CC)
|
||||
|
||||
template <typename T, typename Tuple>
|
||||
void construct_from_tuple(T* ptr, Tuple const& x)
|
||||
{
|
||||
construct_from_tuple_impl(
|
||||
boost::unordered::detail::length<
|
||||
boost::tuples::length<Tuple>::value>(),
|
||||
ptr, x);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// SFINAE traits for construction.
|
||||
|
||||
// Decide which construction method to use for a three argument
|
||||
// call. Note that this is difficult to do using overloads because
|
||||
// the arguments are packed into 'emplace_args3'.
|
||||
//
|
||||
// The decision is made on the first argument.
|
||||
|
||||
|
||||
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
|
||||
template <typename A, typename B, typename A0>
|
||||
struct emulation1 {
|
||||
static choice1::type test(choice1, std::pair<A, B> const&);
|
||||
static choice2::type test(choice2, A const&);
|
||||
static choice3::type test(choice3, convert_from_anything const&);
|
||||
|
||||
enum { value =
|
||||
sizeof(test(choose(), boost::unordered::detail::make<A0>())) ==
|
||||
sizeof(choice2::type) };
|
||||
};
|
||||
#endif
|
||||
|
||||
template <typename A, typename B, typename A0>
|
||||
struct check3_base {
|
||||
static choice1::type test(choice1,
|
||||
boost::unordered::piecewise_construct_t);
|
||||
|
||||
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
|
||||
static choice2::type test(choice2, A const&);
|
||||
#endif
|
||||
|
||||
static choice3::type test(choice3, ...);
|
||||
|
||||
enum { value =
|
||||
sizeof(test(choose(), boost::unordered::detail::make<A0>())) };
|
||||
};
|
||||
|
||||
template <typename A, typename B, typename A0>
|
||||
struct piecewise3 {
|
||||
enum { value = check3_base<A,B,A0>::value == sizeof(choice1::type) };
|
||||
};
|
||||
|
||||
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
|
||||
template <typename A, typename B, typename A0>
|
||||
struct emulation3 {
|
||||
enum { value = check3_base<A,B,A0>::value == sizeof(choice2::type) };
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Construct from variadic parameters
|
||||
|
||||
template <typename T, typename... Args>
|
||||
inline void construct_impl(T* address, Args&&... args)
|
||||
{
|
||||
new((void*) address) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename A0, typename A1, typename A2>
|
||||
inline typename enable_if<piecewise3<A, B, A0>, void>::type
|
||||
construct_impl(std::pair<A, B>* address, A0&&, A1&& a1, A2&& a2)
|
||||
{
|
||||
boost::unordered::detail::construct_from_tuple(
|
||||
boost::addressof(address->first), a1);
|
||||
boost::unordered::detail::construct_from_tuple(
|
||||
boost::addressof(address->second), a2);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
|
||||
|
||||
template <typename A, typename B, typename A0>
|
||||
inline typename enable_if<emulation1<A, B, A0>, void>::type
|
||||
construct_impl(std::pair<A, B>* address, A0&& a0)
|
||||
{
|
||||
new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0));
|
||||
new((void*) boost::addressof(address->second)) B();
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename A0, typename A1, typename A2>
|
||||
inline typename enable_if<emulation3<A, B, A0>, void>::type
|
||||
construct_impl(std::pair<A, B>* address, A0&& a0, A1&& a1, A2&& a2)
|
||||
{
|
||||
new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0));
|
||||
new((void*) boost::addressof(address->second)) B(
|
||||
boost::forward<A1>(a1),
|
||||
boost::forward<A2>(a2));
|
||||
}
|
||||
|
||||
template <typename A, typename B,
|
||||
typename A0, typename A1, typename A2, typename A3,
|
||||
typename... Args>
|
||||
inline void construct_impl(std::pair<A, B>* address,
|
||||
A0&& a0, A1&& a1, A2&& a2, A3&& a3, Args&&... args)
|
||||
{
|
||||
new((void*) boost::addressof(address->first)) A(boost::forward<A0>(a0));
|
||||
|
||||
new((void*) boost::addressof(address->second)) B(
|
||||
boost::forward<A1>(a1),
|
||||
boost::forward<A2>(a2),
|
||||
boost::forward<A3>(a3),
|
||||
boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
|
||||
#else // BOOST_UNORDERED_VARIADIC_MOVE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Construct from emplace_args
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT_IMPL(z, num_params, _) \
|
||||
template < \
|
||||
typename T, \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
|
||||
> \
|
||||
inline void construct_impl(T* address, \
|
||||
boost::unordered::detail::BOOST_PP_CAT(emplace_args,num_params) < \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
|
||||
> const& args) \
|
||||
{ \
|
||||
new((void*) address) T( \
|
||||
BOOST_PP_ENUM_##z(num_params, BOOST_UNORDERED_CALL_FORWARD, \
|
||||
args.a)); \
|
||||
}
|
||||
|
||||
template <typename T, typename A0>
|
||||
inline void construct_impl(T* address, emplace_args1<A0> const& args)
|
||||
{
|
||||
new((void*) address) T(boost::forward<A0>(args.a0));
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1>
|
||||
inline void construct_impl(T* address, emplace_args2<A0, A1> const& args)
|
||||
{
|
||||
new((void*) address) T(
|
||||
boost::forward<A0>(args.a0),
|
||||
boost::forward<A1>(args.a1)
|
||||
);
|
||||
}
|
||||
|
||||
template <typename T, typename A0, typename A1, typename A2>
|
||||
inline void construct_impl(T* address, emplace_args3<A0, A1, A2> const& args)
|
||||
{
|
||||
new((void*) address) T(
|
||||
boost::forward<A0>(args.a0),
|
||||
boost::forward<A1>(args.a1),
|
||||
boost::forward<A2>(args.a2)
|
||||
);
|
||||
}
|
||||
|
||||
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_CONSTRUCT_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_IMPL
|
||||
|
||||
template <typename A, typename B, typename A0, typename A1, typename A2>
|
||||
inline typename enable_if<piecewise3<A, B, A0>, void>::type
|
||||
construct_impl(std::pair<A, B>* address,
|
||||
boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
|
||||
{
|
||||
boost::unordered::detail::construct_from_tuple(
|
||||
boost::addressof(address->first), args.a1);
|
||||
boost::unordered::detail::construct_from_tuple(
|
||||
boost::addressof(address->second), args.a2);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT)
|
||||
|
||||
template <typename A, typename B, typename A0>
|
||||
inline typename enable_if<emulation1<A, B, A0>, void>::type
|
||||
construct_impl(std::pair<A, B>* address,
|
||||
boost::unordered::detail::emplace_args1<A0> const& args)
|
||||
{
|
||||
new((void*) boost::addressof(address->first)) A(
|
||||
boost::forward<A0>(args.a0));
|
||||
new((void*) boost::addressof(address->second)) B();
|
||||
}
|
||||
|
||||
template <typename A, typename B, typename A0, typename A1, typename A2>
|
||||
inline typename enable_if<emulation3<A, B, A0>, void>::type
|
||||
construct_impl(std::pair<A, B>* address,
|
||||
boost::unordered::detail::emplace_args3<A0, A1, A2> const& args)
|
||||
{
|
||||
new((void*) boost::addressof(address->first)) A(
|
||||
boost::forward<A0>(args.a0));
|
||||
new((void*) boost::addressof(address->second)) B(
|
||||
boost::forward<A1>(args.a1),
|
||||
boost::forward<A2>(args.a2));
|
||||
}
|
||||
|
||||
#define BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(z, num_params, _) \
|
||||
template <typename A, typename B, \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, typename A) \
|
||||
> \
|
||||
inline void construct_impl(std::pair<A, B>* address, \
|
||||
boost::unordered::detail::BOOST_PP_CAT(emplace_args, num_params) < \
|
||||
BOOST_PP_ENUM_PARAMS_Z(z, num_params, A) \
|
||||
> const& args) \
|
||||
{ \
|
||||
new((void*) boost::addressof(address->first)) A( \
|
||||
boost::forward<A0>(args.a0)); \
|
||||
new((void*) boost::addressof(address->second)) B( \
|
||||
BOOST_PP_ENUM_##z(BOOST_PP_DEC(num_params), \
|
||||
BOOST_UNORDERED_CALL_FORWARD2, args.a)); \
|
||||
}
|
||||
|
||||
#define BOOST_UNORDERED_CALL_FORWARD2(z, i, a) \
|
||||
BOOST_UNORDERED_CALL_FORWARD(z, BOOST_PP_INC(i), a)
|
||||
|
||||
BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL(1, 2, _)
|
||||
BOOST_PP_REPEAT_FROM_TO(4, BOOST_UNORDERED_EMPLACE_LIMIT,
|
||||
BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL, _)
|
||||
|
||||
#undef BOOST_UNORDERED_CONSTRUCT_PAIR_IMPL
|
||||
#undef BOOST_UNORDERED_CALL_FORWARD2
|
||||
|
||||
#endif // BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT
|
||||
#endif // BOOST_UNORDERED_VARIADIC_MOVE
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Construct without using the emplace args mechanism.
|
||||
|
||||
template <typename T, typename A0>
|
||||
inline void construct_impl2(T* address, BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
new((void*) address) T(
|
||||
boost::forward<A0>(a0)
|
||||
);
|
||||
}
|
||||
|
||||
}}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -22,28 +22,45 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename A, typename T>
|
||||
struct grouped_node :
|
||||
boost::unordered::detail::node_base<
|
||||
typename ::boost::unordered::detail::rebind_wrap<
|
||||
A, grouped_node<A, T> >::type::pointer
|
||||
>,
|
||||
boost::unordered::detail::value_base<T>
|
||||
{
|
||||
typedef typename ::boost::unordered::detail::rebind_wrap<
|
||||
A, grouped_node<A, T> >::type::pointer link_pointer;
|
||||
typedef boost::unordered::detail::node_base<link_pointer> node_base;
|
||||
|
||||
link_pointer next_;
|
||||
link_pointer group_prev_;
|
||||
std::size_t hash_;
|
||||
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
grouped_node(BOOST_UNORDERED_EMPLACE_ARGS) :
|
||||
node_base(),
|
||||
group_prev_(),
|
||||
hash_(0)
|
||||
{
|
||||
boost::unordered::detail::construct_impl(
|
||||
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
}
|
||||
|
||||
~grouped_node() {
|
||||
boost::unordered::detail::destroy(this->value_ptr());
|
||||
}
|
||||
#else
|
||||
grouped_node() :
|
||||
next_(),
|
||||
node_base(),
|
||||
group_prev_(),
|
||||
hash_(0)
|
||||
{}
|
||||
#endif
|
||||
|
||||
void init(link_pointer self)
|
||||
{
|
||||
group_prev_ = self;
|
||||
}
|
||||
|
||||
private:
|
||||
grouped_node& operator=(grouped_node const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -52,24 +69,38 @@ namespace boost { namespace unordered { namespace detail {
|
||||
boost::unordered::detail::ptr_bucket
|
||||
{
|
||||
typedef boost::unordered::detail::ptr_bucket bucket_base;
|
||||
typedef bucket_base node_base;
|
||||
typedef ptr_bucket* link_pointer;
|
||||
|
||||
link_pointer group_prev_;
|
||||
std::size_t hash_;
|
||||
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
grouped_ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) :
|
||||
bucket_base(),
|
||||
group_prev_(0),
|
||||
hash_(0)
|
||||
{
|
||||
boost::unordered::detail::construct_impl(
|
||||
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
}
|
||||
|
||||
~grouped_ptr_node() {
|
||||
boost::unordered::detail::destroy(this->value_ptr());
|
||||
}
|
||||
#else
|
||||
grouped_ptr_node() :
|
||||
bucket_base(),
|
||||
group_prev_(0),
|
||||
hash_(0)
|
||||
{}
|
||||
#endif
|
||||
|
||||
void init(link_pointer self)
|
||||
{
|
||||
group_prev_ = self;
|
||||
}
|
||||
|
||||
private:
|
||||
grouped_ptr_node& operator=(grouped_ptr_node const&);
|
||||
};
|
||||
|
||||
// If the allocator uses raw pointers use grouped_ptr_node
|
||||
@@ -125,15 +156,16 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
typedef boost::unordered::detail::multiset<A, T, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef T value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef T key_type;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<
|
||||
A, value_type>::type allocator;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_grouped_node<allocator,
|
||||
value_type> pick;
|
||||
typedef boost::unordered::detail::pick_grouped_node<allocator, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
@@ -149,15 +181,16 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
typedef boost::unordered::detail::multimap<A, K, M, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef std::pair<K const, M> value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef K key_type;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<
|
||||
A, value_type>::type allocator;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_grouped_node<allocator,
|
||||
value_type> pick;
|
||||
typedef boost::unordered::detail::pick_grouped_node<allocator, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
typedef typename pick::link_pointer link_pointer;
|
||||
@@ -175,6 +208,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
typedef boost::unordered::detail::table<Types> table;
|
||||
typedef typename table::value_type value_type;
|
||||
typedef typename table::bucket bucket;
|
||||
typedef typename table::buckets buckets;
|
||||
typedef typename table::policy policy;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::node_allocator node_allocator;
|
||||
@@ -201,17 +235,12 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
grouped_table_impl(grouped_table_impl const& x)
|
||||
: table(x, node_allocator_traits::
|
||||
select_on_container_copy_construction(x.node_alloc()))
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
select_on_container_copy_construction(x.node_alloc())) {}
|
||||
|
||||
grouped_table_impl(grouped_table_impl const& x,
|
||||
node_allocator const& a)
|
||||
: table(x, a)
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
{}
|
||||
|
||||
grouped_table_impl(grouped_table_impl& x,
|
||||
boost::unordered::detail::move_tag m)
|
||||
@@ -222,9 +251,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
node_allocator const& a,
|
||||
boost::unordered::detail::move_tag m)
|
||||
: table(x, a, m)
|
||||
{
|
||||
this->move_init(x);
|
||||
}
|
||||
{}
|
||||
|
||||
// Accessors
|
||||
|
||||
@@ -236,7 +263,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
std::size_t bucket_index =
|
||||
policy::to_bucket(this->bucket_count_, key_hash);
|
||||
iterator n = this->begin(bucket_index);
|
||||
iterator n = this->get_start(bucket_index);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -291,8 +318,9 @@ namespace boost { namespace unordered { namespace detail {
|
||||
bool equals(grouped_table_impl const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
if(!this->size_) return true;
|
||||
|
||||
for(iterator n1 = this->begin(); n1.node_;)
|
||||
for(iterator n1 = this->get_start(); n1.node_;)
|
||||
{
|
||||
iterator n2 = other.find_matching_node(n1);
|
||||
if (!n2.node_) return false;
|
||||
@@ -469,28 +497,20 @@ namespace boost { namespace unordered { namespace detail {
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
# if defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
iterator emplace(boost::unordered::detail::emplace_args1<
|
||||
boost::unordered::detail::please_ignore_this_overload> const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return iterator();
|
||||
}
|
||||
# else
|
||||
iterator emplace(
|
||||
boost::unordered::detail::please_ignore_this_overload const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return iterator();
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
iterator emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
a.construct_node();
|
||||
a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
|
||||
return iterator(emplace_impl(a));
|
||||
}
|
||||
@@ -509,7 +529,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
std::size_t distance = boost::unordered::detail::distance(i, j);
|
||||
if(distance == 1) {
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value2(*i);
|
||||
a.construct_node();
|
||||
a.construct_value2(*i);
|
||||
emplace_impl(a);
|
||||
}
|
||||
else {
|
||||
@@ -518,7 +539,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
node_constructor a(this->node_alloc());
|
||||
for (; i != j; ++i) {
|
||||
a.construct_with_value2(*i);
|
||||
a.construct_node();
|
||||
a.construct_value2(*i);
|
||||
emplace_impl_no_rehash(a);
|
||||
}
|
||||
}
|
||||
@@ -530,7 +552,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
for (; i != j; ++i) {
|
||||
a.construct_with_value2(*i);
|
||||
a.construct_node();
|
||||
a.construct_value2(*i);
|
||||
emplace_impl(a);
|
||||
}
|
||||
}
|
||||
@@ -676,9 +699,9 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
if(begin == group2) {
|
||||
link_pointer end1 = group1->group_prev_;
|
||||
link_pointer end2 = end->group_prev_;
|
||||
link_pointer end2 = group2->group_prev_;
|
||||
group1->group_prev_ = end2;
|
||||
end->group_prev_ = end1;
|
||||
group2->group_prev_ = end1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -709,12 +732,20 @@ namespace boost { namespace unordered { namespace detail {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// fill_buckets
|
||||
// copy_buckets_to
|
||||
//
|
||||
// Basic exception safety. If an exception is thrown this will
|
||||
// leave dst partially filled and the buckets unset.
|
||||
|
||||
template <class NodeCreator>
|
||||
static void fill_buckets(iterator n, table& dst,
|
||||
NodeCreator& creator)
|
||||
static void copy_buckets_to(buckets const& src, buckets& dst)
|
||||
{
|
||||
BOOST_ASSERT(!dst.buckets_);
|
||||
|
||||
dst.create_buckets();
|
||||
|
||||
node_constructor a(dst.node_alloc());
|
||||
|
||||
iterator n = src.get_start();
|
||||
previous_pointer prev = dst.get_previous_start();
|
||||
|
||||
while (n.node_) {
|
||||
@@ -724,7 +755,10 @@ namespace boost { namespace unordered { namespace detail {
|
||||
static_cast<node_pointer>(n.node_->group_prev_)->next_
|
||||
));
|
||||
|
||||
node_pointer first_node = creator.create(*n);
|
||||
a.construct_node();
|
||||
a.construct_value2(*n);
|
||||
|
||||
node_pointer first_node = a.release();
|
||||
node_pointer end = first_node;
|
||||
first_node->hash_ = key_hash;
|
||||
prev->next_ = static_cast<link_pointer>(first_node);
|
||||
@@ -732,7 +766,56 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
for (++n; n != group_end; ++n)
|
||||
{
|
||||
end = creator.create(*n);
|
||||
a.construct_node();
|
||||
a.construct_value2(*n);
|
||||
end = a.release();
|
||||
end->hash_ = key_hash;
|
||||
add_after_node(end, first_node);
|
||||
++dst.size_;
|
||||
}
|
||||
|
||||
prev = place_in_bucket(dst, prev, end);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// move_buckets_to
|
||||
//
|
||||
// Basic exception safety. The source nodes are left in an unusable
|
||||
// state if an exception throws.
|
||||
|
||||
static void move_buckets_to(buckets& src, buckets& dst)
|
||||
{
|
||||
BOOST_ASSERT(!dst.buckets_);
|
||||
|
||||
dst.create_buckets();
|
||||
|
||||
node_constructor a(dst.node_alloc());
|
||||
|
||||
iterator n = src.get_start();
|
||||
previous_pointer prev = dst.get_previous_start();
|
||||
|
||||
while (n.node_) {
|
||||
std::size_t key_hash = n.node_->hash_;
|
||||
iterator group_end(
|
||||
static_cast<node_pointer>(
|
||||
static_cast<node_pointer>(n.node_->group_prev_)->next_
|
||||
));
|
||||
|
||||
a.construct_node();
|
||||
a.construct_value2(boost::move(*n));
|
||||
|
||||
node_pointer first_node = a.release();
|
||||
node_pointer end = first_node;
|
||||
first_node->hash_ = key_hash;
|
||||
prev->next_ = static_cast<link_pointer>(first_node);
|
||||
++dst.size_;
|
||||
|
||||
for(++n; n != group_end; ++n)
|
||||
{
|
||||
a.construct_node();
|
||||
a.construct_value2(boost::move(*n));
|
||||
end = a.release();
|
||||
end->hash_ = key_hash;
|
||||
add_after_node(end, first_node);
|
||||
++dst.size_;
|
||||
@@ -745,19 +828,33 @@ namespace boost { namespace unordered { namespace detail {
|
||||
// strong otherwise exception safety
|
||||
void rehash_impl(std::size_t num_buckets)
|
||||
{
|
||||
BOOST_ASSERT(this->buckets_);
|
||||
BOOST_ASSERT(this->size_);
|
||||
|
||||
this->create_buckets(num_buckets);
|
||||
previous_pointer prev = this->get_previous_start();
|
||||
buckets dst(this->node_alloc(), num_buckets);
|
||||
dst.create_buckets();
|
||||
|
||||
previous_pointer src_start = this->get_previous_start();
|
||||
previous_pointer dst_start = dst.get_previous_start();
|
||||
|
||||
dst_start->next_ = src_start->next_;
|
||||
src_start->next_ = link_pointer();
|
||||
dst.size_ = this->size_;
|
||||
this->size_ = 0;
|
||||
|
||||
previous_pointer prev = dst_start;
|
||||
while (prev->next_)
|
||||
prev = place_in_bucket(*this, prev,
|
||||
prev = place_in_bucket(dst, prev,
|
||||
static_cast<node_pointer>(
|
||||
static_cast<node_pointer>(prev->next_)->group_prev_));
|
||||
|
||||
// Swap the new nodes back into the container and setup the
|
||||
// variables.
|
||||
dst.swap(*this); // no throw
|
||||
}
|
||||
|
||||
// Iterate through the nodes placing them in the correct buckets.
|
||||
// pre: prev->next_ is not null.
|
||||
static previous_pointer place_in_bucket(table& dst,
|
||||
static previous_pointer place_in_bucket(buckets& dst,
|
||||
previous_pointer prev, node_pointer end)
|
||||
{
|
||||
bucket_pointer b = dst.get_bucket(policy::to_bucket(
|
||||
|
||||
@@ -56,7 +56,7 @@ namespace detail {
|
||||
return no_key();
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <class... Args>
|
||||
static no_key extract(Args const&...)
|
||||
{
|
||||
@@ -111,7 +111,7 @@ namespace detail {
|
||||
return v.first;
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <class Arg1, class... Args>
|
||||
static key_type const& extract(key_type const& k,
|
||||
Arg1 const&, Args const&...)
|
||||
@@ -150,12 +150,12 @@ namespace detail {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
|
||||
#define BOOST_UNORDERED_KEY_FROM_TUPLE(namespace_) \
|
||||
template <typename T2> \
|
||||
static no_key extract(boost::unordered::piecewise_construct_t, \
|
||||
namespace_::tuple<> const&, BOOST_FWD_REF(T2)) \
|
||||
namespace_::tuple<> const&, T2&&) \
|
||||
{ \
|
||||
return no_key(); \
|
||||
} \
|
||||
@@ -163,7 +163,7 @@ namespace detail {
|
||||
template <typename T, typename T2> \
|
||||
static typename is_key<key_type, T>::type \
|
||||
extract(boost::unordered::piecewise_construct_t, \
|
||||
namespace_::tuple<T> const& k, BOOST_FWD_REF(T2)) \
|
||||
namespace_::tuple<T> const& k, T2&&) \
|
||||
{ \
|
||||
return typename is_key<key_type, T>::type( \
|
||||
namespace_::get<0>(k)); \
|
||||
@@ -191,7 +191,7 @@ namespace detail {
|
||||
|
||||
BOOST_UNORDERED_KEY_FROM_TUPLE(boost)
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE)
|
||||
#if !defined(BOOST_NO_0X_HDR_TUPLE)
|
||||
BOOST_UNORDERED_KEY_FROM_TUPLE(std)
|
||||
#endif
|
||||
|
||||
|
||||
@@ -13,11 +13,6 @@
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <cmath>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4127) // conditional expression is constant
|
||||
#endif
|
||||
|
||||
namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -59,73 +54,13 @@ namespace boost { namespace unordered { namespace detail {
|
||||
value_base& operator=(value_base const&);
|
||||
};
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct copy_nodes
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
|
||||
node_constructor<NodeAlloc> constructor;
|
||||
|
||||
explicit copy_nodes(NodeAlloc& a) : constructor(a) {}
|
||||
|
||||
typename node_allocator_traits::pointer create(
|
||||
typename node_allocator_traits::value_type::value_type const& v)
|
||||
{
|
||||
constructor.construct_with_value2(v);
|
||||
return constructor.release();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename NodeAlloc>
|
||||
struct move_nodes
|
||||
{
|
||||
typedef boost::unordered::detail::allocator_traits<NodeAlloc>
|
||||
node_allocator_traits;
|
||||
|
||||
node_constructor<NodeAlloc> constructor;
|
||||
|
||||
explicit move_nodes(NodeAlloc& a) : constructor(a) {}
|
||||
|
||||
typename node_allocator_traits::pointer create(
|
||||
typename node_allocator_traits::value_type::value_type& v)
|
||||
{
|
||||
constructor.construct_with_value2(boost::move(v));
|
||||
return constructor.release();
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Buckets>
|
||||
struct assign_nodes
|
||||
{
|
||||
node_holder<typename Buckets::node_allocator> holder;
|
||||
|
||||
explicit assign_nodes(Buckets& b) : holder(b) {}
|
||||
|
||||
typename Buckets::node_pointer create(
|
||||
typename Buckets::value_type const& v)
|
||||
{
|
||||
return holder.copy_of(v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Buckets>
|
||||
struct move_assign_nodes
|
||||
{
|
||||
node_holder<typename Buckets::node_allocator> holder;
|
||||
|
||||
explicit move_assign_nodes(Buckets& b) : holder(b) {}
|
||||
|
||||
typename Buckets::node_pointer create(
|
||||
typename Buckets::value_type& v)
|
||||
{
|
||||
return holder.move_copy_of(v);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename Types>
|
||||
struct table :
|
||||
Types::policy,
|
||||
boost::unordered::detail::buckets<
|
||||
typename Types::allocator,
|
||||
typename Types::bucket,
|
||||
typename Types::node,
|
||||
typename Types::policy>,
|
||||
boost::unordered::detail::functions<
|
||||
typename Types::hasher,
|
||||
typename Types::key_equal>
|
||||
@@ -134,8 +69,6 @@ namespace boost { namespace unordered { namespace detail {
|
||||
table(table const&);
|
||||
table& operator=(table const&);
|
||||
public:
|
||||
typedef typename Types::node node;
|
||||
typedef typename Types::bucket bucket;
|
||||
typedef typename Types::hasher hasher;
|
||||
typedef typename Types::key_equal key_equal;
|
||||
typedef typename Types::key_type key_type;
|
||||
@@ -149,129 +82,23 @@ namespace boost { namespace unordered { namespace detail {
|
||||
typename Types::hasher,
|
||||
typename Types::key_equal> functions;
|
||||
|
||||
typedef typename Types::allocator allocator;
|
||||
typedef typename boost::unordered::detail::
|
||||
rebind_wrap<allocator, node>::type node_allocator;
|
||||
typedef typename boost::unordered::detail::
|
||||
rebind_wrap<allocator, bucket>::type bucket_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef boost::unordered::detail::allocator_traits<bucket_allocator>
|
||||
bucket_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer
|
||||
node_pointer;
|
||||
typedef typename node_allocator_traits::const_pointer
|
||||
const_node_pointer;
|
||||
typedef typename bucket_allocator_traits::pointer
|
||||
bucket_pointer;
|
||||
typedef typename bucket::previous_pointer
|
||||
previous_pointer;
|
||||
typedef boost::unordered::detail::node_constructor<node_allocator>
|
||||
node_constructor;
|
||||
typedef boost::unordered::detail::buckets<
|
||||
typename Types::allocator,
|
||||
typename Types::bucket,
|
||||
typename Types::node,
|
||||
typename Types::policy> buckets;
|
||||
|
||||
typedef boost::unordered::iterator_detail::
|
||||
iterator<node_pointer, value_type> iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
c_iterator<const_node_pointer, node_pointer, value_type> c_iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
l_iterator<node_pointer, value_type, policy> l_iterator;
|
||||
typedef boost::unordered::iterator_detail::
|
||||
cl_iterator<const_node_pointer, node_pointer, value_type, policy>
|
||||
cl_iterator;
|
||||
typedef typename buckets::node_allocator node_allocator;
|
||||
typedef typename buckets::node_allocator_traits node_allocator_traits;
|
||||
typedef typename buckets::node_pointer node_pointer;
|
||||
typedef typename buckets::const_node_pointer const_node_pointer;
|
||||
|
||||
typedef typename table::iterator iterator;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Members
|
||||
|
||||
boost::unordered::detail::compressed<bucket_allocator, node_allocator>
|
||||
allocators_;
|
||||
std::size_t bucket_count_;
|
||||
std::size_t size_;
|
||||
float mlf_;
|
||||
std::size_t max_load_;
|
||||
bucket_pointer buckets_;
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// 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 policy::prev_bucket_count(
|
||||
bucket_allocator_traits::max_size(bucket_alloc()) - 1);
|
||||
}
|
||||
|
||||
bucket_pointer get_bucket(std::size_t bucket_index) const
|
||||
{
|
||||
BOOST_ASSERT(buckets_);
|
||||
return buckets_ + static_cast<std::ptrdiff_t>(bucket_index);
|
||||
}
|
||||
|
||||
previous_pointer get_previous_start() const
|
||||
{
|
||||
return get_bucket(bucket_count_)->first_from_start();
|
||||
}
|
||||
|
||||
previous_pointer get_previous_start(std::size_t bucket_index) const
|
||||
{
|
||||
return get_bucket(bucket_index)->next_;
|
||||
}
|
||||
|
||||
iterator begin() const
|
||||
{
|
||||
return size_ ? iterator(static_cast<node_pointer>(
|
||||
get_previous_start()->next_)) : iterator();
|
||||
}
|
||||
|
||||
iterator begin(std::size_t bucket_index) const
|
||||
{
|
||||
if (!size_) return iterator();
|
||||
previous_pointer prev = get_previous_start(bucket_index);
|
||||
return prev ? iterator(static_cast<node_pointer>(prev->next_)) :
|
||||
iterator();
|
||||
}
|
||||
|
||||
float load_factor() const
|
||||
{
|
||||
BOOST_ASSERT(bucket_count_ != 0);
|
||||
return static_cast<float>(size_)
|
||||
/ static_cast<float>(bucket_count_);
|
||||
}
|
||||
|
||||
std::size_t bucket_size(std::size_t index) const
|
||||
{
|
||||
iterator it = begin(index);
|
||||
if (!it.node_) return 0;
|
||||
|
||||
std::size_t count = 0;
|
||||
while(it.node_ && policy::to_bucket(
|
||||
bucket_count_, it.node_->hash_) == index)
|
||||
{
|
||||
++count;
|
||||
++it;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
std::size_t max_load_; // Only use if this->buckets_.
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Load methods
|
||||
@@ -282,34 +109,34 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
// size < mlf_ * count
|
||||
return boost::unordered::detail::double_to_size(ceil(
|
||||
static_cast<double>(mlf_) *
|
||||
static_cast<double>(max_bucket_count())
|
||||
static_cast<double>(this->mlf_) *
|
||||
static_cast<double>(this->max_bucket_count())
|
||||
)) - 1;
|
||||
}
|
||||
|
||||
void recalculate_max_load()
|
||||
std::size_t calculate_max_load()
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
// From 6.3.1/13:
|
||||
// Only resize when size >= mlf_ * count
|
||||
max_load_ = buckets_ ? boost::unordered::detail::double_to_size(ceil(
|
||||
static_cast<double>(mlf_) *
|
||||
static_cast<double>(bucket_count_)
|
||||
)) : 0;
|
||||
return boost::unordered::detail::double_to_size(ceil(
|
||||
static_cast<double>(this->mlf_) *
|
||||
static_cast<double>(this->bucket_count_)
|
||||
));
|
||||
|
||||
}
|
||||
|
||||
void max_load_factor(float z)
|
||||
{
|
||||
BOOST_ASSERT(z > 0);
|
||||
mlf_ = (std::max)(z, minimum_max_load_factor);
|
||||
recalculate_max_load();
|
||||
if (this->buckets_)
|
||||
this->max_load_ = this->calculate_max_load();
|
||||
}
|
||||
|
||||
std::size_t min_buckets_for_size(std::size_t size) const
|
||||
{
|
||||
BOOST_ASSERT(mlf_ >= minimum_max_load_factor);
|
||||
BOOST_ASSERT(this->mlf_ >= minimum_max_load_factor);
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -333,449 +160,127 @@ namespace boost { namespace unordered { namespace detail {
|
||||
hasher const& hf,
|
||||
key_equal const& eq,
|
||||
node_allocator const& a) :
|
||||
buckets(a, policy::new_bucket_count(num_buckets)),
|
||||
functions(hf, eq),
|
||||
allocators_(a,a),
|
||||
bucket_count_(policy::new_bucket_count(num_buckets)),
|
||||
size_(0),
|
||||
mlf_(1.0f),
|
||||
max_load_(0),
|
||||
buckets_()
|
||||
max_load_(0)
|
||||
{}
|
||||
|
||||
table(table const& x, node_allocator const& a) :
|
||||
buckets(a, x.min_buckets_for_size(x.size_)),
|
||||
functions(x),
|
||||
allocators_(a,a),
|
||||
bucket_count_(x.min_buckets_for_size(x.size_)),
|
||||
size_(0),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(0),
|
||||
buckets_()
|
||||
{}
|
||||
|
||||
table(table& x, boost::unordered::detail::move_tag m) :
|
||||
functions(x),
|
||||
allocators_(x.allocators_, m),
|
||||
bucket_count_(x.bucket_count_),
|
||||
size_(x.size_),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(x.max_load_),
|
||||
buckets_(x.buckets_)
|
||||
max_load_(0)
|
||||
{
|
||||
x.buckets_ = bucket_pointer();
|
||||
x.size_ = 0;
|
||||
x.max_load_ = 0;
|
||||
}
|
||||
|
||||
table(table& x, node_allocator const& a,
|
||||
boost::unordered::detail::move_tag) :
|
||||
functions(x),
|
||||
allocators_(a, a),
|
||||
bucket_count_(x.bucket_count_),
|
||||
size_(0),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(x.max_load_),
|
||||
buckets_()
|
||||
{}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Initialisation.
|
||||
|
||||
void init(table const& x)
|
||||
{
|
||||
if (x.size_) {
|
||||
create_buckets(bucket_count_);
|
||||
copy_nodes<node_allocator> copy(node_alloc());
|
||||
table_impl::fill_buckets(x.begin(), *this, copy);
|
||||
if(x.size_) {
|
||||
table_impl::copy_buckets_to(x, *this);
|
||||
this->max_load_ = calculate_max_load();
|
||||
}
|
||||
}
|
||||
|
||||
void move_init(table& x)
|
||||
// TODO: Why calculate_max_load?
|
||||
table(table& x, boost::unordered::detail::move_tag m) :
|
||||
buckets(x, m),
|
||||
functions(x),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(calculate_max_load())
|
||||
{}
|
||||
|
||||
// TODO: Why not calculate_max_load?
|
||||
// TODO: Why do I use x's bucket count?
|
||||
table(table& x, node_allocator const& a,
|
||||
boost::unordered::detail::move_tag m) :
|
||||
buckets(a, x.bucket_count_),
|
||||
functions(x),
|
||||
mlf_(x.mlf_),
|
||||
max_load_(x.max_load_)
|
||||
{
|
||||
if(node_alloc() == x.node_alloc()) {
|
||||
move_buckets_from(x);
|
||||
if(a == x.node_alloc()) {
|
||||
this->buckets::swap(x, false_type());
|
||||
}
|
||||
else if(x.size_) {
|
||||
// TODO: Could pick new bucket size?
|
||||
create_buckets(bucket_count_);
|
||||
// Use a temporary table because move_buckets_to leaves the
|
||||
// source container in a complete mess.
|
||||
|
||||
move_nodes<node_allocator> move(node_alloc());
|
||||
node_holder<node_allocator> nodes(x);
|
||||
table_impl::fill_buckets(nodes.begin(), *this, move);
|
||||
buckets tmp(x, m);
|
||||
table_impl::move_buckets_to(tmp, *this);
|
||||
this->max_load_ = calculate_max_load();
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Create buckets
|
||||
// Iterators
|
||||
|
||||
void create_buckets(std::size_t new_count)
|
||||
{
|
||||
boost::unordered::detail::array_constructor<bucket_allocator>
|
||||
constructor(bucket_alloc());
|
||||
|
||||
// Creates an extra bucket to act as the start node.
|
||||
constructor.construct(bucket(), new_count + 1);
|
||||
|
||||
if (buckets_)
|
||||
{
|
||||
// Copy the nodes to the new buckets, including the dummy
|
||||
// node if there is one.
|
||||
(constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(new_count))->next_ =
|
||||
(buckets_ + static_cast<std::ptrdiff_t>(
|
||||
bucket_count_))->next_;
|
||||
destroy_buckets();
|
||||
}
|
||||
else if (bucket::extra_node)
|
||||
{
|
||||
node_constructor a(node_alloc());
|
||||
a.construct();
|
||||
|
||||
(constructor.get() +
|
||||
static_cast<std::ptrdiff_t>(new_count))->next_ =
|
||||
a.release();
|
||||
}
|
||||
|
||||
bucket_count_ = new_count;
|
||||
buckets_ = constructor.release();
|
||||
recalculate_max_load();
|
||||
iterator begin() const {
|
||||
return !this->buckets_ ?
|
||||
iterator() : this->get_start();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Swap and Move
|
||||
|
||||
void swap_allocators(table& other, false_type)
|
||||
{
|
||||
// According to 23.2.1.8, if propagate_on_container_swap is
|
||||
// false the behaviour is undefined unless the allocators
|
||||
// are equal.
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
}
|
||||
|
||||
void swap_allocators(table& other, true_type)
|
||||
{
|
||||
allocators_.swap(other.allocators_);
|
||||
}
|
||||
|
||||
// Only swaps the allocators if propagate_on_container_swap
|
||||
void swap(table& x)
|
||||
{
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
op1(*this, x);
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
op2(x, *this);
|
||||
|
||||
// I think swap can throw if Propagate::value,
|
||||
// since the allocators' swap can throw. Not sure though.
|
||||
swap_allocators(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_swap::value>());
|
||||
|
||||
boost::swap(buckets_, x.buckets_);
|
||||
boost::swap(bucket_count_, x.bucket_count_);
|
||||
boost::swap(size_, x.size_);
|
||||
std::swap(mlf_, x.mlf_);
|
||||
std::swap(max_load_, x.max_load_);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
|
||||
void move_buckets_from(table& other)
|
||||
{
|
||||
BOOST_ASSERT(node_alloc() == other.node_alloc());
|
||||
BOOST_ASSERT(!buckets_);
|
||||
buckets_ = other.buckets_;
|
||||
bucket_count_ = other.bucket_count_;
|
||||
size_ = other.size_;
|
||||
other.buckets_ = bucket_pointer();
|
||||
other.size_ = 0;
|
||||
other.max_load_ = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Delete/destruct
|
||||
|
||||
~table()
|
||||
{
|
||||
delete_buckets();
|
||||
}
|
||||
|
||||
void delete_node(c_iterator n)
|
||||
{
|
||||
boost::unordered::detail::destroy_value_impl(node_alloc(),
|
||||
n.node_->value_ptr());
|
||||
node_allocator_traits::destroy(node_alloc(),
|
||||
boost::addressof(*n.node_));
|
||||
node_allocator_traits::deallocate(node_alloc(), n.node_, 1);
|
||||
--size_;
|
||||
}
|
||||
|
||||
std::size_t delete_nodes(c_iterator begin, c_iterator end)
|
||||
{
|
||||
std::size_t count = 0;
|
||||
|
||||
while(begin != end) {
|
||||
c_iterator n = begin;
|
||||
++begin;
|
||||
delete_node(n);
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void delete_buckets()
|
||||
{
|
||||
if(buckets_) {
|
||||
delete_nodes(begin(), iterator());
|
||||
|
||||
if (bucket::extra_node) {
|
||||
node_pointer n = static_cast<node_pointer>(
|
||||
get_bucket(bucket_count_)->next_);
|
||||
node_allocator_traits::destroy(node_alloc(),
|
||||
boost::addressof(*n));
|
||||
node_allocator_traits::deallocate(node_alloc(), n, 1);
|
||||
}
|
||||
|
||||
destroy_buckets();
|
||||
buckets_ = bucket_pointer();
|
||||
max_load_ = 0;
|
||||
}
|
||||
|
||||
BOOST_ASSERT(!size_);
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
if(!size_) return;
|
||||
|
||||
delete_nodes(begin(), iterator());
|
||||
get_previous_start()->next_ = link_pointer();
|
||||
clear_buckets();
|
||||
|
||||
BOOST_ASSERT(!size_);
|
||||
}
|
||||
|
||||
void clear_buckets()
|
||||
{
|
||||
bucket_pointer end = get_bucket(bucket_count_);
|
||||
for(bucket_pointer it = buckets_; it != end; ++it)
|
||||
{
|
||||
it->next_ = node_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
void destroy_buckets()
|
||||
{
|
||||
bucket_pointer end = get_bucket(bucket_count_ + 1);
|
||||
for(bucket_pointer it = buckets_; it != end; ++it)
|
||||
{
|
||||
bucket_allocator_traits::destroy(bucket_alloc(),
|
||||
boost::addressof(*it));
|
||||
}
|
||||
|
||||
bucket_allocator_traits::deallocate(bucket_alloc(),
|
||||
buckets_, bucket_count_ + 1);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Fix buckets after erase
|
||||
|
||||
// This is called after erasing a node or group of nodes to fix up
|
||||
// the bucket pointers.
|
||||
void fix_buckets(bucket_pointer this_bucket,
|
||||
previous_pointer prev, node_pointer next)
|
||||
{
|
||||
if (!next)
|
||||
{
|
||||
if (this_bucket->next_ == prev)
|
||||
this_bucket->next_ = node_pointer();
|
||||
}
|
||||
else
|
||||
{
|
||||
bucket_pointer next_bucket = get_bucket(
|
||||
policy::to_bucket(bucket_count_, next->hash_));
|
||||
|
||||
if (next_bucket != this_bucket)
|
||||
{
|
||||
next_bucket->next_ = prev;
|
||||
if (this_bucket->next_ == prev)
|
||||
this_bucket->next_ = node_pointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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,
|
||||
previous_pointer prev, node_pointer begin, node_pointer end)
|
||||
{
|
||||
node_pointer n = begin;
|
||||
|
||||
// If we're not at the start of the current bucket, then
|
||||
// go to the start of the next bucket.
|
||||
if (get_bucket(bucket_index)->next_ != prev)
|
||||
{
|
||||
for(;;) {
|
||||
n = static_cast<node_pointer>(n->next_);
|
||||
if (n == end) {
|
||||
if (n) {
|
||||
std::size_t new_bucket_index =
|
||||
policy::to_bucket(bucket_count_, n->hash_);
|
||||
if (bucket_index != new_bucket_index) {
|
||||
get_bucket(new_bucket_index)->next_ = prev;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
std::size_t new_bucket_index =
|
||||
policy::to_bucket(bucket_count_, n->hash_);
|
||||
if (bucket_index != new_bucket_index) {
|
||||
bucket_index = new_bucket_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Iterate through the remaining nodes, clearing out the bucket
|
||||
// pointers.
|
||||
get_bucket(bucket_index)->next_ = previous_pointer();
|
||||
for(;;) {
|
||||
n = static_cast<node_pointer>(n->next_);
|
||||
if (n == end) break;
|
||||
|
||||
std::size_t new_bucket_index =
|
||||
policy::to_bucket(bucket_count_, n->hash_);
|
||||
if (bucket_index != new_bucket_index) {
|
||||
bucket_index = new_bucket_index;
|
||||
get_bucket(bucket_index)->next_ = previous_pointer();
|
||||
}
|
||||
};
|
||||
|
||||
// Finally fix the bucket containing the trailing node.
|
||||
if (n) {
|
||||
get_bucket(
|
||||
policy::to_bucket(bucket_count_, n->hash_))->next_
|
||||
= prev;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Assignment
|
||||
|
||||
void assign(table const& x)
|
||||
{
|
||||
if (this != boost::addressof(x))
|
||||
{
|
||||
assign(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_copy_assignment::value>());
|
||||
}
|
||||
assign(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_copy_assignment::value>());
|
||||
}
|
||||
|
||||
void assign(table const& x, false_type)
|
||||
{
|
||||
// Strong exception safety.
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
new_func_this(*this, x);
|
||||
new_func_this.commit();
|
||||
mlf_ = x.mlf_;
|
||||
recalculate_max_load();
|
||||
|
||||
if (!size_ && !x.size_) return;
|
||||
|
||||
if (x.size_ >= max_load_) {
|
||||
create_buckets(min_buckets_for_size(x.size_));
|
||||
}
|
||||
else {
|
||||
clear_buckets();
|
||||
}
|
||||
|
||||
// assign_nodes takes ownership of the container's elements,
|
||||
// assigning to them if possible, and deleting any that are
|
||||
// left over.
|
||||
assign_nodes<table> assign(*this);
|
||||
table_impl::fill_buckets(x.begin(), *this, assign);
|
||||
table tmp(x, this->node_alloc());
|
||||
this->swap(tmp, false_type());
|
||||
}
|
||||
|
||||
void assign(table const& x, true_type)
|
||||
{
|
||||
if (node_alloc() == x.node_alloc()) {
|
||||
allocators_.assign(x.allocators_);
|
||||
assign(x, false_type());
|
||||
}
|
||||
else {
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
new_func_this(*this, x);
|
||||
|
||||
// Delete everything with current allocators before assigning
|
||||
// the new ones.
|
||||
delete_buckets();
|
||||
allocators_.assign(x.allocators_);
|
||||
|
||||
// Copy over other data, all no throw.
|
||||
new_func_this.commit();
|
||||
mlf_ = x.mlf_;
|
||||
bucket_count_ = min_buckets_for_size(x.size_);
|
||||
max_load_ = 0;
|
||||
|
||||
// Finally copy the elements.
|
||||
if (x.size_) {
|
||||
create_buckets(bucket_count_);
|
||||
copy_nodes<node_allocator> copy(node_alloc());
|
||||
table_impl::fill_buckets(x.begin(), *this, copy);
|
||||
}
|
||||
}
|
||||
table tmp(x, x.node_alloc());
|
||||
// Need to delete before setting the allocator so that buckets
|
||||
// aren't deleted with the wrong allocator.
|
||||
if(this->buckets_) this->delete_buckets();
|
||||
// TODO: Can allocator assignment throw?
|
||||
this->allocators_.assign(x.allocators_);
|
||||
this->swap(tmp, false_type());
|
||||
}
|
||||
|
||||
void move_assign(table& x)
|
||||
{
|
||||
if (this != boost::addressof(x))
|
||||
{
|
||||
move_assign(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_move_assignment::value>());
|
||||
}
|
||||
move_assign(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_move_assignment::value>());
|
||||
}
|
||||
|
||||
void move_assign(table& x, true_type)
|
||||
{
|
||||
delete_buckets();
|
||||
allocators_.move_assign(x.allocators_);
|
||||
if(this->buckets_) this->delete_buckets();
|
||||
this->allocators_.move_assign(x.allocators_);
|
||||
move_assign_no_alloc(x);
|
||||
}
|
||||
|
||||
void move_assign(table& x, false_type)
|
||||
{
|
||||
if (node_alloc() == x.node_alloc()) {
|
||||
delete_buckets();
|
||||
if(this->node_alloc() == x.node_alloc()) {
|
||||
if(this->buckets_) this->delete_buckets();
|
||||
move_assign_no_alloc(x);
|
||||
}
|
||||
else {
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
new_func_this(*this, x);
|
||||
new_func_this.commit();
|
||||
mlf_ = x.mlf_;
|
||||
recalculate_max_load();
|
||||
|
||||
if (!size_ && !x.size_) return;
|
||||
|
||||
if (x.size_ >= max_load_) {
|
||||
create_buckets(min_buckets_for_size(x.size_));
|
||||
if (x.size_) {
|
||||
buckets b(this->node_alloc(),
|
||||
x.min_buckets_for_size(x.size_));
|
||||
buckets tmp(x, move_tag());
|
||||
table_impl::move_buckets_to(tmp, b);
|
||||
b.swap(*this);
|
||||
}
|
||||
else {
|
||||
clear_buckets();
|
||||
this->clear();
|
||||
}
|
||||
|
||||
// move_assign_nodes takes ownership of the container's
|
||||
// elements, assigning to them if possible, and deleting
|
||||
// any that are left over.
|
||||
move_assign_nodes<table> assign(*this);
|
||||
node_holder<node_allocator> nodes(x);
|
||||
table_impl::fill_buckets(nodes.begin(), *this, assign);
|
||||
|
||||
this->mlf_ = x.mlf_;
|
||||
if (this->buckets_) this->max_load_ = calculate_max_load();
|
||||
new_func_this.commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -784,12 +289,48 @@ namespace boost { namespace unordered { namespace detail {
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
new_func_this(*this, x);
|
||||
// No throw from here.
|
||||
mlf_ = x.mlf_;
|
||||
max_load_ = x.max_load_;
|
||||
move_buckets_from(x);
|
||||
this->move_buckets_from(x);
|
||||
this->mlf_ = x.mlf_;
|
||||
this->max_load_ = x.max_load_;
|
||||
new_func_this.commit();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Swap & Move
|
||||
|
||||
void swap(table& x)
|
||||
{
|
||||
swap(x,
|
||||
boost::unordered::detail::integral_constant<bool,
|
||||
allocator_traits<node_allocator>::
|
||||
propagate_on_container_swap::value>());
|
||||
}
|
||||
|
||||
// Only swaps the allocators if Propagate::value
|
||||
template <typename Propagate>
|
||||
void swap(table& x, Propagate p)
|
||||
{
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
op1(*this, x);
|
||||
boost::unordered::detail::set_hash_functions<hasher, key_equal>
|
||||
op2(x, *this);
|
||||
// I think swap can throw if Propagate::value,
|
||||
// since the allocators' swap can throw. Not sure though.
|
||||
this->buckets::swap(x, p);
|
||||
std::swap(this->mlf_, x.mlf_);
|
||||
std::swap(this->max_load_, x.max_load_);
|
||||
op1.commit();
|
||||
op2.commit();
|
||||
}
|
||||
|
||||
// Swap everything but the allocators, and the functions objects.
|
||||
void swap_contents(table& x)
|
||||
{
|
||||
this->buckets::swap(x, false_type());
|
||||
std::swap(this->mlf_, x.mlf_);
|
||||
std::swap(this->max_load_, x.max_load_);
|
||||
}
|
||||
|
||||
// Accessors
|
||||
|
||||
key_type const& get_key(value_type const& x) const
|
||||
@@ -810,6 +351,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
Hash const& hf,
|
||||
Pred const& eq) const
|
||||
{
|
||||
if (!this->size_) return iterator();
|
||||
return static_cast<table_impl const*>(this)->
|
||||
find_node_impl(policy::apply_hash(hf, k), k, eq);
|
||||
}
|
||||
@@ -818,14 +360,16 @@ namespace boost { namespace unordered { namespace detail {
|
||||
std::size_t key_hash,
|
||||
key_type const& k) const
|
||||
{
|
||||
if (!this->size_) return iterator();
|
||||
return static_cast<table_impl const*>(this)->
|
||||
find_node_impl(key_hash, k, this->key_eq());
|
||||
}
|
||||
|
||||
iterator find_node(key_type const& k) const
|
||||
{
|
||||
if (!this->size_) return iterator();
|
||||
return static_cast<table_impl const*>(this)->
|
||||
find_node_impl(hash(k), k, this->key_eq());
|
||||
find_node_impl(this->hash(k), k, this->key_eq());
|
||||
}
|
||||
|
||||
iterator find_matching_node(iterator n) const
|
||||
@@ -853,19 +397,22 @@ namespace boost { namespace unordered { namespace detail {
|
||||
template <typename Types>
|
||||
inline void table<Types>::reserve_for_insert(std::size_t size)
|
||||
{
|
||||
if (!buckets_) {
|
||||
create_buckets((std::max)(bucket_count_,
|
||||
min_buckets_for_size(size)));
|
||||
if (!this->buckets_) {
|
||||
this->bucket_count_ = (std::max)(this->bucket_count_,
|
||||
this->min_buckets_for_size(size));
|
||||
this->create_buckets();
|
||||
this->max_load_ = this->calculate_max_load();
|
||||
}
|
||||
// According to the standard this should be 'size >= max_load_',
|
||||
// but I think this is better, defect report filed.
|
||||
else if(size > max_load_) {
|
||||
std::size_t num_buckets
|
||||
= min_buckets_for_size((std::max)(size,
|
||||
size_ + (size_ >> 1)));
|
||||
|
||||
if (num_buckets != bucket_count_)
|
||||
= this->min_buckets_for_size((std::max)(size,
|
||||
this->size_ + (this->size_ >> 1)));
|
||||
if (num_buckets != this->bucket_count_) {
|
||||
static_cast<table_impl*>(this)->rehash_impl(num_buckets);
|
||||
this->max_load_ = this->calculate_max_load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -877,18 +424,20 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
using namespace std;
|
||||
|
||||
if(!size_) {
|
||||
delete_buckets();
|
||||
bucket_count_ = policy::new_bucket_count(min_buckets);
|
||||
if(!this->size_) {
|
||||
if(this->buckets_) this->delete_buckets();
|
||||
this->bucket_count_ = policy::new_bucket_count(min_buckets);
|
||||
}
|
||||
else {
|
||||
min_buckets = policy::new_bucket_count((std::max)(min_buckets,
|
||||
boost::unordered::detail::double_to_size(floor(
|
||||
static_cast<double>(size_) /
|
||||
static_cast<double>(this->size_) /
|
||||
static_cast<double>(mlf_))) + 1));
|
||||
|
||||
if(min_buckets != bucket_count_)
|
||||
if(min_buckets != this->bucket_count_) {
|
||||
static_cast<table_impl*>(this)->rehash_impl(min_buckets);
|
||||
this->max_load_ = this->calculate_max_load();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -896,12 +445,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
inline void table<Types>::reserve(std::size_t num_elements)
|
||||
{
|
||||
rehash(static_cast<std::size_t>(
|
||||
std::ceil(static_cast<double>(num_elements) / mlf_)));
|
||||
std::ceil(static_cast<double>(num_elements) / this->mlf_)));
|
||||
}
|
||||
}}}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,25 +24,41 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
template <typename A, typename T>
|
||||
struct unique_node :
|
||||
boost::unordered::detail::node_base<
|
||||
typename ::boost::unordered::detail::rebind_wrap<
|
||||
A, unique_node<A, T> >::type::pointer
|
||||
>,
|
||||
boost::unordered::detail::value_base<T>
|
||||
{
|
||||
typedef typename ::boost::unordered::detail::rebind_wrap<
|
||||
A, unique_node<A, T> >::type::pointer link_pointer;
|
||||
typedef boost::unordered::detail::node_base<link_pointer> node_base;
|
||||
|
||||
link_pointer next_;
|
||||
std::size_t hash_;
|
||||
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
unique_node(BOOST_UNORDERED_EMPLACE_ARGS) :
|
||||
node_base(),
|
||||
hash_(0)
|
||||
{
|
||||
boost::unordered::detail::construct_impl(
|
||||
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
}
|
||||
|
||||
~unique_node() {
|
||||
boost::unordered::detail::destroy(this->value_ptr());
|
||||
}
|
||||
#else
|
||||
unique_node() :
|
||||
next_(),
|
||||
node_base(),
|
||||
hash_(0)
|
||||
{}
|
||||
#endif
|
||||
|
||||
void init(link_pointer)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
unique_node& operator=(unique_node const&);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
@@ -51,21 +67,34 @@ namespace boost { namespace unordered { namespace detail {
|
||||
boost::unordered::detail::ptr_bucket
|
||||
{
|
||||
typedef boost::unordered::detail::ptr_bucket bucket_base;
|
||||
typedef bucket_base node_base;
|
||||
typedef ptr_bucket* link_pointer;
|
||||
|
||||
std::size_t hash_;
|
||||
|
||||
#if BOOST_UNORDERED_DETAIL_FULL_CONSTRUCT
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
ptr_node(BOOST_UNORDERED_EMPLACE_ARGS) :
|
||||
bucket_base(),
|
||||
hash_(0)
|
||||
{
|
||||
boost::unordered::detail::construct_impl(
|
||||
this->value_ptr(), BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
}
|
||||
|
||||
~ptr_node() {
|
||||
boost::unordered::detail::destroy(this->value_ptr());
|
||||
}
|
||||
#else
|
||||
ptr_node() :
|
||||
bucket_base(),
|
||||
hash_(0)
|
||||
{}
|
||||
#endif
|
||||
|
||||
void init(link_pointer)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
ptr_node& operator=(ptr_node const&);
|
||||
};
|
||||
|
||||
// If the allocator uses raw pointers use ptr_node
|
||||
@@ -121,12 +150,14 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef T value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef T key_type;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<
|
||||
A, value_type>::type allocator;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
@@ -144,14 +175,15 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
typedef boost::unordered::detail::map<A, K, M, H, P> types;
|
||||
|
||||
typedef A allocator;
|
||||
typedef std::pair<K const, M> value_type;
|
||||
typedef H hasher;
|
||||
typedef P key_equal;
|
||||
typedef K key_type;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator>
|
||||
traits;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<
|
||||
A, value_type>::type allocator;
|
||||
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
typedef boost::unordered::detail::pick_node<allocator, value_type> pick;
|
||||
typedef typename pick::node node;
|
||||
typedef typename pick::bucket bucket;
|
||||
@@ -170,6 +202,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
typedef boost::unordered::detail::table<Types> table;
|
||||
typedef typename table::value_type value_type;
|
||||
typedef typename table::bucket bucket;
|
||||
typedef typename table::buckets buckets;
|
||||
typedef typename table::policy policy;
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
typedef typename table::node_allocator node_allocator;
|
||||
@@ -198,17 +231,12 @@ namespace boost { namespace unordered { namespace detail {
|
||||
|
||||
table_impl(table_impl const& x)
|
||||
: table(x, node_allocator_traits::
|
||||
select_on_container_copy_construction(x.node_alloc()))
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
select_on_container_copy_construction(x.node_alloc())) {}
|
||||
|
||||
table_impl(table_impl const& x,
|
||||
node_allocator const& a)
|
||||
: table(x, a)
|
||||
{
|
||||
this->init(x);
|
||||
}
|
||||
{}
|
||||
|
||||
table_impl(table_impl& x,
|
||||
boost::unordered::detail::move_tag m)
|
||||
@@ -219,9 +247,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
node_allocator const& a,
|
||||
boost::unordered::detail::move_tag m)
|
||||
: table(x, a, m)
|
||||
{
|
||||
this->move_init(x);
|
||||
}
|
||||
{}
|
||||
|
||||
// Accessors
|
||||
|
||||
@@ -233,7 +259,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
std::size_t bucket_index =
|
||||
policy::to_bucket(this->bucket_count_, key_hash);
|
||||
iterator n = this->begin(bucket_index);
|
||||
iterator n = this->get_start(bucket_index);
|
||||
|
||||
for (;;)
|
||||
{
|
||||
@@ -286,8 +312,9 @@ namespace boost { namespace unordered { namespace detail {
|
||||
bool equals(table_impl const& other) const
|
||||
{
|
||||
if(this->size_ != other.size_) return false;
|
||||
if(!this->size_) return true;
|
||||
|
||||
for(iterator n1 = this->begin(); n1.node_; ++n1)
|
||||
for(iterator n1 = this->get_start(); n1.node_; ++n1)
|
||||
{
|
||||
iterator n2 = other.find_matching_node(n1);
|
||||
|
||||
@@ -351,40 +378,39 @@ namespace boost { namespace unordered { namespace detail {
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_ARGS3(
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(k),
|
||||
boost::make_tuple()));
|
||||
a.construct_node();
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
a.construct_value(boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(k), boost::make_tuple());
|
||||
#else
|
||||
a.construct_value(
|
||||
boost::unordered::detail::create_emplace_args(
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(k),
|
||||
boost::make_tuple()));
|
||||
#endif
|
||||
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
return *add_node(a, key_hash);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
# if defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
emplace_return emplace(boost::unordered::detail::emplace_args1<
|
||||
boost::unordered::detail::please_ignore_this_overload> const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return emplace_return(this->begin(), false);
|
||||
}
|
||||
# else
|
||||
emplace_return emplace(
|
||||
boost::unordered::detail::please_ignore_this_overload const&)
|
||||
{
|
||||
BOOST_ASSERT(false);
|
||||
return emplace_return(this->begin(), false);
|
||||
}
|
||||
# endif
|
||||
#endif
|
||||
|
||||
template <BOOST_UNORDERED_EMPLACE_TEMPLATE>
|
||||
emplace_return emplace(BOOST_UNORDERED_EMPLACE_ARGS)
|
||||
{
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
return emplace_impl(
|
||||
extractor::extract(BOOST_UNORDERED_EMPLACE_FORWARD),
|
||||
BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
|
||||
#else
|
||||
return emplace_impl(
|
||||
extractor::extract(args.a0, args.a1),
|
||||
@@ -392,7 +418,7 @@ namespace boost { namespace unordered { namespace detail {
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if !defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <typename A0>
|
||||
emplace_return emplace(
|
||||
boost::unordered::detail::emplace_args1<A0> const& args)
|
||||
@@ -413,7 +439,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
// Create the node before rehashing in case it throws an
|
||||
// exception (need strong safety in such a case).
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
a.construct_node();
|
||||
a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
|
||||
// reserve has basic exception safety if the hash function
|
||||
// throws, strong otherwise.
|
||||
@@ -441,7 +468,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
// Don't have a key, so construct the node first in order
|
||||
// to be able to lookup the position.
|
||||
node_constructor a(this->node_alloc());
|
||||
a.construct_with_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
a.construct_node();
|
||||
a.construct_value(BOOST_UNORDERED_EMPLACE_FORWARD);
|
||||
return emplace_impl_with_node(a);
|
||||
}
|
||||
|
||||
@@ -463,9 +491,14 @@ namespace boost { namespace unordered { namespace detail {
|
||||
{
|
||||
node_constructor a(this->node_alloc());
|
||||
|
||||
insert_range_impl2(a, k, i, j);
|
||||
// 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, k, i, j);
|
||||
if (++i == j) return;
|
||||
}
|
||||
|
||||
while(++i != j) {
|
||||
do {
|
||||
// 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.
|
||||
@@ -475,7 +508,19 @@ namespace boost { namespace unordered { namespace detail {
|
||||
// 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 InputIt>
|
||||
void insert_range_empty(node_constructor& a, key_type const& k,
|
||||
InputIt i, InputIt j)
|
||||
{
|
||||
std::size_t key_hash = this->hash(k);
|
||||
a.construct_node();
|
||||
a.construct_value2(*i);
|
||||
this->reserve_for_insert(this->size_ +
|
||||
boost::unordered::detail::insert_size(i, j));
|
||||
this->add_node(a, key_hash);
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
@@ -487,7 +532,9 @@ namespace boost { namespace unordered { namespace detail {
|
||||
iterator pos = this->find_node(key_hash, k);
|
||||
|
||||
if (!pos.node_) {
|
||||
a.construct_with_value2(*i);
|
||||
a.construct_node();
|
||||
a.construct_value2(*i);
|
||||
|
||||
if(this->size_ + 1 > this->max_load_)
|
||||
this->reserve_for_insert(this->size_ +
|
||||
boost::unordered::detail::insert_size(i, j));
|
||||
@@ -503,7 +550,8 @@ namespace boost { namespace unordered { namespace detail {
|
||||
node_constructor a(this->node_alloc());
|
||||
|
||||
do {
|
||||
a.construct_with_value2(*i);
|
||||
a.construct_node();
|
||||
a.construct_value2(*i);
|
||||
emplace_impl_with_node(a);
|
||||
} while(++i != j);
|
||||
}
|
||||
@@ -595,16 +643,58 @@ namespace boost { namespace unordered { namespace detail {
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// fill_buckets
|
||||
// copy_buckets_to
|
||||
//
|
||||
// Basic exception safety. If an exception is thrown this will
|
||||
// leave dst partially filled and the buckets unset.
|
||||
|
||||
template <class NodeCreator>
|
||||
static void fill_buckets(iterator n, table& dst,
|
||||
NodeCreator& creator)
|
||||
static void copy_buckets_to(buckets const& src, buckets& dst)
|
||||
{
|
||||
BOOST_ASSERT(!dst.buckets_);
|
||||
|
||||
dst.create_buckets();
|
||||
|
||||
node_constructor a(dst.node_alloc());
|
||||
|
||||
iterator n = src.get_start();
|
||||
previous_pointer prev = dst.get_previous_start();
|
||||
|
||||
while(n.node_) {
|
||||
a.construct_node();
|
||||
a.construct_value2(*n);
|
||||
|
||||
node_pointer node = a.release();
|
||||
node->hash_ = n.node_->hash_;
|
||||
prev->next_ = static_cast<link_pointer>(node);
|
||||
++dst.size_;
|
||||
++n;
|
||||
|
||||
prev = place_in_bucket(dst, prev);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// move_buckets_to
|
||||
//
|
||||
// Basic exception safety. The source nodes are left in an unusable
|
||||
// state if an exception throws.
|
||||
|
||||
static void move_buckets_to(buckets& src, buckets& dst)
|
||||
{
|
||||
BOOST_ASSERT(!dst.buckets_);
|
||||
|
||||
dst.create_buckets();
|
||||
|
||||
node_constructor a(dst.node_alloc());
|
||||
|
||||
iterator n = src.get_start();
|
||||
previous_pointer prev = dst.get_previous_start();
|
||||
|
||||
while (n.node_) {
|
||||
node_pointer node = creator.create(*n);
|
||||
a.construct_node();
|
||||
a.construct_value2(boost::move(*n));
|
||||
|
||||
node_pointer node = a.release();
|
||||
node->hash_ = n.node_->hash_;
|
||||
prev->next_ = static_cast<link_pointer>(node);
|
||||
++dst.size_;
|
||||
@@ -617,22 +707,36 @@ namespace boost { namespace unordered { namespace detail {
|
||||
// strong otherwise exception safety
|
||||
void rehash_impl(std::size_t num_buckets)
|
||||
{
|
||||
BOOST_ASSERT(this->buckets_);
|
||||
BOOST_ASSERT(this->size_);
|
||||
|
||||
this->create_buckets(num_buckets);
|
||||
previous_pointer prev = this->get_previous_start();
|
||||
buckets dst(this->node_alloc(), num_buckets);
|
||||
dst.create_buckets();
|
||||
|
||||
previous_pointer src_start = this->get_previous_start();
|
||||
previous_pointer dst_start = dst.get_previous_start();
|
||||
|
||||
dst_start->next_ = src_start->next_;
|
||||
src_start->next_ = link_pointer();
|
||||
dst.size_ = this->size_;
|
||||
this->size_ = 0;
|
||||
|
||||
previous_pointer prev = dst.get_previous_start();
|
||||
while (prev->next_)
|
||||
prev = place_in_bucket(*this, prev);
|
||||
prev = place_in_bucket(dst, prev);
|
||||
|
||||
// Swap the new nodes back into the container and setup the
|
||||
// variables.
|
||||
dst.swap(*this); // no throw
|
||||
}
|
||||
|
||||
// Iterate through the nodes placing them in the correct buckets.
|
||||
// pre: prev->next_ is not null.
|
||||
static previous_pointer place_in_bucket(table& dst,
|
||||
static previous_pointer place_in_bucket(buckets& dst,
|
||||
previous_pointer prev)
|
||||
{
|
||||
node_pointer n = static_cast<node_pointer>(prev->next_);
|
||||
bucket_pointer b = dst.get_bucket(
|
||||
table::to_bucket(dst.bucket_count_, n->hash_));
|
||||
buckets::to_bucket(dst.bucket_count_, n->hash_));
|
||||
|
||||
if (!b->next_) {
|
||||
b->next_ = prev;
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/unordered/detail/equivalent.hpp>
|
||||
#include <boost/unordered/detail/unique.hpp>
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
#include <initializer_list>
|
||||
#endif
|
||||
|
||||
@@ -56,6 +57,7 @@ namespace unordered
|
||||
private:
|
||||
|
||||
typedef boost::unordered::detail::map<A, K, T, H, P> types;
|
||||
typedef typename types::allocator value_allocator;
|
||||
typedef typename types::traits allocator_traits;
|
||||
typedef typename types::table table;
|
||||
|
||||
@@ -131,7 +133,7 @@ namespace unordered
|
||||
unordered_map(unordered_map&&, allocator_type const&);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_map(
|
||||
std::initializer_list<value_type>,
|
||||
size_type = boost::unordered::detail::default_bucket_count,
|
||||
@@ -174,7 +176,7 @@ namespace unordered
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_map& operator=(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -231,15 +233,15 @@ namespace unordered
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args)
|
||||
std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
|
||||
iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...).first;
|
||||
}
|
||||
@@ -399,7 +401,7 @@ namespace unordered
|
||||
|
||||
template <class InputIt> void insert(InputIt, InputIt);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -469,14 +471,16 @@ namespace unordered
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
local_iterator end(size_type)
|
||||
@@ -491,8 +495,9 @@ namespace unordered
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -538,6 +543,7 @@ namespace unordered
|
||||
private:
|
||||
|
||||
typedef boost::unordered::detail::multimap<A, K, T, H, P> types;
|
||||
typedef typename types::allocator value_allocator;
|
||||
typedef typename types::traits allocator_traits;
|
||||
typedef typename types::table table;
|
||||
|
||||
@@ -613,7 +619,7 @@ namespace unordered
|
||||
unordered_multimap(unordered_multimap&&, allocator_type const&);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_multimap(
|
||||
std::initializer_list<value_type>,
|
||||
size_type = boost::unordered::detail::default_bucket_count,
|
||||
@@ -657,7 +663,7 @@ namespace unordered
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_multimap& operator=(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -714,15 +720,15 @@ namespace unordered
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <class... Args>
|
||||
iterator emplace(BOOST_FWD_REF(Args)... args)
|
||||
iterator emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
|
||||
iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...);
|
||||
}
|
||||
@@ -882,7 +888,7 @@ namespace unordered
|
||||
|
||||
template <class InputIt> void insert(InputIt, InputIt);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -948,14 +954,16 @@ namespace unordered
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
local_iterator end(size_type)
|
||||
@@ -970,8 +978,9 @@ namespace unordered
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -1079,7 +1088,7 @@ namespace unordered
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_map<K,T,H,P,A>::unordered_map(
|
||||
@@ -1121,7 +1130,7 @@ namespace unordered
|
||||
table_.insert_range(first, last);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void unordered_map<K,T,H,P,A>::insert(
|
||||
std::initializer_list<value_type> list)
|
||||
@@ -1412,7 +1421,7 @@ namespace unordered
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_multimap<K,T,H,P,A>::unordered_multimap(
|
||||
@@ -1454,7 +1463,7 @@ namespace unordered
|
||||
table_.insert_range(first, last);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
template <class K, class T, class H, class P, class A>
|
||||
void unordered_multimap<K,T,H,P,A>::insert(
|
||||
std::initializer_list<value_type> list)
|
||||
|
||||
@@ -14,13 +14,14 @@
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/unordered/detail/equivalent.hpp>
|
||||
#include <boost/unordered/detail/unique.hpp>
|
||||
#include <boost/unordered/detail/util.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
#include <initializer_list>
|
||||
#endif
|
||||
|
||||
@@ -54,6 +55,7 @@ namespace unordered
|
||||
private:
|
||||
|
||||
typedef boost::unordered::detail::set<A, T, H, P> types;
|
||||
typedef typename types::allocator value_allocator;
|
||||
typedef typename types::traits allocator_traits;
|
||||
typedef typename types::table table;
|
||||
|
||||
@@ -129,7 +131,7 @@ namespace unordered
|
||||
unordered_set(unordered_set&&, allocator_type const&);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_set(
|
||||
std::initializer_list<value_type>,
|
||||
size_type = boost::unordered::detail::default_bucket_count,
|
||||
@@ -172,7 +174,7 @@ namespace unordered
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_set& operator=(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -229,15 +231,15 @@ namespace unordered
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> emplace(BOOST_FWD_REF(Args)... args)
|
||||
std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
|
||||
iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...).first;
|
||||
}
|
||||
@@ -398,7 +400,7 @@ namespace unordered
|
||||
|
||||
template <class InputIt> void insert(InputIt, InputIt);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -454,14 +456,16 @@ namespace unordered
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
local_iterator end(size_type)
|
||||
@@ -476,8 +480,9 @@ namespace unordered
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -522,6 +527,7 @@ namespace unordered
|
||||
private:
|
||||
|
||||
typedef boost::unordered::detail::multiset<A, T, H, P> types;
|
||||
typedef typename types::allocator value_allocator;
|
||||
typedef typename types::traits allocator_traits;
|
||||
typedef typename types::table table;
|
||||
|
||||
@@ -597,7 +603,7 @@ namespace unordered
|
||||
unordered_multiset(unordered_multiset&&, allocator_type const&);
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_multiset(
|
||||
std::initializer_list<value_type>,
|
||||
size_type = boost::unordered::detail::default_bucket_count,
|
||||
@@ -641,7 +647,7 @@ namespace unordered
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
unordered_multiset& operator=(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -698,15 +704,15 @@ namespace unordered
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template <class... Args>
|
||||
iterator emplace(BOOST_FWD_REF(Args)... args)
|
||||
iterator emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator, BOOST_FWD_REF(Args)... args)
|
||||
iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return table_.emplace(boost::forward<Args>(args)...);
|
||||
}
|
||||
@@ -867,7 +873,7 @@ namespace unordered
|
||||
|
||||
template <class InputIt> void insert(InputIt, InputIt);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
@@ -923,14 +929,16 @@ namespace unordered
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator begin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
local_iterator end(size_type)
|
||||
@@ -945,8 +953,9 @@ namespace unordered
|
||||
|
||||
const_local_iterator cbegin(size_type n) const
|
||||
{
|
||||
return const_local_iterator(
|
||||
table_.begin(n), n, table_.bucket_count_);
|
||||
return table_.size_ ? const_local_iterator(
|
||||
table_.get_start(n), n, table_.bucket_count_) :
|
||||
const_local_iterator();
|
||||
}
|
||||
|
||||
const_local_iterator cend(size_type) const
|
||||
@@ -1054,7 +1063,7 @@ namespace unordered
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_set<T,H,P,A>::unordered_set(
|
||||
@@ -1096,7 +1105,7 @@ namespace unordered
|
||||
table_.insert_range(first, last);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
template <class T, class H, class P, class A>
|
||||
void unordered_set<T,H,P,A>::insert(
|
||||
std::initializer_list<value_type> list)
|
||||
@@ -1338,7 +1347,7 @@ namespace unordered
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_multiset<T,H,P,A>::unordered_multiset(
|
||||
@@ -1380,7 +1389,7 @@ namespace unordered
|
||||
table_.insert_range(first, last);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
template <class T, class H, class P, class A>
|
||||
void unordered_multiset<T,H,P,A>::insert(
|
||||
std::initializer_list<value_type> list)
|
||||
|
||||
@@ -39,40 +39,26 @@ template <class T>
|
||||
struct assign_base : public test::exception_base
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
T x,y;
|
||||
const T x,y;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME T::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::key_equal key_equal;
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
|
||||
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2,
|
||||
float mlf1 = 1.0, float mlf2 = 1.0) :
|
||||
assign_base(unsigned int count1, unsigned int count2, int tag1, int tag2) :
|
||||
x_values(count1),
|
||||
y_values(count2),
|
||||
x(x_values.begin(), x_values.end(), 0, hasher(tag1), key_equal(tag1),
|
||||
allocator_type(tag1)),
|
||||
y(y_values.begin(), y_values.end(), 0, hasher(tag2), key_equal(tag2),
|
||||
allocator_type(tag2))
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
}
|
||||
{}
|
||||
|
||||
typedef T data_type;
|
||||
T init() const { return T(x); }
|
||||
void run(T& x1) const { x1 = y; }
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x1) const
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it.
|
||||
T& y = const_cast<T&>(x1);
|
||||
if (x_values.size()) {
|
||||
y.emplace(*x_values.begin());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
{ test::check_equivalent_keys(x1); }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
@@ -99,13 +85,7 @@ struct assign_test4 : assign_base<T>
|
||||
assign_test4() : assign_base<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct assign_test5 : assign_base<T>
|
||||
{
|
||||
assign_test5() : assign_base<T>(5, 60, 0, 0, 1.0, 0.1) {}
|
||||
};
|
||||
|
||||
RUN_EXCEPTION_TESTS(
|
||||
(self_assign_test1)(self_assign_test2)
|
||||
(assign_test1)(assign_test2)(assign_test3)(assign_test4)(assign_test5),
|
||||
(assign_test1)(assign_test2)(assign_test3)(assign_test4),
|
||||
CONTAINER_SEQ)
|
||||
|
||||
@@ -18,13 +18,13 @@ typedef boost::unordered_multiset<
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> > test_multiset;
|
||||
test::exception::allocator<test::exception::object> > test_multiset;
|
||||
typedef boost::unordered_map<
|
||||
test::exception::object,
|
||||
test::exception::object,
|
||||
test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> > test_map;
|
||||
test::exception::allocator<test::exception::object> > test_map;
|
||||
typedef boost::unordered_multimap<
|
||||
test::exception::object,
|
||||
test::exception::object,
|
||||
|
||||
@@ -32,7 +32,7 @@ struct insert_test_base : public test::exception_base
|
||||
std::string scope(test::scope);
|
||||
|
||||
if(scope.find("hash::operator()") == std::string::npos)
|
||||
strong.test(x, test::detail::tracker.count_allocations);
|
||||
strong.test(x, test::exception::detail::tracker.count_allocations);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
};
|
||||
@@ -49,7 +49,7 @@ struct emplace_test1 : public insert_test_base<T>
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.emplace(*it);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,7 @@ struct insert_test1 : public insert_test_base<T>
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
}
|
||||
@@ -83,7 +83,7 @@ struct insert_test2 : public insert_test_base<T>
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(x.begin(), *it);
|
||||
}
|
||||
}
|
||||
@@ -111,7 +111,7 @@ struct insert_test4 : public insert_test_base<T>
|
||||
it = this->values.begin(), end = this->values.end();
|
||||
it != end; ++it)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(it, boost::next(it));
|
||||
}
|
||||
}
|
||||
@@ -150,7 +150,7 @@ struct insert_test_rehash1 : public insert_test_base<T>
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
pos = x.insert(pos, *it);
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ struct insert_test_rehash2 : public insert_test_rehash1<T>
|
||||
end = this->values.end();
|
||||
it != end && count < 10; ++it, ++count)
|
||||
{
|
||||
strong.store(x, test::detail::tracker.count_allocations);
|
||||
strong.store(x, test::exception::detail::tracker.count_allocations);
|
||||
x.insert(*it);
|
||||
}
|
||||
|
||||
|
||||
@@ -60,9 +60,7 @@ struct swap_base : public test::exception_base
|
||||
initial_x(x_values.begin(), x_values.end(), 0, hasher(tag1),
|
||||
key_equal(tag1), allocator_type(tag1)),
|
||||
initial_y(y_values.begin(), y_values.end(), 0, hasher(tag2),
|
||||
key_equal(tag2), allocator_type(
|
||||
T::allocator_type::propagate_on_container_swap::value ?
|
||||
tag2 : tag1))
|
||||
key_equal(tag2), allocator_type(tag2))
|
||||
{}
|
||||
|
||||
struct data_type {
|
||||
@@ -73,7 +71,6 @@ struct swap_base : public test::exception_base
|
||||
};
|
||||
|
||||
data_type init() const { return data_type(initial_x, initial_y); }
|
||||
|
||||
void run(data_type& d) const {
|
||||
try {
|
||||
d.x.swap(d.y);
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_MALLOC_ALLOCATOR_HEADER
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdlib>
|
||||
#include <boost/limits.hpp>
|
||||
#include <new>
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <class T>
|
||||
struct malloc_allocator
|
||||
{
|
||||
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;
|
||||
|
||||
template <class U> struct rebind { typedef malloc_allocator<U> other; };
|
||||
|
||||
malloc_allocator() {}
|
||||
template <class Y> malloc_allocator(malloc_allocator<Y> const&) {}
|
||||
malloc_allocator(malloc_allocator const&) {}
|
||||
|
||||
pointer address(reference r) { return &r; }
|
||||
const_pointer address(const_reference r) { return &r; }
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
using namespace std;
|
||||
T* ptr = static_cast<T*>(malloc(n * sizeof(T)));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
return ptr;
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, void const* u) { return allocate(n); }
|
||||
|
||||
void deallocate(pointer p, size_type) {
|
||||
using namespace std;
|
||||
free(p);
|
||||
}
|
||||
void construct(pointer p, T const& t) { new(p) T(t); }
|
||||
void destroy(pointer p) { p->~T(); }
|
||||
|
||||
size_type max_size() const {
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
|
||||
bool operator==(malloc_allocator const&) const { return true; }
|
||||
bool operator!=(malloc_allocator const&) const { return false; }
|
||||
|
||||
#if BOOST_WORKAROUND(BOOST_MSVC, < 1300)
|
||||
template <class T> void deallocate(T* p, size_type) {
|
||||
using namespace std;
|
||||
free(p);
|
||||
}
|
||||
char* _Charalloc(size_type n) {
|
||||
using namespace std;
|
||||
T* ptr = static_cast<T*>(malloc(n * sizeof(char)));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
return (char*) ptr;
|
||||
}
|
||||
#endif
|
||||
};
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
#pragma warning(disable:4100) // unreferenced formal parameter
|
||||
#endif
|
||||
|
||||
#endif
|
||||
@@ -6,7 +6,7 @@
|
||||
#if !defined(BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER)
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_CHECK_RETURN_TYPE_HEADER
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
|
||||
@@ -18,19 +18,19 @@ namespace test
|
||||
template <class T2>
|
||||
static void equals(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void equals_ref(T2&)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T1, T2>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T1, T2>));
|
||||
}
|
||||
|
||||
template <class T2>
|
||||
static void convertible(T2)
|
||||
{
|
||||
BOOST_STATIC_ASSERT((boost::is_convertible<T2, T1>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_convertible<T2, T1>));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
+16
-8
@@ -52,22 +52,30 @@ namespace test {
|
||||
}
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct counted_object
|
||||
{
|
||||
static object_count count_;
|
||||
|
||||
counted_object() { count_.construct(); }
|
||||
counted_object(counted_object const&) { count_.construct(); }
|
||||
~counted_object() { count_.destruct(); }
|
||||
};
|
||||
|
||||
template <class T> object_count counted_object<T>::count_;
|
||||
|
||||
struct globally_counted_object
|
||||
: counted_object<globally_counted_object> {};
|
||||
|
||||
// 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 {
|
||||
object_count global_object_count;
|
||||
object_count& global_object_count = globally_counted_object::count_;
|
||||
}
|
||||
|
||||
struct counted_object
|
||||
{
|
||||
counted_object() { global_object_count.construct(); }
|
||||
counted_object(counted_object const&) { global_object_count.construct(); }
|
||||
~counted_object() { global_object_count.destruct(); }
|
||||
};
|
||||
|
||||
struct check_instances {
|
||||
int instances;
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include <cmath>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./helpers.hpp"
|
||||
#include "./allocator.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
@@ -28,7 +29,10 @@ namespace test
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal eq = x1.key_eq();
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
std::set<key_type, std::less<key_type> > found_;
|
||||
// Boost.Test was reporting memory leaks for std::set on g++-3.3.
|
||||
// So I work around it by using malloc.
|
||||
std::set<key_type, std::less<key_type>,
|
||||
test::malloc_allocator<key_type> > found_;
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::const_iterator
|
||||
it = x1.begin(), end = x1.end();
|
||||
@@ -82,39 +86,16 @@ namespace test
|
||||
}
|
||||
};
|
||||
|
||||
// Check that size matches up.
|
||||
|
||||
// Finally, check that size matches up.
|
||||
if(x1.size() != size) {
|
||||
BOOST_ERROR("x1.size() doesn't match actual size.");
|
||||
std::cout<<x1.size()<<"/"<<size<<std::endl;
|
||||
}
|
||||
|
||||
// Check the load factor.
|
||||
|
||||
float load_factor =
|
||||
static_cast<float>(size) / static_cast<float>(x1.bucket_count());
|
||||
using namespace std;
|
||||
if(fabs(x1.load_factor() - load_factor) > x1.load_factor() / 64)
|
||||
BOOST_ERROR("x1.load_factor() doesn't match actual load_factor.");
|
||||
|
||||
// Check that size in the buckets matches up.
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::size_type bucket_size = 0;
|
||||
|
||||
for (BOOST_DEDUCED_TYPENAME X::size_type
|
||||
i = 0; i < x1.bucket_count(); ++i)
|
||||
{
|
||||
for (BOOST_DEDUCED_TYPENAME X::const_local_iterator
|
||||
begin = x1.begin(i), end = x1.end(i); begin != end; ++begin)
|
||||
{
|
||||
++bucket_size;
|
||||
}
|
||||
}
|
||||
|
||||
if(x1.size() != bucket_size) {
|
||||
BOOST_ERROR("x1.size() doesn't match bucket size.");
|
||||
std::cout<<x1.size()<<"/"<<bucket_size<<std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+52
-6
@@ -8,8 +8,10 @@
|
||||
|
||||
#include <memory>
|
||||
#include <map>
|
||||
#include <boost/mpl/apply.hpp>
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/unordered/detail/allocate.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/mpl/aux_/config/eti.hpp>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
namespace test
|
||||
@@ -51,10 +53,30 @@ namespace test
|
||||
}
|
||||
};
|
||||
|
||||
struct memory_tracker {
|
||||
template <class Alloc>
|
||||
struct allocator_memory_type_gen {
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare,
|
||||
std::allocator<std::pair<memory_area const, memory_track> >
|
||||
> allocated_memory_type;
|
||||
Alloc> type;
|
||||
};
|
||||
|
||||
#if defined(BOOST_MPL_CFG_MSVC_ETI_BUG)
|
||||
template <>
|
||||
struct allocator_memory_type_gen<int> {
|
||||
typedef std::map<memory_area, memory_track, memory_area_compare>
|
||||
type;
|
||||
};
|
||||
#endif
|
||||
|
||||
template <class Alloc = std::allocator<int> >
|
||||
struct memory_tracker {
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
::boost::unordered::detail::rebind_wrap<Alloc,
|
||||
std::pair<memory_area const, memory_track> >::type
|
||||
allocator_type;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME
|
||||
allocator_memory_type_gen<allocator_type>::type
|
||||
allocated_memory_type;
|
||||
|
||||
allocated_memory_type allocated_memory;
|
||||
unsigned int count_allocators;
|
||||
@@ -117,7 +139,7 @@ namespace test
|
||||
void track_deallocate(void* ptr, std::size_t n, std::size_t size,
|
||||
int tag, bool check_tag_ = true)
|
||||
{
|
||||
allocated_memory_type::iterator pos =
|
||||
BOOST_DEDUCED_TYPENAME allocated_memory_type::iterator pos =
|
||||
allocated_memory.find(
|
||||
memory_area(ptr, (char*) ptr + n * size));
|
||||
if(pos == allocated_memory.end()) {
|
||||
@@ -155,9 +177,33 @@ namespace test
|
||||
//
|
||||
// boostinspect:nounnamed
|
||||
namespace {
|
||||
test::detail::memory_tracker tracker;
|
||||
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 };
|
||||
};
|
||||
|
||||
struct convert_from_anything
|
||||
{
|
||||
template <typename T>
|
||||
convert_from_anything(T const&) {}
|
||||
};
|
||||
|
||||
int selected_count(convert_from_anything)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,11 +8,32 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/mpl/not.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
|
||||
namespace test
|
||||
{
|
||||
/*
|
||||
struct unordered_set_type { char x[100]; };
|
||||
struct unordered_multiset_type { char x[200]; };
|
||||
struct unordered_map_type { char x[300]; };
|
||||
struct unordered_multimap_type { char x[400]; };
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
unordered_set_type container_type(
|
||||
boost::unordered_set<V, H, P, A> const*);
|
||||
template <class V, class H, class P, class A>
|
||||
unordered_multiset_type container_type(
|
||||
boost::unordered_multiset<V, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
unordered_map_type container_type(
|
||||
boost::unordered_map<K, M, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
unordered_multimap_type container_type(
|
||||
boost::unordered_multimap<K, M, H, P, A> const*);
|
||||
*/
|
||||
|
||||
template <class Container>
|
||||
struct is_set
|
||||
: public boost::is_same<
|
||||
@@ -20,21 +41,39 @@ namespace test
|
||||
BOOST_DEDUCED_TYPENAME Container::value_type> {};
|
||||
|
||||
template <class Container>
|
||||
struct has_unique_keys
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = false);
|
||||
};
|
||||
struct is_map
|
||||
: public boost::mpl::not_<is_set<Container> > {};
|
||||
|
||||
struct yes_type { char x[100]; };
|
||||
struct no_type { char x[200]; };
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
struct has_unique_keys<boost::unordered_set<V, H, P, A> >
|
||||
yes_type has_unique_key_impl(
|
||||
boost::unordered_set<V, H, P, A> const*);
|
||||
template <class V, class H, class P, class A>
|
||||
no_type has_unique_key_impl(
|
||||
boost::unordered_multiset<V, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
yes_type has_unique_key_impl(
|
||||
boost::unordered_map<K, M, H, P, A> const*);
|
||||
template <class K, class M, class H, class P, class A>
|
||||
no_type has_unique_key_impl(
|
||||
boost::unordered_multimap<K, M, H, P, A> const*);
|
||||
|
||||
template <class Container>
|
||||
struct has_unique_keys
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
sizeof(has_unique_key_impl((Container const*)0))
|
||||
== sizeof(yes_type));
|
||||
};
|
||||
|
||||
template <class K, class M, class H, class P, class A>
|
||||
struct has_unique_keys<boost::unordered_map<K, M, H, P, A> >
|
||||
template <class Container>
|
||||
struct has_equivalent_keys
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(bool, value = true);
|
||||
BOOST_STATIC_CONSTANT(bool, value =
|
||||
sizeof(has_unique_key_impl((Container const*)0))
|
||||
== sizeof(no_type));
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
#include "./list.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/detail/select_type.hpp>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include "./generators.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
|
||||
@@ -33,15 +33,14 @@ namespace test
|
||||
void fill(T& x, std::size_t len) {
|
||||
value_type* value_ptr = 0;
|
||||
int* int_ptr = 0;
|
||||
len += x.size();
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
for(std::size_t i = 0; i < len; ++i) {
|
||||
value_type value = generate(value_ptr);
|
||||
|
||||
int count = type_ == generate_collisions ?
|
||||
1 + (generate(int_ptr) % 5) : 1;
|
||||
|
||||
for(int i = 0; i < count; ++i) {
|
||||
for(int count =
|
||||
type_ == generate_collisions ?
|
||||
generate(int_ptr) % 10 : 1;
|
||||
count; --count) {
|
||||
x.push_back(value);
|
||||
}
|
||||
}
|
||||
@@ -65,15 +64,16 @@ namespace test
|
||||
mapped_type* mapped_ptr = 0;
|
||||
int* int_ptr = 0;
|
||||
|
||||
for (std::size_t i = 0; i < len; ++i) {
|
||||
for(std::size_t i = 0; i < len; ++i) {
|
||||
key_type key = generate(key_ptr);
|
||||
|
||||
int count = type_ == generate_collisions ?
|
||||
1 + (generate(int_ptr) % 5) : 1;
|
||||
|
||||
for(int i = 0; i < count; ++i) {
|
||||
x.push_back(std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr)));
|
||||
for(int count =
|
||||
type_ == generate_collisions ?
|
||||
generate(int_ptr) % 10 : 1;
|
||||
count; --count) {
|
||||
x.push_back(
|
||||
std::pair<key_type const, mapped_type>(
|
||||
key, generate(mapped_ptr)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,12 +81,10 @@ namespace test
|
||||
|
||||
template <class X>
|
||||
struct unordered_generator_base
|
||||
: public boost::detail::if_true<
|
||||
test::is_set<X>::value
|
||||
>::BOOST_NESTED_TEMPLATE then<
|
||||
: public boost::mpl::if_<
|
||||
test::is_set<X>,
|
||||
test::unordered_generator_set<X>,
|
||||
test::unordered_generator_map<X>
|
||||
>
|
||||
test::unordered_generator_map<X> >
|
||||
{
|
||||
};
|
||||
|
||||
@@ -106,7 +104,7 @@ namespace test
|
||||
random_values(int count, test::random_generator const& generator =
|
||||
test::default_generator)
|
||||
{
|
||||
test::unordered_generator<X> gen(generator);
|
||||
static test::unordered_generator<X> gen(generator);
|
||||
gen.fill(*this, count);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <iterator>
|
||||
#include "./metafunctions.hpp"
|
||||
#include "./equivalent.hpp"
|
||||
#include "./list.hpp"
|
||||
#include "./exception_test.hpp"
|
||||
|
||||
+5
-13
@@ -76,29 +76,21 @@ namespace test {
|
||||
|
||||
// Run test with every combination of the parameters (a sequence of sequences)
|
||||
#define UNORDERED_TEST(name, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, \
|
||||
((name))((1)) parameters) \
|
||||
|
||||
#define UNORDERED_TEST_REPEAT(name, n, parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, \
|
||||
((name))((n)) parameters) \
|
||||
BOOST_PP_SEQ_FOR_EACH_PRODUCT(UNORDERED_TEST_OP, ((name)) parameters) \
|
||||
|
||||
#define UNORDERED_TEST_OP(r, product) \
|
||||
UNORDERED_TEST_OP2( \
|
||||
BOOST_PP_SEQ_ELEM(0, product), \
|
||||
BOOST_PP_SEQ_ELEM(1, product), \
|
||||
BOOST_PP_SEQ_TAIL(BOOST_PP_SEQ_TAIL(product))) \
|
||||
BOOST_PP_SEQ_HEAD(product), \
|
||||
BOOST_PP_SEQ_TAIL(product)) \
|
||||
|
||||
#define UNORDERED_TEST_OP2(name, n, params) \
|
||||
#define UNORDERED_TEST_OP2(name, params) \
|
||||
UNORDERED_AUTO_TEST( \
|
||||
BOOST_PP_SEQ_FOLD_LEFT(UNORDERED_TEST_OP_JOIN, name, params)) \
|
||||
{ \
|
||||
for (int i = 0; i < n; ++i) \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
name BOOST_PP_SEQ_TO_TUPLE(params); \
|
||||
} \
|
||||
|
||||
#define UNORDERED_TEST_OP_JOIN(s, state, elem) \
|
||||
BOOST_PP_CAT(state, BOOST_PP_CAT(_, elem)) \
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+57
-39
@@ -13,6 +13,9 @@
|
||||
#include <map>
|
||||
#include <iterator>
|
||||
#include <algorithm>
|
||||
#include <boost/mpl/if.hpp>
|
||||
#include <boost/mpl/eval_if.hpp>
|
||||
#include <boost/mpl/identity.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include "../objects/fwd.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
@@ -22,17 +25,21 @@
|
||||
|
||||
namespace test
|
||||
{
|
||||
template <typename X>
|
||||
struct equals_to_compare
|
||||
template <class X>
|
||||
struct equals_to_compare2
|
||||
: public boost::mpl::identity<
|
||||
std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type> >
|
||||
{
|
||||
typedef std::less<BOOST_DEDUCED_TYPENAME X::first_argument_type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <>
|
||||
struct equals_to_compare<test::equal_to>
|
||||
template <class X>
|
||||
struct equals_to_compare
|
||||
: public boost::mpl::eval_if<
|
||||
boost::is_same<X, test::equal_to>,
|
||||
boost::mpl::identity<test::less>,
|
||||
equals_to_compare2<X>
|
||||
>
|
||||
{
|
||||
typedef test::less type;
|
||||
};
|
||||
|
||||
template <class X1, class X2>
|
||||
@@ -60,40 +67,51 @@ namespace test
|
||||
values2.begin(), test::equivalent));
|
||||
}
|
||||
|
||||
template <typename X>
|
||||
struct ordered_base;
|
||||
template <class X>
|
||||
struct ordered_set : public
|
||||
boost::mpl::if_<
|
||||
test::has_unique_keys<X>,
|
||||
std::set<
|
||||
BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>,
|
||||
std::multiset<
|
||||
BOOST_DEDUCED_TYPENAME X::value_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>
|
||||
> {};
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_set<V, H, P, A> >
|
||||
{
|
||||
typedef std::set<V,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
template <class X>
|
||||
struct ordered_map : public
|
||||
boost::mpl::if_<
|
||||
test::has_unique_keys<X>,
|
||||
std::map<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>,
|
||||
std::multimap<
|
||||
BOOST_DEDUCED_TYPENAME X::key_type,
|
||||
BOOST_DEDUCED_TYPENAME X::mapped_type,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<
|
||||
BOOST_DEDUCED_TYPENAME X::key_equal
|
||||
>::type
|
||||
>
|
||||
> {};
|
||||
|
||||
template <class V, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_multiset<V, H, P, A> >
|
||||
{
|
||||
typedef std::multiset<V,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class K, class M, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_map<K, M, H, P, A> >
|
||||
{
|
||||
typedef std::map<K, M,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
|
||||
template <class K, class M, class H, class P, class A>
|
||||
struct ordered_base<boost::unordered_multimap<K, M, H, P, A> >
|
||||
{
|
||||
typedef std::multimap<K, M,
|
||||
BOOST_DEDUCED_TYPENAME equals_to_compare<P>::type>
|
||||
type;
|
||||
};
|
||||
template <class X>
|
||||
struct ordered_base : public
|
||||
boost::mpl::eval_if<
|
||||
test::is_set<X>,
|
||||
test::ordered_set<X>,
|
||||
test::ordered_map<X>
|
||||
> {};
|
||||
|
||||
template <class X>
|
||||
class ordered : public ordered_base<X>::type
|
||||
|
||||
@@ -21,8 +21,7 @@ namespace test
|
||||
is_select_on_copy = 0,
|
||||
is_propagate_on_swap = 0,
|
||||
is_propagate_on_assign = 0,
|
||||
is_propagate_on_move = 0,
|
||||
cxx11_construct = 0
|
||||
is_propagate_on_move = 0
|
||||
};
|
||||
};
|
||||
|
||||
@@ -32,8 +31,7 @@ namespace test
|
||||
is_select_on_copy = 1,
|
||||
is_propagate_on_swap = 1,
|
||||
is_propagate_on_assign = 1,
|
||||
is_propagate_on_move = 1,
|
||||
cxx11_construct = 1
|
||||
is_propagate_on_move = 1
|
||||
};
|
||||
};
|
||||
|
||||
@@ -170,8 +168,8 @@ namespace test
|
||||
new(p) T(t);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template<typename... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template<typename... Args> void construct(T* p, Args&&... args) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
@@ -293,20 +291,6 @@ namespace test
|
||||
return x.tag_ == y.tag_;
|
||||
}
|
||||
|
||||
// Function to check how many times an allocator has been selected,
|
||||
// return 0 for other allocators.
|
||||
|
||||
struct convert_from_anything
|
||||
{
|
||||
template <typename T>
|
||||
convert_from_anything(T const&) {}
|
||||
};
|
||||
|
||||
inline int selected_count(convert_from_anything)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <typename T, typename Flags>
|
||||
int selected_count(cxx11_allocator<T, Flags> const& x)
|
||||
{
|
||||
|
||||
+22
-193
@@ -13,12 +13,21 @@
|
||||
#include <boost/limits.hpp>
|
||||
#include <new>
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/allocator.hpp"
|
||||
#include "../helpers/memory.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
namespace exception
|
||||
{
|
||||
namespace detail
|
||||
{
|
||||
namespace
|
||||
{
|
||||
test::detail::memory_tracker<test::malloc_allocator<int> > tracker;
|
||||
}
|
||||
}
|
||||
|
||||
class object;
|
||||
class hash;
|
||||
class equal_to;
|
||||
@@ -250,7 +259,7 @@ namespace exception
|
||||
UNORDERED_SCOPE(allocator::allocator()) {
|
||||
UNORDERED_EPOINT("Mock allocator default constructor.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <class Y> allocator(allocator<Y> const& x) : tag_(x.tag_)
|
||||
@@ -258,7 +267,7 @@ namespace exception
|
||||
UNORDERED_SCOPE(allocator::allocator()) {
|
||||
UNORDERED_EPOINT("Mock allocator template copy constructor.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
allocator(allocator const& x) : tag_(x.tag_)
|
||||
@@ -266,11 +275,11 @@ namespace exception
|
||||
UNORDERED_SCOPE(allocator::allocator()) {
|
||||
UNORDERED_EPOINT("Mock allocator copy constructor.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~allocator() {
|
||||
test::detail::tracker.allocator_unref();
|
||||
detail::tracker.allocator_unref();
|
||||
}
|
||||
|
||||
allocator& operator=(allocator const& x) {
|
||||
@@ -308,7 +317,7 @@ namespace exception
|
||||
ptr = (T*) malloc(n * sizeof(T));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
}
|
||||
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return pointer(ptr);
|
||||
|
||||
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
@@ -324,7 +333,7 @@ namespace exception
|
||||
ptr = (T*) malloc(n * sizeof(T));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
}
|
||||
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return pointer(ptr);
|
||||
|
||||
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
@@ -334,7 +343,7 @@ namespace exception
|
||||
{
|
||||
//::operator delete((void*) p);
|
||||
if(p) {
|
||||
test::detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
|
||||
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
|
||||
using namespace std;
|
||||
free(p);
|
||||
}
|
||||
@@ -345,21 +354,21 @@ namespace exception
|
||||
UNORDERED_EPOINT("Mock allocator construct function.");
|
||||
new(p) T(t);
|
||||
}
|
||||
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
UNORDERED_SCOPE(allocator::construct(pointer, BOOST_FWD_REF(Args)...)) {
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template<class... Args> void construct(T* p, Args&&... args) {
|
||||
UNORDERED_SCOPE(allocator::construct(pointer, Args&&...)) {
|
||||
UNORDERED_EPOINT("Mock allocator construct function.");
|
||||
new(p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) {
|
||||
test::detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
|
||||
@@ -401,186 +410,6 @@ namespace exception
|
||||
//}
|
||||
return x.tag_ != y.tag_;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
class allocator2
|
||||
{
|
||||
public:
|
||||
int tag_;
|
||||
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;
|
||||
|
||||
template <class U> struct rebind { typedef allocator2<U> other; };
|
||||
|
||||
explicit allocator2(int t = 0) : tag_(t)
|
||||
{
|
||||
UNORDERED_SCOPE(allocator2::allocator2()) {
|
||||
UNORDERED_EPOINT("Mock allocator2 default constructor.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
allocator2(allocator<T> const& x) : tag_(x.tag_)
|
||||
{
|
||||
UNORDERED_SCOPE(allocator2::allocator2()) {
|
||||
UNORDERED_EPOINT("Mock allocator2 constructor from allocator.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <class Y> allocator2(allocator2<Y> const& x) : tag_(x.tag_)
|
||||
{
|
||||
UNORDERED_SCOPE(allocator2::allocator2()) {
|
||||
UNORDERED_EPOINT("Mock allocator2 template copy constructor.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
allocator2(allocator2 const& x) : tag_(x.tag_)
|
||||
{
|
||||
UNORDERED_SCOPE(allocator2::allocator2()) {
|
||||
UNORDERED_EPOINT("Mock allocator2 copy constructor.");
|
||||
}
|
||||
test::detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~allocator2() {
|
||||
test::detail::tracker.allocator_unref();
|
||||
}
|
||||
|
||||
allocator2& operator=(allocator2 const& x) {
|
||||
UNORDERED_SCOPE(allocator2::allocator2()) {
|
||||
UNORDERED_EPOINT("Mock allocator2 assignment operator.");
|
||||
tag_ = x.tag_;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
// If address throws, then it can't be used in erase or the
|
||||
// destructor, which is very limiting. I need to check up on
|
||||
// this.
|
||||
|
||||
pointer address(reference r) {
|
||||
//UNORDERED_SCOPE(allocator2::address(reference)) {
|
||||
// UNORDERED_EPOINT("Mock allocator2 address function.");
|
||||
//}
|
||||
return pointer(&r);
|
||||
}
|
||||
|
||||
const_pointer address(const_reference r) {
|
||||
//UNORDERED_SCOPE(allocator2::address(const_reference)) {
|
||||
// UNORDERED_EPOINT("Mock allocator2 const address function.");
|
||||
//}
|
||||
return const_pointer(&r);
|
||||
}
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
T* ptr = 0;
|
||||
UNORDERED_SCOPE(allocator2::allocate(size_type)) {
|
||||
UNORDERED_EPOINT("Mock allocator2 allocate function.");
|
||||
|
||||
using namespace std;
|
||||
ptr = (T*) malloc(n * sizeof(T));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
}
|
||||
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return pointer(ptr);
|
||||
|
||||
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
pointer allocate(size_type n, void const* u)
|
||||
{
|
||||
T* ptr = 0;
|
||||
UNORDERED_SCOPE(allocator2::allocate(size_type, const_pointer)) {
|
||||
UNORDERED_EPOINT("Mock allocator2 allocate function.");
|
||||
|
||||
using namespace std;
|
||||
ptr = (T*) malloc(n * sizeof(T));
|
||||
if(!ptr) throw std::bad_alloc();
|
||||
}
|
||||
test::detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return pointer(ptr);
|
||||
|
||||
//return pointer(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
}
|
||||
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
//::operator delete((void*) p);
|
||||
if(p) {
|
||||
test::detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
|
||||
using namespace std;
|
||||
free(p);
|
||||
}
|
||||
}
|
||||
|
||||
void construct(pointer p, T const& t) {
|
||||
UNORDERED_SCOPE(allocator2::construct(T*, T)) {
|
||||
UNORDERED_EPOINT("Mock allocator2 construct function.");
|
||||
new(p) T(t);
|
||||
}
|
||||
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
UNORDERED_SCOPE(allocator2::construct(pointer, BOOST_FWD_REF(Args)...)) {
|
||||
UNORDERED_EPOINT("Mock allocator2 construct function.");
|
||||
new(p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
test::detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
}
|
||||
#endif
|
||||
|
||||
void destroy(T* p) {
|
||||
test::detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
}
|
||||
|
||||
size_type max_size() const {
|
||||
UNORDERED_SCOPE(allocator2::construct(pointer, T)) {
|
||||
UNORDERED_EPOINT("Mock allocator2 max_size function.");
|
||||
}
|
||||
return (std::numeric_limits<std::size_t>::max)();
|
||||
}
|
||||
|
||||
typedef false_type propagate_on_container_copy_assignment;
|
||||
typedef false_type propagate_on_container_move_assignment;
|
||||
typedef false_type propagate_on_container_swap;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
void swap(allocator2<T>& x, allocator2<T>& y)
|
||||
{
|
||||
std::swap(x.tag_, y.tag_);
|
||||
}
|
||||
|
||||
// It's pretty much impossible to write a compliant swap when these
|
||||
// two can throw. So they don't.
|
||||
|
||||
template <class T>
|
||||
inline bool operator==(allocator2<T> const& x, allocator2<T> const& y)
|
||||
{
|
||||
//UNORDERED_SCOPE(operator==(allocator2, allocator2)) {
|
||||
// UNORDERED_EPOINT("Mock allocator2 equality operator.");
|
||||
//}
|
||||
return x.tag_ == y.tag_;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
inline bool operator!=(allocator2<T> const& x, allocator2<T> const& y)
|
||||
{
|
||||
//UNORDERED_SCOPE(operator!=(allocator2, allocator2)) {
|
||||
// UNORDERED_EPOINT("Mock allocator2 inequality operator.");
|
||||
//}
|
||||
return x.tag_ != y.tag_;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-17
@@ -26,7 +26,7 @@ namespace minimal
|
||||
class destructible;
|
||||
class copy_constructible;
|
||||
class copy_constructible_equality_comparable;
|
||||
class default_assignable;
|
||||
class default_copy_constructible;
|
||||
class assignable;
|
||||
|
||||
struct ampersand_operator_used {};
|
||||
@@ -99,29 +99,26 @@ namespace minimal
|
||||
return false;
|
||||
}
|
||||
|
||||
class default_assignable
|
||||
class default_copy_constructible
|
||||
{
|
||||
public:
|
||||
default_assignable(constructor_param const&) {}
|
||||
default_copy_constructible(constructor_param const&) {}
|
||||
|
||||
default_assignable()
|
||||
default_copy_constructible()
|
||||
{
|
||||
}
|
||||
|
||||
default_assignable(default_assignable const&)
|
||||
default_copy_constructible(default_copy_constructible const&)
|
||||
{
|
||||
}
|
||||
|
||||
default_assignable& operator=(default_assignable const&)
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
~default_assignable()
|
||||
~default_copy_constructible()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
default_copy_constructible& operator=(
|
||||
default_copy_constructible const&);
|
||||
ampersand_operator_used operator&() const {
|
||||
return ampersand_operator_used(); }
|
||||
};
|
||||
@@ -151,7 +148,7 @@ namespace minimal
|
||||
movable1() {}
|
||||
explicit movable1(movable_init) {}
|
||||
movable1(BOOST_RV_REF(movable1)) {}
|
||||
movable1& operator=(BOOST_RV_REF(movable1)) { return *this; }
|
||||
movable1& operator=(BOOST_RV_REF(movable1));
|
||||
~movable1() {}
|
||||
};
|
||||
|
||||
@@ -163,7 +160,6 @@ namespace minimal
|
||||
explicit movable2(movable_init) {}
|
||||
movable2(movable2&&) {}
|
||||
~movable2() {}
|
||||
movable2& operator=(movable2&&) { return *this; }
|
||||
private:
|
||||
movable2() {}
|
||||
movable2(movable2 const&);
|
||||
@@ -371,8 +367,8 @@ namespace minimal
|
||||
|
||||
void construct(T* p, T const& t) { new((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template<class... Args> void construct(T* p, Args&&... args) {
|
||||
new((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
@@ -443,8 +439,8 @@ namespace minimal
|
||||
|
||||
void construct(T* p, T const& t) { new((void*)p) T(t); }
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template<class... Args> void construct(T* p, Args&&... args) {
|
||||
new((void*)p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
#endif
|
||||
|
||||
+23
-362
@@ -18,20 +18,15 @@ namespace test
|
||||
// Note that the default hash function will work for any equal_to (but not
|
||||
// very well).
|
||||
class object;
|
||||
class movable;
|
||||
class implicitly_convertible;
|
||||
class hash;
|
||||
class less;
|
||||
class equal_to;
|
||||
template <class T> class allocator1;
|
||||
template <class T> class allocator2;
|
||||
template <class T> class allocator;
|
||||
object generate(object const*);
|
||||
movable generate(movable const*);
|
||||
implicitly_convertible generate(implicitly_convertible const*);
|
||||
|
||||
inline void ignore_variable(void const*) {}
|
||||
|
||||
class object : private counted_object
|
||||
|
||||
class object : private globally_counted_object
|
||||
{
|
||||
friend class hash;
|
||||
friend class equal_to;
|
||||
@@ -69,82 +64,7 @@ namespace test
|
||||
}
|
||||
};
|
||||
|
||||
class movable : private counted_object
|
||||
{
|
||||
friend class hash;
|
||||
friend class equal_to;
|
||||
friend class less;
|
||||
int tag1_, tag2_;
|
||||
|
||||
BOOST_COPYABLE_AND_MOVABLE(movable)
|
||||
public:
|
||||
explicit movable(int t1 = 0, int t2 = 0) : tag1_(t1), tag2_(t2) {}
|
||||
|
||||
movable(movable const& x) :
|
||||
counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
}
|
||||
|
||||
movable(BOOST_RV_REF(movable) x) :
|
||||
counted_object(x), tag1_(x.tag1_), tag2_(x.tag2_)
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
x.tag1_ = -1;
|
||||
x.tag2_ = -1;
|
||||
}
|
||||
|
||||
movable& operator=(BOOST_COPY_ASSIGN_REF(movable) x) // Copy assignment
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
tag1_ = x.tag1_;
|
||||
tag2_ = x.tag2_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
movable& operator=(BOOST_RV_REF(movable) x) //Move assignment
|
||||
{
|
||||
BOOST_TEST(x.tag1_ != -1);
|
||||
tag1_ = x.tag1_;
|
||||
tag2_ = x.tag2_;
|
||||
x.tag1_ = -1;
|
||||
x.tag2_ = -1;
|
||||
return *this;
|
||||
}
|
||||
|
||||
~movable() {
|
||||
tag1_ = -1;
|
||||
tag2_ = -1;
|
||||
}
|
||||
|
||||
friend bool operator==(movable const& x1, movable const& x2) {
|
||||
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
|
||||
return x1.tag1_ == x2.tag1_ && x1.tag2_ == x2.tag2_;
|
||||
}
|
||||
|
||||
friend bool operator!=(movable const& x1, movable const& x2) {
|
||||
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
|
||||
return x1.tag1_ != x2.tag1_ || x1.tag2_ != x2.tag2_;
|
||||
}
|
||||
|
||||
friend bool operator<(movable const& x1, movable const& x2) {
|
||||
BOOST_TEST(x1.tag1_ != -1 && x2.tag1_ != -1);
|
||||
return x1.tag1_ < x2.tag1_ ||
|
||||
(x1.tag1_ == x2.tag1_ && x1.tag2_ < x2.tag2_);
|
||||
}
|
||||
|
||||
friend movable generate(movable const*) {
|
||||
int* x = 0;
|
||||
return movable(generate(x), generate(x));
|
||||
}
|
||||
|
||||
friend std::ostream& operator<<(std::ostream& out, movable const& o)
|
||||
{
|
||||
return out<<"("<<o.tag1_<<","<<o.tag2_<<")";
|
||||
}
|
||||
};
|
||||
|
||||
class implicitly_convertible : private counted_object
|
||||
class implicitly_convertible : private globally_counted_object
|
||||
{
|
||||
int tag1_, tag2_;
|
||||
public:
|
||||
@@ -158,11 +78,6 @@ namespace test
|
||||
return object(tag1_, tag2_);
|
||||
}
|
||||
|
||||
operator movable() const
|
||||
{
|
||||
return movable(tag1_, tag2_);
|
||||
}
|
||||
|
||||
friend implicitly_convertible generate(implicitly_convertible const*) {
|
||||
int* x = 0;
|
||||
return implicitly_convertible(generate(x), generate(x));
|
||||
@@ -174,7 +89,6 @@ namespace test
|
||||
}
|
||||
};
|
||||
|
||||
// Note: This is a deliberately bad hash function.
|
||||
class hash
|
||||
{
|
||||
int type_;
|
||||
@@ -192,17 +106,6 @@ namespace test
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(movable const& x) const {
|
||||
switch(type_) {
|
||||
case 1:
|
||||
return x.tag1_;
|
||||
case 2:
|
||||
return x.tag2_;
|
||||
default:
|
||||
return x.tag1_ + x.tag2_;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x) const {
|
||||
return x;
|
||||
}
|
||||
@@ -220,10 +123,6 @@ namespace test
|
||||
return hash()(x);
|
||||
}
|
||||
|
||||
std::size_t hash_value(test::movable const& x) {
|
||||
return hash()(x);
|
||||
}
|
||||
|
||||
class less
|
||||
{
|
||||
int type_;
|
||||
@@ -241,17 +140,6 @@ namespace test
|
||||
}
|
||||
}
|
||||
|
||||
bool operator()(movable const& x1, movable const& x2) const {
|
||||
switch(type_) {
|
||||
case 1:
|
||||
return x1.tag1_ < x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ < x2.tag2_;
|
||||
default:
|
||||
return x1 < x2;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x1, int x2) const {
|
||||
return x1 < x2;
|
||||
}
|
||||
@@ -278,17 +166,6 @@ namespace test
|
||||
}
|
||||
}
|
||||
|
||||
bool operator()(movable const& x1, movable const& x2) const {
|
||||
switch(type_) {
|
||||
case 1:
|
||||
return x1.tag1_ == x2.tag1_;
|
||||
case 2:
|
||||
return x1.tag2_ == x2.tag2_;
|
||||
default:
|
||||
return x1 == x2;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t operator()(int x1, int x2) const {
|
||||
return x1 == x2;
|
||||
}
|
||||
@@ -306,253 +183,44 @@ namespace test
|
||||
}
|
||||
};
|
||||
|
||||
// allocator1 only has the old fashioned 'construct' method and has
|
||||
// a few less typedefs. allocator2 uses a custom pointer class.
|
||||
|
||||
template <class T>
|
||||
class allocator1
|
||||
{
|
||||
public:
|
||||
int tag_;
|
||||
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind { typedef allocator1<U> other; };
|
||||
|
||||
explicit allocator1(int t = 0) : tag_(t)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <class Y> allocator1(allocator1<Y> const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
allocator1(allocator1 const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~allocator1()
|
||||
{
|
||||
detail::tracker.allocator_unref();
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n) {
|
||||
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n, void const* u)
|
||||
{
|
||||
T* ptr(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) ptr, n, sizeof(T), tag_);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t n)
|
||||
{
|
||||
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
|
||||
::operator delete((void*) p);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t) {
|
||||
// Don't count constructions here as it isn't always called.
|
||||
//detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(t);
|
||||
}
|
||||
|
||||
void destroy(T* p) {
|
||||
//detail::tracker.track_destroy((void*) p, sizeof(T), tag_);
|
||||
p->~T();
|
||||
|
||||
// Work around MSVC buggy unused parameter warning.
|
||||
ignore_variable(&p);
|
||||
}
|
||||
|
||||
bool operator==(allocator1 const& x) const
|
||||
{
|
||||
return tag_ == x.tag_;
|
||||
}
|
||||
|
||||
bool operator!=(allocator1 const& x) const
|
||||
{
|
||||
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> class ptr;
|
||||
template <class T> class const_ptr;
|
||||
|
||||
struct void_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T>
|
||||
friend class ptr;
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T>
|
||||
explicit void_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
class void_const_ptr
|
||||
{
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template <typename T>
|
||||
friend class const_ptr;
|
||||
private:
|
||||
#endif
|
||||
|
||||
void* ptr_;
|
||||
|
||||
public:
|
||||
void_const_ptr() : ptr_(0) {}
|
||||
|
||||
template <typename T>
|
||||
explicit void_const_ptr(const_ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(void_const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(void_const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class ptr
|
||||
{
|
||||
friend class allocator2<T>;
|
||||
friend class const_ptr<T>;
|
||||
friend struct void_ptr;
|
||||
|
||||
T* ptr_;
|
||||
|
||||
ptr(T* x) : ptr_(x) {}
|
||||
public:
|
||||
ptr() : ptr_(0) {}
|
||||
explicit ptr(void_ptr const& x) : ptr_((T*) x.ptr_) {}
|
||||
|
||||
T& operator*() const { return *ptr_; }
|
||||
T* operator->() const { return ptr_; }
|
||||
ptr& operator++() { ++ptr_; return *this; }
|
||||
ptr operator++(int) { ptr tmp(*this); ++ptr_; return tmp; }
|
||||
ptr operator+(std::ptrdiff_t s) const { return ptr<T>(ptr_ + s); }
|
||||
friend ptr operator+(std::ptrdiff_t s, ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T& operator[](std::ptrdiff_t s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
|
||||
// I'm not using the safe bool idiom because the containers should be
|
||||
// able to cope with bool conversions.
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class const_ptr
|
||||
{
|
||||
friend class allocator2<T>;
|
||||
friend struct const_void_ptr;
|
||||
|
||||
T const* ptr_;
|
||||
|
||||
const_ptr(T const* ptr) : ptr_(ptr) {}
|
||||
public:
|
||||
const_ptr() : ptr_(0) {}
|
||||
const_ptr(ptr<T> const& x) : ptr_(x.ptr_) {}
|
||||
explicit const_ptr(void_const_ptr const& x) : ptr_((T const*) x.ptr_) {}
|
||||
|
||||
T const& operator*() const { return *ptr_; }
|
||||
T const* operator->() const { return ptr_; }
|
||||
const_ptr& operator++() { ++ptr_; return *this; }
|
||||
const_ptr operator++(int) { const_ptr tmp(*this); ++ptr_; return tmp; }
|
||||
const_ptr operator+(std::ptrdiff_t s) const
|
||||
{ return const_ptr(ptr_ + s); }
|
||||
friend const_ptr operator+(std::ptrdiff_t s, const_ptr p)
|
||||
{ return ptr<T>(s + p.ptr_); }
|
||||
T const& operator[](int s) const { return ptr_[s]; }
|
||||
bool operator!() const { return !ptr_; }
|
||||
operator bool() const { return !!ptr_; }
|
||||
|
||||
bool operator==(const_ptr const& x) const { return ptr_ == x.ptr_; }
|
||||
bool operator!=(const_ptr const& x) const { return ptr_ != x.ptr_; }
|
||||
bool operator<(const_ptr const& x) const { return ptr_ < x.ptr_; }
|
||||
bool operator>(const_ptr const& x) const { return ptr_ > x.ptr_; }
|
||||
bool operator<=(const_ptr const& x) const { return ptr_ <= x.ptr_; }
|
||||
bool operator>=(const_ptr const& x) const { return ptr_ >= x.ptr_; }
|
||||
};
|
||||
|
||||
template <class T>
|
||||
class allocator2
|
||||
class allocator
|
||||
{
|
||||
# ifdef BOOST_NO_MEMBER_TEMPLATE_FRIENDS
|
||||
public:
|
||||
# else
|
||||
template <class> friend class allocator2;
|
||||
template <class> friend class allocator;
|
||||
# endif
|
||||
int tag_;
|
||||
public:
|
||||
typedef std::size_t size_type;
|
||||
typedef std::ptrdiff_t difference_type;
|
||||
typedef void_ptr void_pointer;
|
||||
typedef void_const_ptr const_void_pointer;
|
||||
typedef ptr<T> pointer;
|
||||
typedef const_ptr<T> const_pointer;
|
||||
typedef T* pointer;
|
||||
typedef T const* const_pointer;
|
||||
typedef T& reference;
|
||||
typedef T const& const_reference;
|
||||
typedef T value_type;
|
||||
|
||||
template <class U> struct rebind { typedef allocator2<U> other; };
|
||||
template <class U> struct rebind { typedef allocator<U> other; };
|
||||
|
||||
explicit allocator2(int t = 0) : tag_(t)
|
||||
explicit allocator(int t = 0) : tag_(t)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
template <class Y> allocator2(allocator2<Y> const& x)
|
||||
template <class Y> allocator(allocator<Y> const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
allocator2(allocator2 const& x)
|
||||
allocator(allocator const& x)
|
||||
: tag_(x.tag_)
|
||||
{
|
||||
detail::tracker.allocator_ref();
|
||||
}
|
||||
|
||||
~allocator2()
|
||||
~allocator()
|
||||
{
|
||||
detail::tracker.allocator_unref();
|
||||
}
|
||||
@@ -568,9 +236,9 @@ namespace test
|
||||
}
|
||||
|
||||
pointer allocate(size_type n) {
|
||||
pointer p(static_cast<T*>(::operator new(n * sizeof(T))));
|
||||
detail::tracker.track_allocate((void*) p.ptr_, n, sizeof(T), tag_);
|
||||
return p;
|
||||
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)
|
||||
@@ -582,8 +250,8 @@ namespace test
|
||||
|
||||
void deallocate(pointer p, size_type n)
|
||||
{
|
||||
detail::tracker.track_deallocate((void*) p.ptr_, n, sizeof(T), tag_);
|
||||
::operator delete((void*) p.ptr_);
|
||||
detail::tracker.track_deallocate((void*) p, n, sizeof(T), tag_);
|
||||
::operator delete((void*) p);
|
||||
}
|
||||
|
||||
void construct(T* p, T const& t) {
|
||||
@@ -591,8 +259,8 @@ namespace test
|
||||
new(p) T(t);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
template<class... Args> void construct(T* p, BOOST_FWD_REF(Args)... args) {
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
template<class... Args> void construct(T* p, Args&&... args) {
|
||||
detail::tracker.track_construct((void*) p, sizeof(T), tag_);
|
||||
new(p) T(boost::forward<Args>(args)...);
|
||||
}
|
||||
@@ -607,12 +275,12 @@ namespace test
|
||||
return (std::numeric_limits<size_type>::max)();
|
||||
}
|
||||
|
||||
bool operator==(allocator2 const& x) const
|
||||
bool operator==(allocator const& x) const
|
||||
{
|
||||
return tag_ == x.tag_;
|
||||
}
|
||||
|
||||
bool operator!=(allocator2 const& x) const
|
||||
bool operator!=(allocator const& x) const
|
||||
{
|
||||
return tag_ != x.tag_;
|
||||
}
|
||||
@@ -626,14 +294,7 @@ namespace test
|
||||
};
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(allocator1<T> const& x, allocator1<T> const& y,
|
||||
test::derived_type)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool equivalent_impl(allocator2<T> const& x, allocator2<T> const& y,
|
||||
bool equivalent_impl(allocator<T> const& x, allocator<T> const& y,
|
||||
test::derived_type)
|
||||
{
|
||||
return x == y;
|
||||
|
||||
@@ -15,6 +15,9 @@ project unordered-test/unordered
|
||||
<toolset>darwin:<cxxflags>"-pedantic -Wstrict-aliasing -fstrict-aliasing -Wextra -Wsign-promo -Wunused-parameter -Wconversion -Wfloat-equal"
|
||||
#<toolset>gcc:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>darwin:<define>_GLIBCXX_DEBUG
|
||||
#<toolset>msvc:<warnings-as-errors>on
|
||||
<toolset>gcc:<warnings-as-errors>on
|
||||
<toolset>darwin:<warnings-as-errors>on
|
||||
;
|
||||
|
||||
test-suite unordered
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered/detail/allocate.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include <boost/limits.hpp>
|
||||
|
||||
// Boilerplate
|
||||
@@ -91,15 +91,15 @@ void test_empty_allocator()
|
||||
typedef empty_allocator<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::pointer, int*>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, int const*>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
@@ -129,15 +129,15 @@ void test_allocator1()
|
||||
typedef allocator1<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));
|
||||
#endif
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::pointer, int*>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, int const*>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(traits::propagate_on_container_swap::value);
|
||||
@@ -174,11 +174,11 @@ void test_allocator2()
|
||||
{
|
||||
typedef allocator2<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, std::size_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, int*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, int const*>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::size_type, std::size_t>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::pointer, int*>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, int const*>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
@@ -233,11 +233,11 @@ void test_allocator3()
|
||||
{
|
||||
typedef allocator3<int> allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<allocator> traits;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::size_type, unsigned short>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::pointer, ptr<int> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::const_pointer, ptr<int const> >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<traits::value_type, int>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::size_type, unsigned short>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::difference_type, std::ptrdiff_t>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::pointer, ptr<int> >));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::const_pointer, ptr<int const> >));
|
||||
BOOST_MPL_ASSERT((boost::is_same<traits::value_type, int>));
|
||||
BOOST_TEST(traits::propagate_on_container_copy_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_move_assignment::value);
|
||||
BOOST_TEST(!traits::propagate_on_container_swap::value);
|
||||
|
||||
@@ -25,7 +25,8 @@ namespace assign_tests {
|
||||
test::seed_t initialize_seed(96785);
|
||||
|
||||
template <class T>
|
||||
void assign_tests1(T*, test::random_generator generator)
|
||||
void assign_tests1(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@@ -62,12 +63,12 @@ void assign_tests1(T*, test::random_generator generator)
|
||||
tracker.compare(y);
|
||||
BOOST_TEST(x.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.max_load_factor() == mlf);
|
||||
BOOST_TEST(y.load_factor() <= y.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void assign_tests2(T*, test::random_generator generator)
|
||||
void assign_tests2(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf2(2);
|
||||
@@ -86,31 +87,9 @@ void assign_tests2(T*, test::random_generator generator)
|
||||
T x1(v.begin(), v.end(), 0, hf1, eq1);
|
||||
T x2(0, hf2, eq2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
test::check_container(x1, v);
|
||||
test::check_container(x2, v);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.1a\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(0, generator);
|
||||
test::random_values<T> v2(1000, generator);
|
||||
T x1(0, hf2, eq2);
|
||||
T x2(v2.begin(), v2.end(), 0, hf1, eq1);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x1.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x1.key_eq(), eq2));
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf2));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq2));
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.2\n";
|
||||
@@ -131,74 +110,22 @@ void assign_tests2(T*, test::random_generator generator)
|
||||
BOOST_TEST(test::equivalent(x2.get_allocator(), al2));
|
||||
BOOST_TEST(!test::equivalent(x2.get_allocator(), al1));
|
||||
}
|
||||
test::check_container(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.3\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(100, generator), v2(1000, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
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(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
|
||||
std::cerr<<"assign_tests2.4\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v1(1000, generator), v2(100, generator);
|
||||
T x1(v1.begin(), v1.end(), 0, hf1, eq1, al1);
|
||||
T x2(v2.begin(), v2.end(), 0, hf2, eq2, al2);
|
||||
x2 = x1;
|
||||
BOOST_TEST(test::equivalent(x2.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x2.key_eq(), eq1));
|
||||
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(x1, v1);
|
||||
test::check_container(x2, v1);
|
||||
BOOST_TEST(x2.load_factor() <= x2.max_load_factor());
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
@@ -251,7 +178,6 @@ UNORDERED_AUTO_TEST(check_traits)
|
||||
}
|
||||
|
||||
UNORDERED_TEST(assign_tests1, (
|
||||
(test_map_std_alloc)
|
||||
(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)
|
||||
@@ -267,7 +193,7 @@ UNORDERED_TEST(assign_tests2, (
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
@@ -282,7 +208,7 @@ UNORDERED_AUTO_TEST(assign_default_initializer_list) {
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
UNORDERED_AUTO_TEST(assign_initializer_list)
|
||||
{
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
|
||||
@@ -13,31 +13,21 @@
|
||||
namespace at_tests {
|
||||
|
||||
UNORDERED_AUTO_TEST(at_tests) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
|
||||
|
||||
boost::unordered_map<std::string, int> x;
|
||||
typedef boost::unordered_map<std::string, int>::iterator iterator;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Add elements" << std::endl;
|
||||
|
||||
x["one"] = 1;
|
||||
x["two"] = 2;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check existing elements" << std::endl;
|
||||
|
||||
BOOST_TEST(x.at("one") == 1);
|
||||
BOOST_TEST(x.at("two") == 2);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check missing element" << std::endl;
|
||||
|
||||
try {
|
||||
x.at("three");
|
||||
BOOST_ERROR("Should have thrown.");
|
||||
}
|
||||
catch(std::out_of_range) {
|
||||
}
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -24,7 +24,7 @@ namespace bucket_tests {
|
||||
test::seed_t initialize_seed(54635);
|
||||
|
||||
template <class X>
|
||||
void tests(X*, test::random_generator generator)
|
||||
void tests(X* = 0, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@@ -68,30 +68,20 @@ void tests(X*, test::random_generator generator)
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_multimap_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(tests,
|
||||
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(tests, ((test_set)(test_multiset)(test_map)(test_multimap)))
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@ template class boost::unordered_multimap<
|
||||
|
||||
template class boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
test::minimal::default_copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
template class boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >;
|
||||
@@ -48,7 +48,7 @@ UNORDERED_AUTO_TEST(test0)
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::assignable> value_type;
|
||||
test::minimal::copy_constructible> value_type;
|
||||
value_type value(x, x);
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
@@ -62,7 +62,7 @@ UNORDERED_AUTO_TEST(test0)
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > map;
|
||||
@@ -82,7 +82,7 @@ UNORDERED_AUTO_TEST(test0)
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> > multimap;
|
||||
@@ -95,7 +95,7 @@ UNORDERED_AUTO_TEST(test0)
|
||||
UNORDERED_AUTO_TEST(equality_tests) {
|
||||
typedef std::pair<
|
||||
test::minimal::copy_constructible_equality_comparable const,
|
||||
test::minimal::copy_constructible_equality_comparable> value_type;
|
||||
test::minimal::copy_constructible> value_type;
|
||||
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
@@ -187,44 +187,44 @@ UNORDERED_AUTO_TEST(test2)
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
typedef std::pair<test::minimal::assignable const,
|
||||
test::minimal::assignable> map_value_type;
|
||||
map_value_type map_value(assignable, assignable);
|
||||
test::minimal::copy_constructible> map_value_type;
|
||||
map_value_type map_value(assignable, copy_constructible);
|
||||
|
||||
std::cout<<"Test unordered_map.\n";
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > map;
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, assignable, assignable);
|
||||
unordered_map_test(map, assignable, copy_constructible);
|
||||
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||
|
||||
boost::unordered_map<
|
||||
test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
test::minimal::default_copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > map2;
|
||||
|
||||
test::minimal::default_assignable default_assignable;
|
||||
test::minimal::default_copy_constructible default_copy_constructible;
|
||||
|
||||
unordered_map_functions(map2, assignable, default_assignable);
|
||||
unordered_map_functions(map2, assignable, default_copy_constructible);
|
||||
|
||||
std::cout<<"Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::assignable,
|
||||
test::minimal::assignable,
|
||||
test::minimal::copy_constructible,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> > multimap;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, assignable, assignable);
|
||||
unordered_map_test(multimap, assignable, copy_constructible);
|
||||
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include <boost/mpl/bool.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/is_convertible.hpp>
|
||||
#include <boost/iterator/iterator_traits.hpp>
|
||||
@@ -54,38 +55,42 @@ void container_test(X& r, T const&)
|
||||
|
||||
// value_type
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T, value_type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T, value_type>));
|
||||
boost::function_requires<boost::CopyConstructibleConcept<X> >();
|
||||
|
||||
// reference_type / const_reference_type
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T&, reference>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T const&, const_reference>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T&, reference>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T const&, const_reference>));
|
||||
|
||||
// iterator
|
||||
|
||||
boost::function_requires<boost::InputIteratorConcept<iterator> >();
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T, iterator_value_type>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_convertible<iterator, const_iterator>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T, iterator_value_type>));
|
||||
BOOST_MPL_ASSERT((boost::is_convertible<iterator, const_iterator>));
|
||||
|
||||
// const_iterator
|
||||
|
||||
boost::function_requires<boost::InputIteratorConcept<const_iterator> >();
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T, const_iterator_value_type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<T, const_iterator_value_type>));
|
||||
|
||||
// difference_type
|
||||
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_signed);
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_integer);
|
||||
BOOST_STATIC_ASSERT((boost::is_same<difference_type,
|
||||
iterator_difference_type>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<difference_type,
|
||||
const_iterator_difference_type>::value));
|
||||
BOOST_MPL_ASSERT((boost::mpl::bool_<
|
||||
std::numeric_limits<difference_type>::is_signed>));
|
||||
BOOST_MPL_ASSERT((boost::mpl::bool_<
|
||||
std::numeric_limits<difference_type>::is_integer>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<difference_type,
|
||||
iterator_difference_type>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<difference_type,
|
||||
const_iterator_difference_type>));
|
||||
|
||||
// size_type
|
||||
|
||||
BOOST_STATIC_ASSERT(!std::numeric_limits<size_type>::is_signed);
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<size_type>::is_integer);
|
||||
BOOST_MPL_ASSERT_NOT((boost::mpl::bool_<
|
||||
std::numeric_limits<size_type>::is_signed>));
|
||||
BOOST_MPL_ASSERT((boost::mpl::bool_<
|
||||
std::numeric_limits<size_type>::is_integer>));
|
||||
|
||||
// size_type can represent any non-negative value type of difference_type
|
||||
// I'm not sure about either of these tests...
|
||||
@@ -179,7 +184,7 @@ void unordered_set_test(X&, Key const&)
|
||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<value_type, key_type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<value_type, key_type>));
|
||||
}
|
||||
|
||||
template <class X, class Key, class T>
|
||||
@@ -188,8 +193,8 @@ 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::key_type key_type;
|
||||
|
||||
BOOST_STATIC_ASSERT((
|
||||
boost::is_same<value_type, std::pair<key_type const, T> >::value));
|
||||
BOOST_MPL_ASSERT((
|
||||
boost::is_same<value_type, std::pair<key_type const, T> >));
|
||||
|
||||
r.insert(std::pair<Key const, T>(k, v));
|
||||
|
||||
@@ -308,36 +313,36 @@ void unordered_test(X& x, Key& k, Hash& hf, Pred& eq)
|
||||
boost::iterator_reference<const_local_iterator>::type
|
||||
const_local_iterator_reference;
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<Key, key_type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<Key, key_type>));
|
||||
//boost::function_requires<boost::CopyConstructibleConcept<key_type> >();
|
||||
//boost::function_requires<boost::AssignableConcept<key_type> >();
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<Hash, hasher>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<Hash, hasher>));
|
||||
test::check_return_type<std::size_t>::equals(hf(k));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<Pred, key_equal>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<Pred, key_equal>));
|
||||
test::check_return_type<bool>::convertible(eq(k, k));
|
||||
|
||||
boost::function_requires<boost::InputIteratorConcept<local_iterator> >();
|
||||
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_category,
|
||||
iterator_category>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_difference,
|
||||
iterator_difference>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_pointer,
|
||||
iterator_pointer>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<local_iterator_reference,
|
||||
iterator_reference>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<local_iterator_category,
|
||||
iterator_category>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<local_iterator_difference,
|
||||
iterator_difference>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<local_iterator_pointer,
|
||||
iterator_pointer>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<local_iterator_reference,
|
||||
iterator_reference>));
|
||||
|
||||
boost::function_requires<
|
||||
boost::InputIteratorConcept<const_local_iterator> >();
|
||||
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_category,
|
||||
const_iterator_category>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_difference,
|
||||
const_iterator_difference>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_pointer,
|
||||
const_iterator_pointer>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<const_local_iterator_reference,
|
||||
const_iterator_reference>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_category,
|
||||
const_iterator_category>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_difference,
|
||||
const_iterator_difference>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_pointer,
|
||||
const_iterator_pointer>));
|
||||
BOOST_MPL_ASSERT((boost::is_same<const_local_iterator_reference,
|
||||
const_iterator_reference>));
|
||||
|
||||
X(10, hf, eq);
|
||||
X a(10, hf, eq);
|
||||
|
||||
@@ -21,7 +21,8 @@ namespace constructor_tests {
|
||||
test::seed_t initialize_seed(356730);
|
||||
|
||||
template <class T>
|
||||
void constructor_tests1(T*, test::random_generator generator)
|
||||
void constructor_tests1(T*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@@ -172,7 +173,8 @@ void constructor_tests1(T*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void constructor_tests2(T*, test::random_generator const& generator)
|
||||
void constructor_tests2(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf1(1);
|
||||
@@ -316,7 +318,7 @@ void constructor_tests2(T*, test::random_generator const& generator)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
std::initializer_list<BOOST_DEDUCED_TYPENAME T::value_type> list;
|
||||
|
||||
std::cerr<<"Initializer list construct 1\n";
|
||||
@@ -381,7 +383,8 @@ void constructor_tests2(T*, test::random_generator const& generator)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void map_constructor_test(T*, test::random_generator const& generator)
|
||||
void map_constructor_test(T* = 0,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_constructor_test\n";
|
||||
|
||||
@@ -399,28 +402,24 @@ void map_constructor_test(T*, test::random_generator const& generator)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(constructor_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
@@ -430,11 +429,10 @@ UNORDERED_TEST(constructor_tests2,
|
||||
)
|
||||
|
||||
UNORDERED_TEST(map_constructor_test,
|
||||
((test_map_std_alloc)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
((test_map)(test_multimap))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_default_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
@@ -445,7 +443,7 @@ UNORDERED_AUTO_TEST(test_default_initializer_list) {
|
||||
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(test_initializer_list) {
|
||||
std::cerr<<"Initializer List Tests\n";
|
||||
|
||||
@@ -22,7 +22,8 @@ namespace copy_tests
|
||||
{
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests1(T*, test::random_generator const& generator)
|
||||
void copy_construct_tests1(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME T::allocator_type allocator_type;
|
||||
|
||||
@@ -81,8 +82,11 @@ void copy_construct_tests1(T*, test::random_generator const& generator)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests2(T*, test::random_generator const& generator)
|
||||
void copy_construct_tests2(T* ptr,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
copy_construct_tests1(ptr);
|
||||
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf(1);
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq(1);
|
||||
BOOST_DEDUCED_TYPENAME T::allocator_type al(1);
|
||||
@@ -151,16 +155,16 @@ void copy_construct_tests2(T*, test::random_generator const& generator)
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
@@ -204,7 +208,6 @@ UNORDERED_TEST(copy_construct_tests1, (
|
||||
(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))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2, (
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/list.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include <set>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
@@ -52,21 +51,12 @@ struct collision2_hash
|
||||
int operator()(int x) const { return x & 1; }
|
||||
};
|
||||
|
||||
// For testing erase in lots of buckets.
|
||||
struct collision3_hash
|
||||
{
|
||||
int operator()(int x) const { return x; }
|
||||
};
|
||||
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision_hash, std::equal_to<int>,
|
||||
test::allocator1<std::pair<int const, int> > > collide_map;
|
||||
test::allocator<std::pair<int const, int> > > collide_map;
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision2_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > > collide_map2;
|
||||
typedef boost::unordered_multimap<int, int,
|
||||
collision3_hash, std::equal_to<int>,
|
||||
test::allocator2<std::pair<int const, int> > > collide_map3;
|
||||
test::allocator<std::pair<int const, int> > > collide_map2;
|
||||
typedef collide_map::value_type collide_value;
|
||||
typedef test::list<collide_value> collide_list;
|
||||
|
||||
@@ -76,7 +66,6 @@ UNORDERED_AUTO_TEST(empty_range_tests)
|
||||
x.erase(x.begin(), x.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
x.erase(x.end(), x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(single_item_tests)
|
||||
@@ -87,13 +76,10 @@ UNORDERED_AUTO_TEST(single_item_tests)
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.begin());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.end(), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1);
|
||||
test::check_equivalent_keys(x);
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
@@ -106,7 +92,6 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
collide_map x(init.begin(), init.end());
|
||||
x.erase(x.begin(), x.end());
|
||||
BOOST_TEST(x.count(1) == 0 && x.size() == 0);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -115,7 +100,6 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
x.erase(x.begin(), boost::next(x.begin()));
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
{
|
||||
@@ -124,7 +108,6 @@ UNORDERED_AUTO_TEST(two_equivalent_item_tests)
|
||||
x.erase(boost::next(x.begin()), x.end());
|
||||
BOOST_TEST(x.count(1) == 1 && x.size() == 1 &&
|
||||
x.begin()->first == 1 && x.begin()->second == value);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +129,6 @@ bool general_erase_range_test(Container& x, std::size_t start, std::size_t end)
|
||||
collide_list l(x.begin(), x.end());
|
||||
l.erase(boost::next(l.begin(), start), boost::next(l.begin(), end));
|
||||
x.erase(boost::next(x.begin(), start), boost::next(x.begin(), end));
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
return compare(l, x);
|
||||
}
|
||||
|
||||
@@ -210,11 +191,4 @@ UNORDERED_AUTO_TEST(exhaustive_collide2_tests)
|
||||
std::cout<<"\n";
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(exhaustive_collide3_tests)
|
||||
{
|
||||
std::cout<<"exhaustive_collide3_tests:\n";
|
||||
exhaustive_erase_tests((collide_map3*) 0, 8, 4);
|
||||
std::cout<<"\n";
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -25,7 +24,8 @@ namespace erase_tests
|
||||
test::seed_t initialize_seed(85638);
|
||||
|
||||
template <class Container>
|
||||
void erase_tests1(Container*, test::random_generator generator)
|
||||
void erase_tests1(Container*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"Erase by key.\n";
|
||||
{
|
||||
@@ -33,7 +33,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
int iterations = 0;
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<Container>::iterator
|
||||
it = v.begin(); it != v.end(); ++it)
|
||||
{
|
||||
@@ -43,7 +42,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
BOOST_TEST(x.size() == old_size - count);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == 0);
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,7 +52,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
@@ -66,7 +63,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
BOOST_TEST(pos == x.begin());
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
@@ -78,7 +74,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
@@ -102,7 +97,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
@@ -123,15 +117,12 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
BOOST_TEST(x.erase(x.end(), x.end()) == x.end());
|
||||
BOOST_TEST(x.erase(x.begin(), x.begin()) == x.begin());
|
||||
BOOST_TEST(x.size() == size);
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.end());
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.begin() == x.end());
|
||||
test::check_equivalent_keys(x);
|
||||
|
||||
BOOST_TEST(x.erase(x.begin(), x.end()) == x.begin());
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"quick_erase(begin()).\n";
|
||||
@@ -141,7 +132,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type
|
||||
@@ -151,7 +141,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
--size;
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
@@ -163,7 +152,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
test::random_values<Container> v(1000, generator);
|
||||
Container x(v.begin(), v.end());
|
||||
std::size_t size = x.size();
|
||||
int iterations = 0;
|
||||
while(size > 0 && !x.empty())
|
||||
{
|
||||
using namespace std;
|
||||
@@ -187,7 +175,6 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
next == boost::next(prev));
|
||||
BOOST_TEST(x.count(key) == count - 1);
|
||||
BOOST_TEST(x.size() == size);
|
||||
if (++iterations % 20 == 0) test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
@@ -209,16 +196,16 @@ void erase_tests1(Container*, test::random_generator generator)
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
@@ -20,7 +20,7 @@ namespace find_tests
|
||||
test::seed_t initialize_seed(78937);
|
||||
|
||||
template <class X>
|
||||
void find_tests1(X*, test::random_generator generator)
|
||||
void find_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
|
||||
@@ -115,7 +115,8 @@ struct compatible_predicate
|
||||
};
|
||||
|
||||
template <class X>
|
||||
void find_compatible_keys_test(X*, test::random_generator generator)
|
||||
void find_compatible_keys_test(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator
|
||||
@@ -141,16 +142,16 @@ void find_compatible_keys_test(X*, test::random_generator generator)
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
@@ -15,25 +15,26 @@ namespace x
|
||||
struct D { boost::unordered_map<D, D> x; };
|
||||
}
|
||||
|
||||
namespace incomplete_test
|
||||
namespace test
|
||||
{
|
||||
// Declare, but don't define some types.
|
||||
|
||||
struct value;
|
||||
struct hash;
|
||||
struct equals;
|
||||
template <class T> struct allocator;
|
||||
template <class T>
|
||||
struct malloc_allocator;
|
||||
|
||||
// Declare some instances
|
||||
|
||||
typedef boost::unordered_map<value, value, hash, equals,
|
||||
allocator<std::pair<value const, value> > > map;
|
||||
malloc_allocator<std::pair<value const, value> > > map;
|
||||
typedef boost::unordered_multimap<value, value, hash, equals,
|
||||
allocator<std::pair<value const, value> > > multimap;
|
||||
malloc_allocator<std::pair<value const, value> > > multimap;
|
||||
typedef boost::unordered_set<value, hash, equals,
|
||||
allocator<value> > set;
|
||||
malloc_allocator<value> > set;
|
||||
typedef boost::unordered_multiset<value, hash, equals,
|
||||
allocator<value> > multiset;
|
||||
malloc_allocator<value> > multiset;
|
||||
|
||||
// Now define the types which are stored as members, as they are needed for
|
||||
// declaring struct members.
|
||||
@@ -48,17 +49,12 @@ namespace incomplete_test
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
};
|
||||
|
||||
// This is a dubious way to implement an allocator, but good enough
|
||||
// for this test.
|
||||
template <typename T>
|
||||
struct allocator : std::allocator<T> {
|
||||
allocator() {}
|
||||
}
|
||||
|
||||
template <typename T2>
|
||||
allocator(const allocator<T2>& other) :
|
||||
std::allocator<T>(other) {}
|
||||
};
|
||||
#include "../helpers/allocator.hpp"
|
||||
|
||||
namespace test
|
||||
{
|
||||
// Declare some members of a structs.
|
||||
//
|
||||
// Incomplete hash, equals and allocator aren't here supported at the
|
||||
@@ -66,19 +62,19 @@ namespace incomplete_test
|
||||
|
||||
struct struct1 {
|
||||
boost::unordered_map<struct1, struct1, hash, equals,
|
||||
allocator<std::pair<struct1 const, struct1> > > x;
|
||||
malloc_allocator<std::pair<struct1 const, struct1> > > x;
|
||||
};
|
||||
struct struct2 {
|
||||
boost::unordered_multimap<struct2, struct2, hash, equals,
|
||||
allocator<std::pair<struct2 const, struct2> > > x;
|
||||
malloc_allocator<std::pair<struct2 const, struct2> > > x;
|
||||
};
|
||||
struct struct3 {
|
||||
boost::unordered_set<struct3, hash, equals,
|
||||
allocator<struct3> > x;
|
||||
malloc_allocator<struct3> > x;
|
||||
};
|
||||
struct struct4 {
|
||||
boost::unordered_multiset<struct4, hash, equals,
|
||||
allocator<struct4> > x;
|
||||
malloc_allocator<struct4> > x;
|
||||
};
|
||||
|
||||
// Now define the value type.
|
||||
@@ -87,15 +83,15 @@ namespace incomplete_test
|
||||
|
||||
// Create some instances.
|
||||
|
||||
incomplete_test::map m1;
|
||||
incomplete_test::multimap m2;
|
||||
incomplete_test::set s1;
|
||||
incomplete_test::multiset s2;
|
||||
test::map m1;
|
||||
test::multimap m2;
|
||||
test::set s1;
|
||||
test::multiset s2;
|
||||
|
||||
incomplete_test::struct1 c1;
|
||||
incomplete_test::struct2 c2;
|
||||
incomplete_test::struct3 c3;
|
||||
incomplete_test::struct4 c4;
|
||||
test::struct1 c1;
|
||||
test::struct2 c2;
|
||||
test::struct3 c3;
|
||||
test::struct4 c4;
|
||||
|
||||
// Now declare, but don't define, the operators required for comparing
|
||||
// elements.
|
||||
@@ -117,7 +113,7 @@ namespace incomplete_test
|
||||
|
||||
void use_types()
|
||||
{
|
||||
incomplete_test::value x;
|
||||
test::value x;
|
||||
m1[x] = x;
|
||||
m2.insert(std::make_pair(x, x));
|
||||
s1.insert(x);
|
||||
@@ -149,5 +145,5 @@ int main() {
|
||||
// This could just be a compile test, but I like to be able to run these
|
||||
// things. It's probably irrational, but I find it reassuring.
|
||||
|
||||
incomplete_test::use_types();
|
||||
test::use_types();
|
||||
}
|
||||
|
||||
+34
-142
@@ -16,7 +16,6 @@
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
@@ -25,7 +24,8 @@ namespace insert_tests {
|
||||
test::seed_t initialize_seed(243432);
|
||||
|
||||
template <class X>
|
||||
void unique_insert_tests1(X*, test::random_generator generator)
|
||||
void unique_insert_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
@@ -63,7 +63,8 @@ void unique_insert_tests1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void equivalent_insert_tests1(X*, test::random_generator generator)
|
||||
void equivalent_insert_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"insert(value) tests for containers with equivalent keys.\n";
|
||||
|
||||
@@ -96,7 +97,8 @@ void equivalent_insert_tests1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void insert_tests2(X*, test::random_generator generator)
|
||||
void insert_tests2(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME test::ordered<X> tracker_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
@@ -230,24 +232,6 @@ void insert_tests2(X*, test::random_generator generator)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"insert range with rehash tests.\n";
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
X x;
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
|
||||
x.insert(*v.begin());
|
||||
x.clear();
|
||||
|
||||
x.insert(v.begin(), v.end());
|
||||
|
||||
test::check_container(x, v);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"insert input iterator range tests.\n";
|
||||
|
||||
{
|
||||
@@ -277,25 +261,13 @@ void insert_tests2(X*, test::random_generator generator)
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
std::cerr<<"insert copy iterator range test 2.\n";
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
X x;
|
||||
|
||||
test::random_values<X> v1(500, generator);
|
||||
test::random_values<X> v2(500, generator);
|
||||
x.insert(test::copy_iterator(v1.begin()), test::copy_iterator(v1.end()));
|
||||
x.insert(test::copy_iterator(v2.begin()), test::copy_iterator(v2.end()));
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
|
||||
template <class X>
|
||||
void unique_emplace_tests1(X*, test::random_generator generator)
|
||||
void unique_emplace_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef test::ordered<X> ordered;
|
||||
@@ -331,7 +303,8 @@ void unique_emplace_tests1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void equivalent_emplace_tests1(X*, test::random_generator generator)
|
||||
void equivalent_emplace_tests1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"emplace(value) tests for containers with equivalent keys.\n";
|
||||
|
||||
@@ -360,76 +333,10 @@ void equivalent_emplace_tests1(X*, test::random_generator generator)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void move_emplace_tests(X*, test::random_generator generator)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
typedef test::ordered<X> ordered;
|
||||
|
||||
std::cerr<<"emplace(move(value)) tests for containers with unique keys.\n";
|
||||
|
||||
X x;
|
||||
test::ordered<X> tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
|
||||
for(BOOST_DEDUCED_TYPENAME test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
{
|
||||
|
||||
BOOST_DEDUCED_TYPENAME X::size_type old_bucket_count = x.bucket_count();
|
||||
float b = x.max_load_factor();
|
||||
|
||||
typename X::value_type value = *it;
|
||||
x.emplace(boost::move(value));
|
||||
tracker.insert(*it);
|
||||
tracker.compare_key(x, *it);
|
||||
|
||||
if(static_cast<double>(x.size()) < b * static_cast<double>(old_bucket_count))
|
||||
BOOST_TEST(x.bucket_count() == old_bucket_count);
|
||||
}
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
tracker.compare(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class X>
|
||||
void default_emplace_tests(X*, test::random_generator)
|
||||
{
|
||||
std::cerr<<"emplace() tests.\n";
|
||||
bool is_unique = test::has_unique_keys<X>::value;
|
||||
|
||||
X x;
|
||||
|
||||
x.emplace();
|
||||
BOOST_TEST(x.size() == 1);
|
||||
x.emplace();
|
||||
BOOST_TEST(x.size() == is_unique ? 1: 2);
|
||||
x.emplace();
|
||||
BOOST_TEST(x.size() == is_unique ? 1: 3);
|
||||
|
||||
typename X::value_type y;
|
||||
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 3);
|
||||
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
|
||||
|
||||
x.emplace(y);
|
||||
BOOST_TEST(x.size() == is_unique ? 1: 4);
|
||||
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 4);
|
||||
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
|
||||
|
||||
x.clear();
|
||||
BOOST_TEST(x.empty());
|
||||
x.emplace(y);
|
||||
BOOST_TEST(x.size() == 1);
|
||||
x.emplace(y);
|
||||
BOOST_TEST(x.size() == is_unique ? 1: 2);
|
||||
|
||||
BOOST_TEST(x.count(test::get_key<X>(y)) == is_unique ? 1: 2);
|
||||
BOOST_TEST(*x.equal_range(test::get_key<X>(y)).first == y);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void map_tests(X*, test::random_generator generator)
|
||||
void map_tests(X*, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map tests.\n";
|
||||
|
||||
@@ -459,7 +366,8 @@ void map_tests(X*, test::random_generator generator)
|
||||
// value type.
|
||||
|
||||
template <class X>
|
||||
void map_insert_range_test1(X*, test::random_generator generator)
|
||||
void map_insert_range_test1(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_insert_range_test1\n";
|
||||
|
||||
@@ -480,7 +388,8 @@ void map_insert_range_test1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void map_insert_range_test2(X*, test::random_generator generator)
|
||||
void map_insert_range_test2(X*,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
std::cerr<<"map_insert_range_test2\n";
|
||||
|
||||
@@ -499,65 +408,48 @@ void map_insert_range_test2(X*, test::random_generator generator)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
boost::unordered_set<test::movable,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_set_std_alloc;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_multimap_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::movable,
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::movable> >* test_multiset;
|
||||
boost::unordered_map<test::movable, test::movable,
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::movable> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(unique_insert_tests1,
|
||||
((test_set_std_alloc)(test_set)(test_map))
|
||||
((test_set)(test_map))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(equivalent_insert_tests1,
|
||||
((test_multimap_std_alloc)(test_multiset)(test_multimap))
|
||||
((test_multiset)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(insert_tests2,
|
||||
((test_multimap_std_alloc)(test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((test_set)(test_multiset)(test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES) && !defined(BOOST_NO_VARIADIC_TEMPLATES)
|
||||
UNORDERED_TEST(unique_emplace_tests1,
|
||||
((test_set_std_alloc)(test_set)(test_map))
|
||||
((test_set)(test_map))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(equivalent_emplace_tests1,
|
||||
((test_multimap_std_alloc)(test_multiset)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(move_emplace_tests,
|
||||
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
|
||||
(test_multiset)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(default_emplace_tests,
|
||||
((test_set_std_alloc)(test_multimap_std_alloc)(test_set)(test_map)
|
||||
(test_multiset)(test_multimap))
|
||||
((test_multiset)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
#endif
|
||||
|
||||
UNORDERED_TEST(map_tests,
|
||||
((test_map))
|
||||
@@ -565,16 +457,16 @@ UNORDERED_TEST(map_tests,
|
||||
)
|
||||
|
||||
UNORDERED_TEST(map_insert_range_test1,
|
||||
((test_multimap_std_alloc)(test_map)(test_multimap))
|
||||
((test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(map_insert_range_test2,
|
||||
((test_multimap_std_alloc)(test_map)(test_multimap))
|
||||
((test_map)(test_multimap))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#if !defined(BOOST_NO_0X_HDR_INITIALIZER_LIST)
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_initializer_list_set)
|
||||
{
|
||||
|
||||
@@ -23,7 +23,7 @@ namespace load_factor_tests
|
||||
test::seed_t initialize_seed(783656);
|
||||
|
||||
template <class X>
|
||||
void set_load_factor_tests(X*)
|
||||
void set_load_factor_tests(X* = 0)
|
||||
{
|
||||
X x;
|
||||
|
||||
@@ -37,7 +37,8 @@ void set_load_factor_tests(X*)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void insert_test(X*, float mlf, test::random_generator generator)
|
||||
void insert_test(X*, float mlf,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
X x;
|
||||
x.max_load_factor(mlf);
|
||||
@@ -57,18 +58,16 @@ void insert_test(X*, float mlf, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void load_factor_insert_tests(X* ptr, test::random_generator generator)
|
||||
void load_factor_insert_tests(X* ptr = 0)
|
||||
{
|
||||
insert_test(ptr, 1.0f, generator);
|
||||
insert_test(ptr, 0.1f, generator);
|
||||
insert_test(ptr, 100.0f, generator);
|
||||
insert_test(ptr, 1.0f);
|
||||
insert_test(ptr, 0.1f);
|
||||
insert_test(ptr, 100.0f);
|
||||
|
||||
insert_test(ptr, (std::numeric_limits<float>::min)(),
|
||||
generator);
|
||||
insert_test(ptr, (std::numeric_limits<float>::min)());
|
||||
|
||||
if(std::numeric_limits<float>::has_infinity)
|
||||
insert_test(ptr, std::numeric_limits<float>::infinity(),
|
||||
generator);
|
||||
insert_test(ptr, std::numeric_limits<float>::infinity());
|
||||
}
|
||||
|
||||
boost::unordered_set<int>* int_set_ptr;
|
||||
@@ -76,16 +75,12 @@ boost::unordered_multiset<int>* int_multiset_ptr;
|
||||
boost::unordered_map<int, int>* int_map_ptr;
|
||||
boost::unordered_multimap<int, int>* int_multimap_ptr;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(set_load_factor_tests,
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(load_factor_insert_tests,
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/unordered/detail/allocate.hpp>
|
||||
#include <boost/unordered/detail/allocator_helpers.hpp>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/mpl/assert.hpp>
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
template <class Tp>
|
||||
@@ -41,22 +41,22 @@ void test_simple_allocator()
|
||||
typedef boost::unordered::detail::allocator_traits<
|
||||
SimpleAllocator<T> > traits;
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::allocator_type, SimpleAllocator<T> >::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::allocator_type, SimpleAllocator<T> >));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::value_type, T>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::value_type, T>));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::pointer, T* >::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::const_pointer, T const*>::value));
|
||||
//BOOST_STATIC_ASSERT((boost::is_same<typename traits::void_pointer, void* >::value));
|
||||
//BOOST_STATIC_ASSERT((boost::is_same<typename traits::const_void_pointer, void const*>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::pointer, T* >));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::const_pointer, T const*>));
|
||||
//BOOST_MPL_ASSERT((boost::is_same<typename traits::void_pointer, void* >));
|
||||
//BOOST_MPL_ASSERT((boost::is_same<typename traits::const_void_pointer, void const*>));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::difference_type, std::ptrdiff_t>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::difference_type, std::ptrdiff_t>));
|
||||
|
||||
#if BOOST_UNORDERED_USE_ALLOCATOR_TRAITS == 1
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::size_type,
|
||||
std::make_unsigned<std::ptrdiff_t>::type>));
|
||||
#else
|
||||
BOOST_STATIC_ASSERT((boost::is_same<typename traits::size_type, std::size_t>::value));
|
||||
BOOST_MPL_ASSERT((boost::is_same<typename traits::size_type, std::size_t>));
|
||||
#endif
|
||||
|
||||
BOOST_TEST(!traits::propagate_on_container_copy_assignment::value);
|
||||
|
||||
@@ -57,7 +57,8 @@ namespace move_tests
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_construct_tests1(T* ptr, test::random_generator const& generator)
|
||||
void move_construct_tests1(T* ptr,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
BOOST_DEDUCED_TYPENAME T::hasher hf;
|
||||
BOOST_DEDUCED_TYPENAME T::key_equal eq;
|
||||
@@ -90,7 +91,8 @@ namespace move_tests
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_assign_tests1(T*, test::random_generator const& generator)
|
||||
void move_assign_tests1(T*,
|
||||
test::random_generator const& generator = test::default_generator)
|
||||
{
|
||||
{
|
||||
test::check_instances check_;
|
||||
@@ -108,7 +110,8 @@ namespace move_tests
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_construct_tests2(T*, test::random_generator const& generator)
|
||||
void move_construct_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);
|
||||
@@ -158,17 +161,13 @@ namespace move_tests
|
||||
BOOST_TEST(count == test::global_object_count);
|
||||
#elif defined(BOOST_HAS_NRVO)
|
||||
BOOST_TEST(
|
||||
static_cast<std::size_t>(test::global_object_count.constructions
|
||||
- count.constructions) <=
|
||||
(test::is_set<T>::value ? 1 : 2) *
|
||||
(test::has_unique_keys<T>::value ? 25 : v.size()));
|
||||
test::global_object_count.constructions - count.constructions <=
|
||||
(test::is_map<T>::value ? 50 : 25));
|
||||
BOOST_TEST(count.instances == test::global_object_count.instances);
|
||||
#else
|
||||
BOOST_TEST(
|
||||
static_cast<std::size_t>(test::global_object_count.constructions
|
||||
- count.constructions) <=
|
||||
(test::is_set<T>::value ? 2 : 4) *
|
||||
(test::has_unique_keys<T>::value ? 25 : v.size()));
|
||||
test::global_object_count.constructions - count.constructions <=
|
||||
(test::is_map<T>::value ? 100 : 50));
|
||||
BOOST_TEST(count.instances == test::global_object_count.instances);
|
||||
#endif
|
||||
test::check_container(y, v);
|
||||
@@ -181,7 +180,8 @@ namespace move_tests
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void move_assign_tests2(T*, test::random_generator const& generator)
|
||||
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);
|
||||
@@ -316,22 +316,18 @@ namespace move_tests
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
@@ -371,20 +367,16 @@ boost::unordered_multimap<test::object, test::object,
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(move_construct_tests1, (
|
||||
(test_map_std_alloc)
|
||||
(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))
|
||||
)
|
||||
UNORDERED_TEST(move_assign_tests1, (
|
||||
(test_map_std_alloc)
|
||||
(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))
|
||||
)
|
||||
UNORDERED_TEST(move_construct_tests2, (
|
||||
(test_set)(test_multiset)(test_map)(test_multimap)
|
||||
@@ -398,7 +390,6 @@ boost::unordered_multimap<test::object, test::object,
|
||||
(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))
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
namespace rehash_tests
|
||||
{
|
||||
@@ -28,7 +26,7 @@ bool postcondition(X const& x, BOOST_DEDUCED_TYPENAME X::size_type n)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_empty_test1(X*)
|
||||
void rehash_empty_test1(X* = 0)
|
||||
{
|
||||
X x;
|
||||
|
||||
@@ -37,13 +35,11 @@ void rehash_empty_test1(X*)
|
||||
|
||||
x.rehash(0);
|
||||
BOOST_TEST(postcondition(x, 0));
|
||||
|
||||
x.rehash(10000000);
|
||||
BOOST_TEST(postcondition(x, 10000000));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_empty_test2(X*, test::random_generator generator)
|
||||
void rehash_empty_test2(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
@@ -58,14 +54,11 @@ void rehash_empty_test2(X*, test::random_generator generator)
|
||||
tracker.compare(x);
|
||||
|
||||
BOOST_TEST(postcondition(x, 10000));
|
||||
|
||||
x.rehash(10000000);
|
||||
tracker.compare(x);
|
||||
BOOST_TEST(postcondition(x, 10000000));
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_empty_test3(X*, test::random_generator generator)
|
||||
void rehash_empty_test3(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
@@ -82,8 +75,10 @@ void rehash_empty_test3(X*, test::random_generator generator)
|
||||
BOOST_TEST(postcondition(x, 0));
|
||||
}
|
||||
|
||||
|
||||
template <class X>
|
||||
void rehash_test1(X*, test::random_generator generator)
|
||||
void rehash_test1(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
@@ -106,36 +101,8 @@ void rehash_test1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void reserve_empty_test1(X*)
|
||||
{
|
||||
X x;
|
||||
|
||||
x.reserve(10000);
|
||||
BOOST_TEST(x.bucket_count() >= 10000);
|
||||
|
||||
x.reserve(0);
|
||||
|
||||
x.reserve(10000000);
|
||||
BOOST_TEST(x.bucket_count() >= 10000000);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void reserve_empty_test2(X*)
|
||||
{
|
||||
X x;
|
||||
x.max_load_factor(0.25);
|
||||
|
||||
x.reserve(10000);
|
||||
BOOST_TEST(x.bucket_count() >= 40000);
|
||||
|
||||
x.reserve(0);
|
||||
|
||||
x.reserve(10000000);
|
||||
BOOST_TEST(x.bucket_count() >= 40000000);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void reserve_test1(X*, test::random_generator generator)
|
||||
void reserve_test1(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
|
||||
{
|
||||
@@ -149,10 +116,11 @@ void reserve_test1(X*, test::random_generator generator)
|
||||
X x;
|
||||
x.max_load_factor(random_mlf ?
|
||||
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
|
||||
|
||||
// For the current standard this should reserve i+1, I've
|
||||
// submitted a defect report and will assume it's a defect
|
||||
// for now.
|
||||
x.reserve(test::has_unique_keys<X>::value ? i : v.size());
|
||||
x.reserve(i);
|
||||
|
||||
// Insert an element before the range insert, otherwise there are
|
||||
// no iterators to invalidate in the range insert, and it can
|
||||
@@ -170,7 +138,8 @@ void reserve_test1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void reserve_test2(X*, test::random_generator generator)
|
||||
void reserve_test2(X* = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
for (int random_mlf = 0; random_mlf < 2; ++random_mlf)
|
||||
{
|
||||
@@ -185,9 +154,9 @@ void reserve_test2(X*, test::random_generator generator)
|
||||
x.max_load_factor(random_mlf ?
|
||||
static_cast<float>(std::rand() % 1000) / 500.0f + 0.5f : 1.0f);
|
||||
|
||||
x.reserve(test::has_unique_keys<X>::value ? i : v.size());
|
||||
|
||||
x.reserve(i);
|
||||
std::size_t bucket_count = x.bucket_count();
|
||||
|
||||
for (typename test::random_values<X>::iterator it = v.begin();
|
||||
it != v.end(); ++it)
|
||||
{
|
||||
@@ -201,45 +170,27 @@ void reserve_test2(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
boost::unordered_set<int>* int_set_ptr;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset_ptr;
|
||||
boost::unordered_map<test::movable, test::movable,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::movable> >* test_map_ptr;
|
||||
boost::unordered_multiset<int>* int_multiset_ptr;
|
||||
boost::unordered_map<int, int>* int_map_ptr;
|
||||
boost::unordered_multimap<int, int>* int_multimap_ptr;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(rehash_empty_test1,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(rehash_empty_test2,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((default_generator)(generate_collisions))
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(rehash_empty_test3,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((default_generator)(generate_collisions))
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(rehash_test1,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(reserve_empty_test1,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(reserve_empty_test2,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(reserve_test1,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((default_generator)(generate_collisions))
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
UNORDERED_TEST(reserve_test2,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr))
|
||||
((default_generator)(generate_collisions))
|
||||
((int_set_ptr)(int_multiset_ptr)(int_map_ptr)(int_multimap_ptr))
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ void swap_test_impl(X& x1, X& x2)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void swap_tests1(X*, test::random_generator generator)
|
||||
void swap_tests1(X*, test::random_generator generator = test::default_generator)
|
||||
{
|
||||
{
|
||||
test::check_instances check_;
|
||||
@@ -76,9 +76,10 @@ void swap_tests1(X*, test::random_generator generator)
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void swap_tests2(X* ptr, test::random_generator generator)
|
||||
void swap_tests2(X* ptr = 0,
|
||||
test::random_generator generator = test::default_generator)
|
||||
{
|
||||
swap_tests1(ptr, generator);
|
||||
swap_tests1(ptr);
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::hasher hasher;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_equal key_equal;
|
||||
@@ -147,22 +148,18 @@ void swap_tests2(X* ptr, test::random_generator generator)
|
||||
}
|
||||
}
|
||||
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
test::allocator<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
test::allocator<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
test::allocator<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object,
|
||||
test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multimap;
|
||||
test::allocator<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<test::object,
|
||||
test::hash, test::equal_to,
|
||||
@@ -204,9 +201,6 @@ bool is_propagate(T*)
|
||||
return T::allocator_type::is_propagate_on_swap;
|
||||
}
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_AUTO_TEST(check_traits)
|
||||
{
|
||||
BOOST_TEST(!is_propagate(test_set));
|
||||
@@ -215,21 +209,16 @@ UNORDERED_AUTO_TEST(check_traits)
|
||||
}
|
||||
|
||||
UNORDERED_TEST(swap_tests1, (
|
||||
(test_map_std_alloc)
|
||||
(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)
|
||||
)
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
(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)
|
||||
)
|
||||
((default_generator)(generate_collisions))
|
||||
)
|
||||
(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()
|
||||
|
||||
@@ -11,6 +11,23 @@
|
||||
#include <iostream>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
#if defined(BOOST_UNORDERED_VARIADIC_MOVE)
|
||||
# if defined(__SGI_STL_PORT) || defined(_STLPORT_VERSION)
|
||||
# elif defined(__STD_RWCOMPILER_H__) || defined(_RWSTD_VER)
|
||||
# elif defined(_LIBCPP_VERSION)
|
||||
# define BOOST_UNORDERED_VARIADIC_MOVE
|
||||
# elif defined(__GLIBCPP__) || defined(__GLIBCXX__)
|
||||
# if defined(__GLIBCXX__) && __GLIBCXX__ >= 20090804
|
||||
# define BOOST_UNORDERED_VARIADIC_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)
|
||||
# endif
|
||||
#endif
|
||||
|
||||
namespace unnecessary_copy_tests
|
||||
{
|
||||
struct count_copies
|
||||
@@ -20,17 +37,8 @@ namespace unnecessary_copy_tests
|
||||
public:
|
||||
static int copies;
|
||||
static int moves;
|
||||
static int id_count;
|
||||
|
||||
count_copies() : tag_(0), id_(++id_count) {
|
||||
++copies;
|
||||
trace_op("Default construct");
|
||||
}
|
||||
|
||||
explicit count_copies(int tag) : tag_(tag), id_(++id_count) {
|
||||
++copies;
|
||||
trace_op("Tag construct");
|
||||
}
|
||||
count_copies() : tag_(0) { ++copies; }
|
||||
explicit count_copies(int tag) : tag_(tag) { ++copies; }
|
||||
|
||||
// This bizarre constructor is an attempt to confuse emplace.
|
||||
//
|
||||
@@ -42,30 +50,17 @@ namespace unnecessary_copy_tests
|
||||
// The second emplace should use the single argument contructor for
|
||||
// the key, and this constructor for the value.
|
||||
count_copies(count_copies const&, count_copies const& x)
|
||||
: tag_(x.tag_), id_(++id_count)
|
||||
{
|
||||
++copies;
|
||||
trace_op("Pair construct");
|
||||
}
|
||||
: tag_(x.tag_) { ++copies; }
|
||||
|
||||
count_copies(count_copies const& x) : tag_(x.tag_), id_(++id_count)
|
||||
{
|
||||
++copies;
|
||||
trace_op("Copy construct");
|
||||
}
|
||||
|
||||
count_copies(BOOST_RV_REF(count_copies) x) :
|
||||
tag_(x.tag_), id_(++id_count)
|
||||
{
|
||||
count_copies(count_copies const& x) : tag_(x.tag_) { ++copies; }
|
||||
count_copies(BOOST_RV_REF(count_copies) x) : tag_(x.tag_) {
|
||||
x.tag_ = -1; ++moves;
|
||||
trace_op("Move construct");
|
||||
}
|
||||
|
||||
count_copies& operator=(BOOST_COPY_ASSIGN_REF(count_copies) p) // Copy assignment
|
||||
{
|
||||
tag_ = p.tag_;
|
||||
++copies;
|
||||
trace_op("Copy assign");
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -73,21 +68,10 @@ namespace unnecessary_copy_tests
|
||||
{
|
||||
tag_ = p.tag_;
|
||||
++moves;
|
||||
trace_op("Move assign");
|
||||
return *this;
|
||||
}
|
||||
|
||||
~count_copies() {
|
||||
trace_op("Destruct");
|
||||
}
|
||||
|
||||
void trace_op(char const* str) {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << str << ": " << tag_
|
||||
<< " (#" << id_ << ")" <<std::endl;
|
||||
}
|
||||
|
||||
int tag_;
|
||||
int id_;
|
||||
};
|
||||
|
||||
bool operator==(count_copies const& x, count_copies const& y) {
|
||||
@@ -102,9 +86,6 @@ namespace unnecessary_copy_tests
|
||||
void reset() {
|
||||
count_copies::copies = 0;
|
||||
count_copies::moves = 0;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM
|
||||
<< "\nReset\n" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,7 +139,6 @@ namespace unnecessary_copy_tests
|
||||
{
|
||||
int count_copies::copies;
|
||||
int count_copies::moves;
|
||||
int count_copies::id_count;
|
||||
|
||||
template <class T>
|
||||
void unnecessary_copy_insert_test(T*)
|
||||
@@ -207,6 +187,7 @@ namespace unnecessary_copy_tests
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_rvalue_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||
template <class T>
|
||||
void unnecessary_copy_emplace_move_test(T*)
|
||||
{
|
||||
@@ -214,17 +195,13 @@ namespace unnecessary_copy_tests
|
||||
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)
|
||||
x.emplace(std::move(a));
|
||||
COPY_COUNT(1); MOVE_COUNT(1);
|
||||
#else
|
||||
// Since std::pair isn't movable, move only works for sets.
|
||||
COPY_COUNT_RANGE(1, 2); MOVE_COUNT_RANGE(0, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_TEST(unnecessary_copy_emplace_move_test,
|
||||
((set)(multiset)(map)(multimap)))
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
void unnecessary_copy_emplace_boost_move_set_test(T*)
|
||||
@@ -285,8 +262,7 @@ namespace unnecessary_copy_tests
|
||||
// the existing element.
|
||||
reset();
|
||||
x.emplace();
|
||||
#if !defined(BOOST_NO_VARIADIC_TEMPLATES) || \
|
||||
!defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
// source_cost doesn't make much sense here, but it seems to fit.
|
||||
COPY_COUNT(1); MOVE_COUNT(source_cost);
|
||||
#else
|
||||
@@ -310,16 +286,14 @@ namespace unnecessary_copy_tests
|
||||
x.emplace(source<count_copies>());
|
||||
COPY_COUNT(1); MOVE_COUNT(source_cost);
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||
// No move should take place.
|
||||
reset();
|
||||
x.emplace(boost::move(a));
|
||||
#if !defined(BOOST_NO_RVALUE_REFERENCES)
|
||||
x.emplace(std::move(a));
|
||||
COPY_COUNT(0); MOVE_COUNT(0);
|
||||
#else
|
||||
COPY_COUNT(0); MOVE_COUNT(1);
|
||||
#endif
|
||||
|
||||
// Use a new value for cases where a did get moved...
|
||||
// Just in case a did get moved...
|
||||
count_copies b;
|
||||
|
||||
// The container will have to create a copy in order to compare with
|
||||
@@ -374,16 +348,7 @@ namespace unnecessary_copy_tests
|
||||
// COPY_COUNT(1) would be okay here.
|
||||
reset();
|
||||
x.emplace();
|
||||
# if BOOST_WORKAROUND(BOOST_MSVC, >= 1700)
|
||||
// This is a little odd, Visual C++ 11 seems to move the pair, which
|
||||
// results in one copy (for the const key) and one move (for the
|
||||
// non-const mapped value). Since 'emplace(boost::move(a))' (see below)
|
||||
// has the normal result, it must be some odd consequence of how
|
||||
// Visual C++ 11 handles calling move for default arguments.
|
||||
COPY_COUNT(3); MOVE_COUNT(1);
|
||||
# else
|
||||
COPY_COUNT(2); MOVE_COUNT(0);
|
||||
# endif
|
||||
#endif
|
||||
|
||||
reset();
|
||||
@@ -418,12 +383,16 @@ namespace unnecessary_copy_tests
|
||||
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_STD_FORWARD_MOVE)
|
||||
|
||||
// No move should take place.
|
||||
// (since a is already in the container)
|
||||
reset();
|
||||
x.emplace(boost::move(a));
|
||||
x.emplace(std::move(a));
|
||||
COPY_COUNT(0); MOVE_COUNT(0);
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
// 2 arguments
|
||||
//
|
||||
@@ -453,7 +422,7 @@ namespace unnecessary_copy_tests
|
||||
boost::make_tuple(boost::ref(b.second)));
|
||||
COPY_COUNT(0); MOVE_COUNT(0);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
|
||||
#if !defined(BOOST_NO_0X_HDR_TUPLE) || defined(BOOST_HAS_TR1_TUPLE)
|
||||
|
||||
reset();
|
||||
x.emplace(boost::unordered::piecewise_construct,
|
||||
|
||||
Reference in New Issue
Block a user