mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-11 13:34:06 +00:00
Support node_handle
This commit is contained in:
parent
9c4c3a754a
commit
21a24d6cd7
261
doc/ref.php
261
doc/ref.php
@ -189,6 +189,20 @@ EOL;
|
||||
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
<para>See <classname>node_handle_<?php echo $map ? 'map' : 'set'; ?></classname> for details.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<?php if (!$equivalent_keys): ?>
|
||||
<typedef name="insert_return_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
Structure returned by inserting <code>node_type</code>.
|
||||
</description>
|
||||
</typedef>
|
||||
<?php endif; ?>
|
||||
<constructor>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
@ -876,6 +890,142 @@ EOL;
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<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>
|
||||
<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="extract">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes the element pointed to by <code>position</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element.</para>
|
||||
</returns>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="k">
|
||||
<paramtype>key_type const&</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes an element with key equivalent to <code>k</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element if found, otherwise an empty <code>node_type</code>.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>Only throws an exception if it is thrown by <code>hasher</code> or <code>key_equal</code>.</para>
|
||||
</throws>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type><?php echo $equivalent_keys ? 'iterator' : 'insert_return_type' ?></type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
<?php else: ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
|
||||
</para>
|
||||
<?php endif ?>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly inserted element.</para>
|
||||
<?php else: ?>
|
||||
<para>If <code>nh</code> was empty, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> equal to <code>end()</code> and
|
||||
<code>node</code> empty.</para>
|
||||
<para>Otherwise if there was already an element with an equivalent key, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> pointing to a matching element and
|
||||
<code>node</code> contains the node from <code>nh</code>.</para>
|
||||
<para>Otherwise if the insertion succeeded, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>true</code>,
|
||||
<code>position</code> pointing to the newly inserted element and
|
||||
<code>node</code> empty.</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="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
<?php else: ?>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent <?php echo $key_name; ?>.
|
||||
</para>
|
||||
<para>If there is already an element in the container with an equivalent <?php echo $key_name; ?>
|
||||
has no effect on <code>nh</code> (i.e. <code>nh</code> still contains the node.)</para>
|
||||
<?php endif ?>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<?php if ($equivalent_keys): ?>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly inserted element.</para>
|
||||
<?php else: ?>
|
||||
<para>If <code>nh</code> was empty returns <code>end()</code>.</para>
|
||||
<para>If there was already an element in the container with an equivalent <?php echo $key_name; ?>
|
||||
returns an iterator pointing to that.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly inserted element.</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="erase">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
@ -1416,6 +1566,115 @@ EOL;
|
||||
<?php
|
||||
}
|
||||
|
||||
function echo_node_handle_docs($map)
|
||||
{
|
||||
$type = $map ? 'map' : 'set';
|
||||
$name = 'node_handle_'.$type;
|
||||
$full_type = "{$name}<ImplementationDefined>";
|
||||
?>
|
||||
<namespace name="unordered">
|
||||
<class name="<?php echo $name ?>">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<purpose>
|
||||
<para>
|
||||
An object that owns a single element extracted from an
|
||||
<classname>unordered_<?php echo $type ?></classname> or an
|
||||
<classname>unordered_multi<?php echo $type ?></classname>, that
|
||||
can then be inserted into a compatible container type.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
The name and template parameters of this type is implementation
|
||||
defined, and should be obtained using the <code>node_type</code>
|
||||
member typedef from the appropriate container.
|
||||
</para>
|
||||
</note>
|
||||
</purpose>
|
||||
<?php if ($map): ?>
|
||||
<typedef name="key_type">
|
||||
<type>typename Container::key_type</type>
|
||||
</typedef>
|
||||
<typedef name="mapped_type">
|
||||
<type>typename Container::mapped_type</type>
|
||||
</typedef>
|
||||
<?php else: ?>
|
||||
<typedef name="value_type">
|
||||
<type>typename Container::value_type></type>
|
||||
</typedef>
|
||||
<?php endif ?>
|
||||
<typedef name="allocator_type">
|
||||
<type>typename Container::allocator_type></type>
|
||||
</typedef>
|
||||
<constructor specifiers="constexpr" cv="noexcept">
|
||||
</constructor>
|
||||
<destructor/>
|
||||
<constructor cv="noexcept">
|
||||
<parameter>
|
||||
<paramtype><?php echo $name; ?> &&</paramtype>
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="operator=">
|
||||
<parameter>
|
||||
<paramtype><?php echo $name; ?>&&</paramtype>
|
||||
</parameter>
|
||||
<type><?php echo $name; ?>&</type>
|
||||
</method>
|
||||
<?php if ($map): ?>
|
||||
<method name="key" cv="const">
|
||||
<type>key_type&</type>
|
||||
</method>
|
||||
<method name="mapped" cv="const">
|
||||
<type>mapped_type&</type>
|
||||
</method>
|
||||
<?php else: ?>
|
||||
<method name="value" cv="const">
|
||||
<type>value_type&</type>
|
||||
</method>
|
||||
<?php endif; ?>
|
||||
<method name="get_allocator" cv="const">
|
||||
<type>allocator_type</type>
|
||||
</method>
|
||||
<method name="operator bool" specifiers="explicit" cv="const noexcept">
|
||||
</method>
|
||||
<method name="empty" cv="const noexcept">
|
||||
<type>bool</type>
|
||||
</method>
|
||||
<method name="swap" cv="noexcept(ator_traits::propagate_on_container_swap::value)">
|
||||
<parameter>
|
||||
<paramtype><?php echo $name; ?>&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<notes>
|
||||
<para>
|
||||
In C++17 is also <code>noexcept</code> if <code>ator_traits::is_always_equal::value</code> is true.
|
||||
But we don't support that trait yet.
|
||||
</para>
|
||||
</notes>
|
||||
</method>
|
||||
<free-function-group name="swap" cv="noexcept(noexcept(x.swap(y)))">
|
||||
<function name="swap">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<parameter name="x">
|
||||
<paramtype><?php echo $full_type; ?>&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="y">
|
||||
<paramtype><?php echo $full_type; ?>&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<effects>
|
||||
<para><code>x.swap(y)</code></para>
|
||||
</effects>
|
||||
</function>
|
||||
</free-function-group>
|
||||
</class>
|
||||
</namespace>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<!--
|
||||
Copyright Daniel James 2006-2009
|
||||
@ -1427,6 +1686,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<?php
|
||||
echo_unordered_docs(false, false);
|
||||
echo_unordered_docs(false, true);
|
||||
echo_node_handle_docs(false);
|
||||
?>
|
||||
</namespace>
|
||||
</header>
|
||||
@ -1435,6 +1695,7 @@ echo_unordered_docs(false, true);
|
||||
<?php
|
||||
echo_unordered_docs(true, false);
|
||||
echo_unordered_docs(true, true);
|
||||
echo_node_handle_docs(true);
|
||||
?>
|
||||
</namespace>
|
||||
</header>
|
||||
|
640
doc/ref.xml
640
doc/ref.xml
@ -130,6 +130,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
<para>See <classname>node_handle_set</classname> for details.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="insert_return_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
Structure returned by inserting <code>node_type</code>.
|
||||
</description>
|
||||
</typedef>
|
||||
<constructor>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
@ -769,6 +781,122 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<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>
|
||||
<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="extract">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes the element pointed to by <code>position</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element.</para>
|
||||
</returns>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="k">
|
||||
<paramtype>key_type const&</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes an element with key equivalent to <code>k</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element if found, otherwise an empty <code>node_type</code>.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>Only throws an exception if it is thrown by <code>hasher</code> or <code>key_equal</code>.</para>
|
||||
</throws>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>insert_return_type</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent value.
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> equal to <code>end()</code> and
|
||||
<code>node</code> empty.</para>
|
||||
<para>Otherwise if there was already an element with an equivalent key, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> pointing to a matching element and
|
||||
<code>node</code> contains the node from <code>nh</code>.</para>
|
||||
<para>Otherwise if the insertion succeeded, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>true</code>,
|
||||
<code>position</code> pointing to the newly inserted element and
|
||||
<code>node</code> empty.</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="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent value.
|
||||
</para>
|
||||
<para>If there is already an element in the container with an equivalent value has no effect on <code>nh</code> (i.e. <code>nh</code> still contains the node.)</para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty returns <code>end()</code>.</para>
|
||||
<para>If there was already an element in the container with an equivalent value returns an iterator pointing to that.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly 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="erase">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
@ -1383,6 +1511,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
<para>See <classname>node_handle_set</classname> for details.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<constructor>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
@ -2017,6 +2151,106 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<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>
|
||||
<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="extract">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes the element pointed to by <code>position</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element.</para>
|
||||
</returns>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="k">
|
||||
<paramtype>key_type const&</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes an element with key equivalent to <code>k</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element if found, otherwise an empty <code>node_type</code>.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>Only throws an exception if it is thrown by <code>hasher</code> or <code>key_equal</code>.</para>
|
||||
</throws>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly 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="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly 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="erase">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
@ -2506,6 +2740,88 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
</function>
|
||||
</free-function-group>
|
||||
</class>
|
||||
<namespace name="unordered">
|
||||
<class name="node_handle_set">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<purpose>
|
||||
<para>
|
||||
An object that owns a single element extracted from an
|
||||
<classname>unordered_set</classname> or an
|
||||
<classname>unordered_multiset</classname>, that
|
||||
can then be inserted into a compatible container type.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
The name and template parameters of this type is implementation
|
||||
defined, and should be obtained using the <code>node_type</code>
|
||||
member typedef from the appropriate container.
|
||||
</para>
|
||||
</note>
|
||||
</purpose>
|
||||
<typedef name="value_type">
|
||||
<type>typename Container::value_type></type>
|
||||
</typedef>
|
||||
<typedef name="allocator_type">
|
||||
<type>typename Container::allocator_type></type>
|
||||
</typedef>
|
||||
<constructor specifiers="constexpr" cv="noexcept">
|
||||
</constructor>
|
||||
<destructor/>
|
||||
<constructor cv="noexcept">
|
||||
<parameter>
|
||||
<paramtype>node_handle_set &&</paramtype>
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="operator=">
|
||||
<parameter>
|
||||
<paramtype>node_handle_set&&</paramtype>
|
||||
</parameter>
|
||||
<type>node_handle_set&</type>
|
||||
</method>
|
||||
<method name="value" cv="const">
|
||||
<type>value_type&</type>
|
||||
</method>
|
||||
<method name="get_allocator" cv="const">
|
||||
<type>allocator_type</type>
|
||||
</method>
|
||||
<method name="operator bool" specifiers="explicit" cv="const noexcept">
|
||||
</method>
|
||||
<method name="empty" cv="const noexcept">
|
||||
<type>bool</type>
|
||||
</method>
|
||||
<method name="swap" cv="noexcept(ator_traits::propagate_on_container_swap::value)">
|
||||
<parameter>
|
||||
<paramtype>node_handle_set&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<notes>
|
||||
<para>
|
||||
In C++17 is also <code>noexcept</code> if <code>ator_traits::is_always_equal::value</code> is true.
|
||||
But we don't support that trait yet.
|
||||
</para>
|
||||
</notes>
|
||||
</method>
|
||||
<free-function-group name="swap" cv="noexcept(noexcept(x.swap(y)))">
|
||||
<function name="swap">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<parameter name="x">
|
||||
<paramtype>node_handle_set<ImplementationDefined>&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="y">
|
||||
<paramtype>node_handle_set<ImplementationDefined>&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<effects>
|
||||
<para><code>x.swap(y)</code></para>
|
||||
</effects>
|
||||
</function>
|
||||
</free-function-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</namespace>
|
||||
</header>
|
||||
<header name="boost/unordered_map.hpp">
|
||||
@ -2645,6 +2961,18 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
<para>See <classname>node_handle_map</classname> for details.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="insert_return_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
Structure returned by inserting <code>node_type</code>.
|
||||
</description>
|
||||
</typedef>
|
||||
<constructor>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
@ -2661,7 +2989,6 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<constructor specifiers="explicit">
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
<default><emphasis>implementation-defined</emphasis></default>
|
||||
</parameter>
|
||||
<parameter name="hf">
|
||||
<paramtype>hasher const&</paramtype>
|
||||
@ -2809,6 +3136,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
</parameter>
|
||||
<parameter name="n">
|
||||
<paramtype>size_type</paramtype>
|
||||
<default><emphasis>implementation-defined</emphasis></default>
|
||||
</parameter>
|
||||
<parameter name="hf">
|
||||
<paramtype>hasher const&</paramtype>
|
||||
@ -3284,6 +3612,122 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<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>
|
||||
<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="extract">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes the element pointed to by <code>position</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element.</para>
|
||||
</returns>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="k">
|
||||
<paramtype>key_type const&</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes an element with key equivalent to <code>k</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element if found, otherwise an empty <code>node_type</code>.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>Only throws an exception if it is thrown by <code>hasher</code> or <code>key_equal</code>.</para>
|
||||
</throws>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>insert_return_type</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent key.
|
||||
</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> equal to <code>end()</code> and
|
||||
<code>node</code> empty.</para>
|
||||
<para>Otherwise if there was already an element with an equivalent key, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>false</code>,
|
||||
<code>position</code> pointing to a matching element and
|
||||
<code>node</code> contains the node from <code>nh</code>.</para>
|
||||
<para>Otherwise if the insertion succeeded, returns an <code>insert_return_type</code> with:
|
||||
<code>inserted</code> equal to <code>true</code>,
|
||||
<code>position</code> pointing to the newly inserted element and
|
||||
<code>node</code> empty.</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="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code>
|
||||
if and only if there is no element in the container with an equivalent key.
|
||||
</para>
|
||||
<para>If there is already an element in the container with an equivalent key has no effect on <code>nh</code> (i.e. <code>nh</code> still contains the node.)</para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty returns <code>end()</code>.</para>
|
||||
<para>If there was already an element in the container with an equivalent key returns an iterator pointing to that.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly 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="erase">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
@ -3945,6 +4389,12 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>A const_local_iterator object can be used to iterate through a single bucket.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<typedef name="node_type">
|
||||
<type><emphasis>implementation-defined</emphasis></type>
|
||||
<description>
|
||||
<para>See <classname>node_handle_map</classname> for details.</para>
|
||||
</description>
|
||||
</typedef>
|
||||
<constructor>
|
||||
<postconditions>
|
||||
<code><methodname>size</methodname>() == 0</code>
|
||||
@ -4579,6 +5029,106 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
<para>Pointers and references to elements are never invalidated.</para>
|
||||
</notes>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="il">
|
||||
<paramtype>initializer_list<value_type></paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<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>
|
||||
<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="extract">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes the element pointed to by <code>position</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element.</para>
|
||||
</returns>
|
||||
</method>
|
||||
<method name="extract">
|
||||
<parameter name="k">
|
||||
<paramtype>key_type const&</paramtype>
|
||||
</parameter>
|
||||
<type>node_type</type>
|
||||
<description>
|
||||
<para>Removes an element with key equivalent to <code>k</code>.</para>
|
||||
</description>
|
||||
<returns>
|
||||
<para>A <code>node_type</code> owning the element if found, otherwise an empty <code>node_type</code>.</para>
|
||||
</returns>
|
||||
<throws>
|
||||
<para>Only throws an exception if it is thrown by <code>hasher</code> or <code>key_equal</code>.</para>
|
||||
</throws>
|
||||
</method>
|
||||
<method name="insert">
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly 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="hint">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
</parameter>
|
||||
<parameter name="nh">
|
||||
<paramtype>node_type&&</paramtype>
|
||||
</parameter>
|
||||
<type>iterator</type>
|
||||
<description>
|
||||
<para>If <code>nh</code> is empty, has no affect.</para>
|
||||
<para>Otherwise inserts the element owned by <code>nh</code></para>
|
||||
<para>hint is a suggestion to where the element should be inserted.</para>
|
||||
</description>
|
||||
<requires>
|
||||
<para><code>nh</code> is empty or <code>nh.get_allocator()</code> is equal to the container's allocator.</para>
|
||||
</requires>
|
||||
<returns>
|
||||
<para>If <code>nh</code> was empty, returns <code>end()</code>.</para>
|
||||
<para>Otherwise returns an iterator pointing to the newly 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="erase">
|
||||
<parameter name="position">
|
||||
<paramtype>const_iterator</paramtype>
|
||||
@ -5074,6 +5624,94 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
</function>
|
||||
</free-function-group>
|
||||
</class>
|
||||
<namespace name="unordered">
|
||||
<class name="node_handle_map">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<purpose>
|
||||
<para>
|
||||
An object that owns a single element extracted from an
|
||||
<classname>unordered_map</classname> or an
|
||||
<classname>unordered_multimap</classname>, that
|
||||
can then be inserted into a compatible container type.
|
||||
</para>
|
||||
<note>
|
||||
<para>
|
||||
The name and template parameters of this type is implementation
|
||||
defined, and should be obtained using the <code>node_type</code>
|
||||
member typedef from the appropriate container.
|
||||
</para>
|
||||
</note>
|
||||
</purpose>
|
||||
<typedef name="key_type">
|
||||
<type>typename Container::key_type</type>
|
||||
</typedef>
|
||||
<typedef name="mapped_type">
|
||||
<type>typename Container::mapped_type</type>
|
||||
</typedef>
|
||||
<typedef name="allocator_type">
|
||||
<type>typename Container::allocator_type></type>
|
||||
</typedef>
|
||||
<constructor specifiers="constexpr" cv="noexcept">
|
||||
</constructor>
|
||||
<destructor/>
|
||||
<constructor cv="noexcept">
|
||||
<parameter>
|
||||
<paramtype>node_handle_map &&</paramtype>
|
||||
</parameter>
|
||||
</constructor>
|
||||
<method name="operator=">
|
||||
<parameter>
|
||||
<paramtype>node_handle_map&&</paramtype>
|
||||
</parameter>
|
||||
<type>node_handle_map&</type>
|
||||
</method>
|
||||
<method name="key" cv="const">
|
||||
<type>key_type&</type>
|
||||
</method>
|
||||
<method name="mapped" cv="const">
|
||||
<type>mapped_type&</type>
|
||||
</method>
|
||||
<method name="get_allocator" cv="const">
|
||||
<type>allocator_type</type>
|
||||
</method>
|
||||
<method name="operator bool" specifiers="explicit" cv="const noexcept">
|
||||
</method>
|
||||
<method name="empty" cv="const noexcept">
|
||||
<type>bool</type>
|
||||
</method>
|
||||
<method name="swap" cv="noexcept(ator_traits::propagate_on_container_swap::value)">
|
||||
<parameter>
|
||||
<paramtype>node_handle_map&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<notes>
|
||||
<para>
|
||||
In C++17 is also <code>noexcept</code> if <code>ator_traits::is_always_equal::value</code> is true.
|
||||
But we don't support that trait yet.
|
||||
</para>
|
||||
</notes>
|
||||
</method>
|
||||
<free-function-group name="swap" cv="noexcept(noexcept(x.swap(y)))">
|
||||
<function name="swap">
|
||||
<template pack="true">
|
||||
<template-type-parameter name="ImplementationDefined"/>
|
||||
</template>
|
||||
<parameter name="x">
|
||||
<paramtype>node_handle_map<ImplementationDefined>&</paramtype>
|
||||
</parameter>
|
||||
<parameter name="y">
|
||||
<paramtype>node_handle_map<ImplementationDefined>&</paramtype>
|
||||
</parameter>
|
||||
<type>void</type>
|
||||
<effects>
|
||||
<para><code>x.swap(y)</code></para>
|
||||
</effects>
|
||||
</function>
|
||||
</free-function-group>
|
||||
</class>
|
||||
</namespace>
|
||||
</namespace>
|
||||
</header>
|
||||
</library-reference>
|
||||
|
@ -3800,6 +3800,46 @@ struct table_impl : boost::unordered::detail::table<Types>
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeType, typename InsertReturnType>
|
||||
void move_insert_node_type(NodeType& np, InsertReturnType& result)
|
||||
{
|
||||
if (np) {
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
|
||||
if (pos) {
|
||||
result.node = boost::move(np);
|
||||
result.position = iterator(pos);
|
||||
} else {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result.position = iterator(this->add_node(np.ptr_, key_hash));
|
||||
result.inserted = true;
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeType>
|
||||
iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np)
|
||||
{
|
||||
if (!np) {
|
||||
return iterator();
|
||||
}
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
|
||||
return iterator(hint.node_);
|
||||
}
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
if (!pos) {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
pos = this->add_node(np.ptr_, key_hash);
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
return iterator(pos);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
//
|
||||
@ -3876,39 +3916,87 @@ struct table_impl : boost::unordered::detail::table<Types>
|
||||
} while (++i != j);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Extract
|
||||
|
||||
inline node_pointer extract_by_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_) {
|
||||
return node_pointer();
|
||||
}
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev) {
|
||||
return node_pointer();
|
||||
}
|
||||
node_pointer n = next_node(prev);
|
||||
prev->next_ = n->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
n->next_ = link_pointer();
|
||||
return n;
|
||||
}
|
||||
|
||||
inline node_pointer extract_by_iterator(c_iterator i)
|
||||
{
|
||||
node_pointer n = i.node_;
|
||||
BOOST_ASSERT(n);
|
||||
std::size_t key_hash = n->hash_;
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
while (prev->next_ != n) {
|
||||
prev = prev->next_;
|
||||
}
|
||||
prev->next_ = n->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
n->next_ = link_pointer();
|
||||
return n;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
link_pointer find_previous_node(
|
||||
const_key_type& k, std::size_t key_hash, std::size_t bucket_index)
|
||||
{
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
if (!prev) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_) {
|
||||
return link_pointer();
|
||||
}
|
||||
std::size_t node_hash = next_node(prev)->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index) {
|
||||
return link_pointer();
|
||||
}
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(next_node(prev)->value()))) {
|
||||
return prev;
|
||||
}
|
||||
prev = prev->next_;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t erase_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_)
|
||||
return 0;
|
||||
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev)
|
||||
return 0;
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_)
|
||||
return 0;
|
||||
std::size_t node_hash = next_node(prev)->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return 0;
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(next_node(prev)->value())))
|
||||
break;
|
||||
prev = prev->next_;
|
||||
}
|
||||
|
||||
link_pointer end = next_node(prev)->next_;
|
||||
|
||||
std::size_t deleted_count = this->delete_nodes(prev, end);
|
||||
this->delete_nodes(prev, end);
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
return deleted_count;
|
||||
return 1;
|
||||
}
|
||||
|
||||
iterator erase(c_iterator r)
|
||||
@ -4459,6 +4547,45 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
this->add_node(a.release(), key_hash, position);
|
||||
}
|
||||
|
||||
template <typename NodeType> iterator move_insert_node_type(NodeType& np)
|
||||
{
|
||||
iterator result;
|
||||
|
||||
if (np) {
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result = iterator(this->add_node(np.ptr_, key_hash, pos));
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <typename NodeType>
|
||||
iterator move_insert_node_type_with_hint(c_iterator hint, NodeType& np)
|
||||
{
|
||||
iterator result;
|
||||
|
||||
if (np) {
|
||||
const_key_type& k = this->get_key(np.ptr_->value());
|
||||
|
||||
if (hint.node_ && this->key_eq()(k, this->get_key(*hint))) {
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result = iterator(this->add_using_hint(np.ptr_, hint.node_));
|
||||
} else {
|
||||
std::size_t key_hash = this->hash(k);
|
||||
node_pointer pos = this->find_node(key_hash, k);
|
||||
this->reserve_for_insert(this->size_ + 1);
|
||||
result = iterator(this->add_node(np.ptr_, key_hash, pos));
|
||||
}
|
||||
np.ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Insert range methods
|
||||
|
||||
@ -4499,11 +4626,95 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Extract
|
||||
|
||||
inline node_pointer extract_by_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_) {
|
||||
return node_pointer();
|
||||
}
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev) {
|
||||
return node_pointer();
|
||||
}
|
||||
node_pointer n = next_node(prev);
|
||||
|
||||
if (n->group_prev_ != n) {
|
||||
node_pointer next = next_node(n);
|
||||
next->group_prev_ = n->group_prev_;
|
||||
n->group_prev_ = n;
|
||||
}
|
||||
|
||||
prev->next_ = n->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
n->next_ = link_pointer();
|
||||
|
||||
return n;
|
||||
}
|
||||
|
||||
inline node_pointer extract_by_iterator(c_iterator n)
|
||||
{
|
||||
node_pointer i = n.node_;
|
||||
BOOST_ASSERT(i);
|
||||
node_pointer j(next_node(i));
|
||||
std::size_t bucket_index = this->hash_to_bucket(i->hash_);
|
||||
// Split the groups containing 'i' and 'j'.
|
||||
// And get the pointer to the node before i while
|
||||
// we're at it.
|
||||
link_pointer prev = split_groups(i, j);
|
||||
|
||||
// If we don't have a 'prev' it means that i is at the
|
||||
// beginning of a block, so search through the blocks in the
|
||||
// same bucket.
|
||||
if (!prev) {
|
||||
prev = this->get_previous_start(bucket_index);
|
||||
while (prev->next_ != i) {
|
||||
prev = next_node(prev)->group_prev_;
|
||||
}
|
||||
}
|
||||
|
||||
prev->next_ = i->next_;
|
||||
--this->size_;
|
||||
this->fix_bucket(bucket_index, prev);
|
||||
i->next_ = link_pointer();
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////
|
||||
// Erase
|
||||
//
|
||||
// no throw
|
||||
|
||||
link_pointer find_previous_node(
|
||||
const_key_type& k, std::size_t key_hash, std::size_t bucket_index)
|
||||
{
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
if (!prev) {
|
||||
return prev;
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_) {
|
||||
return link_pointer();
|
||||
}
|
||||
node_pointer first_node = next_node(prev);
|
||||
std::size_t node_hash = first_node->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index) {
|
||||
return link_pointer();
|
||||
}
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(first_node->value()))) {
|
||||
return prev;
|
||||
}
|
||||
prev = first_node->group_prev_;
|
||||
}
|
||||
}
|
||||
|
||||
std::size_t erase_key(const_key_type& k)
|
||||
{
|
||||
if (!this->size_)
|
||||
@ -4511,25 +4722,11 @@ struct grouped_table_impl : boost::unordered::detail::table<Types>
|
||||
|
||||
std::size_t key_hash = this->hash(k);
|
||||
std::size_t bucket_index = this->hash_to_bucket(key_hash);
|
||||
link_pointer prev = this->get_previous_start(bucket_index);
|
||||
link_pointer prev = find_previous_node(k, key_hash, bucket_index);
|
||||
if (!prev)
|
||||
return 0;
|
||||
|
||||
node_pointer first_node;
|
||||
|
||||
for (;;) {
|
||||
if (!prev->next_)
|
||||
return 0;
|
||||
first_node = next_node(prev);
|
||||
std::size_t node_hash = first_node->hash_;
|
||||
if (this->hash_to_bucket(node_hash) != bucket_index)
|
||||
return 0;
|
||||
if (node_hash == key_hash &&
|
||||
this->key_eq()(k, this->get_key(first_node->value())))
|
||||
break;
|
||||
prev = first_node->group_prev_;
|
||||
}
|
||||
|
||||
node_pointer first_node = next_node(prev);
|
||||
link_pointer end = first_node->group_prev_->next_;
|
||||
|
||||
std::size_t deleted_count = this->delete_nodes(prev, end);
|
||||
|
@ -39,6 +39,10 @@ template <typename A, typename K, typename M, typename H, typename P> struct map
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_map<node, K, M, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename A, typename K, typename M, typename H, typename P>
|
||||
@ -72,6 +76,25 @@ struct multimap
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_map<node, K, M, A> node_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_map
|
||||
{
|
||||
typedef boost::unordered_map<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename K, typename M, typename H, typename P, typename A>
|
||||
class instantiate_multimap
|
||||
{
|
||||
typedef boost::unordered_multimap<K, M, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,10 @@ template <typename A, typename T, typename H, typename P> struct set
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
typedef boost::unordered::insert_return_type_set<node, T, A>
|
||||
insert_return_type;
|
||||
};
|
||||
|
||||
template <typename A, typename T, typename H, typename P> struct multiset
|
||||
@ -71,6 +75,24 @@ template <typename A, typename T, typename H, typename P> struct multiset
|
||||
l_iterator;
|
||||
typedef boost::unordered::iterator_detail::cl_iterator<node, policy>
|
||||
cl_iterator;
|
||||
|
||||
typedef boost::unordered::node_handle_set<node, T, A> node_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A> class instantiate_set
|
||||
{
|
||||
typedef boost::unordered_set<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
typename container::insert_return_type insert_return_type;
|
||||
};
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_multiset
|
||||
{
|
||||
typedef boost::unordered_multiset<T, H, P, A> container;
|
||||
container x;
|
||||
typename container::node_type node_type;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -14,10 +14,10 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/unordered/detail/map.hpp>
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
#include <initializer_list>
|
||||
@ -67,6 +67,8 @@ template <class K, class T, class H, class P, class A> class unordered_map
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
typedef typename types::insert_return_type insert_return_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@ -206,6 +208,19 @@ template <class K, class T, class H, class P, class A> class unordered_map
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@ -572,6 +587,27 @@ template <class K, class T, class H, class P, class A> class unordered_map
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
insert_return_type insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
insert_return_type result;
|
||||
table_.move_insert_node_type(np, result);
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
insert_return_type insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@ -703,6 +739,7 @@ template <class K, class T, class H, class P, class A> class unordered_multimap
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@ -843,6 +880,19 @@ template <class K, class T, class H, class P, class A> class unordered_multimap
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@ -977,6 +1027,25 @@ template <class K, class T, class H, class P, class A> class unordered_multimap
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
iterator insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type(np);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
iterator insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@ -1816,6 +1885,199 @@ inline void swap(unordered_multimap<K, T, H, P, A>& m1,
|
||||
m1.swap(m2);
|
||||
}
|
||||
|
||||
template <typename N, class K, class T, class A> class node_handle_map
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_map)
|
||||
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::table_impl;
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::grouped_table_impl;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A,
|
||||
std::pair<K const, T> >::type value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
typedef N node;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
|
||||
public:
|
||||
typedef K key_type;
|
||||
typedef T mapped_type;
|
||||
typedef A allocator_type;
|
||||
|
||||
private:
|
||||
node_pointer ptr_;
|
||||
bool has_alloc_;
|
||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
||||
|
||||
public:
|
||||
BOOST_CONSTEXPR node_handle_map() BOOST_NOEXCEPT : ptr_(), has_alloc_(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*BOOST_CONSTEXPR */ node_handle_map(
|
||||
node_pointer ptr, allocator_type const& a)
|
||||
: ptr_(ptr), has_alloc_(false)
|
||||
{
|
||||
if (ptr_) {
|
||||
new ((void*)&alloc_) value_allocator(a);
|
||||
has_alloc_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
~node_handle_map()
|
||||
{
|
||||
if (has_alloc_ && ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
}
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_map(BOOST_RV_REF(node_handle_map) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
has_alloc_(false)
|
||||
{
|
||||
if (n.has_alloc_) {
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
has_alloc_ = true;
|
||||
n.ptr_ = node_pointer();
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_map& operator=(BOOST_RV_REF(node_handle_map) n)
|
||||
{
|
||||
BOOST_ASSERT(!has_alloc_ ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
||||
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = false;
|
||||
}
|
||||
|
||||
if (!has_alloc_ && n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
|
||||
ptr_ = n.ptr_;
|
||||
n.ptr_ = node_pointer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
key_type& key() const { return const_cast<key_type&>(ptr_->value().first); }
|
||||
|
||||
mapped_type& mapped() const { return ptr_->value().second; }
|
||||
|
||||
allocator_type get_allocator() const { return alloc_.value(); }
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
void swap(node_handle_map& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value
|
||||
/* || value_allocator_traits::is_always_equal::value */)
|
||||
{
|
||||
if (!has_alloc_) {
|
||||
if (n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
} else if (!n.has_alloc_) {
|
||||
n.move_allocator(*this);
|
||||
} else {
|
||||
swap_impl(n, boost::unordered::detail::integral_constant<bool,
|
||||
value_allocator_traits::
|
||||
propagate_on_container_swap::value>());
|
||||
}
|
||||
boost::swap(ptr_, n.ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
void move_allocator(node_handle_map& n)
|
||||
{
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = true;
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
|
||||
void swap_impl(node_handle_map&, boost::unordered::detail::false_type) {}
|
||||
|
||||
void swap_impl(node_handle_map& n, boost::unordered::detail::true_type)
|
||||
{
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
};
|
||||
|
||||
template <class N, class K, class T, class A>
|
||||
void swap(node_handle_map<N, K, T, A>& x, node_handle_map<N, K, T, A>& y)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(x.swap(y)))
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map
|
||||
{
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_map)
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A,
|
||||
std::pair<K const, T> >::type value_allocator;
|
||||
typedef N node_;
|
||||
|
||||
public:
|
||||
bool inserted;
|
||||
boost::unordered::iterator_detail::iterator<node_> position;
|
||||
boost::unordered::node_handle_map<N, K, T, A> node;
|
||||
|
||||
insert_return_type_map() : inserted(false), position(), node() {}
|
||||
|
||||
insert_return_type_map(BOOST_RV_REF(insert_return_type_map)
|
||||
x) BOOST_NOEXCEPT : inserted(x.inserted),
|
||||
position(x.position),
|
||||
node(boost::move(x.node))
|
||||
{
|
||||
}
|
||||
|
||||
insert_return_type_map& operator=(BOOST_RV_REF(insert_return_type_map) x)
|
||||
{
|
||||
inserted = x.inserted;
|
||||
position = x.position;
|
||||
node = boost::move(x.node);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <class N, class K, class T, class A>
|
||||
void swap(insert_return_type_map<N, K, T, A>& x,
|
||||
insert_return_type_map<N, K, T, A>& y)
|
||||
{
|
||||
boost::swap(x.node, y.node);
|
||||
boost::swap(x.inserted, y.inserted);
|
||||
boost::swap(x.position, y.position);
|
||||
}
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
|
@ -46,6 +46,9 @@ inline bool operator!=(unordered_multimap<K, T, H, P, A> const&,
|
||||
template <class K, class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_multimap<K, T, H, P, A>&, unordered_multimap<K, T, H, P, A>&);
|
||||
|
||||
template <class N, class K, class T, class A> class node_handle_map;
|
||||
template <class N, class K, class T, class A> struct insert_return_type_map;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_map;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/core/explicit_operator_bool.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/move/move.hpp>
|
||||
#include <boost/unordered/detail/set.hpp>
|
||||
@ -64,6 +65,8 @@ template <class T, class H, class P, class A> class unordered_set
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
typedef typename types::insert_return_type insert_return_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@ -203,6 +206,19 @@ template <class T, class H, class P, class A> class unordered_set
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@ -345,6 +361,27 @@ template <class T, class H, class P, class A> class unordered_set
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
insert_return_type insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
insert_return_type result;
|
||||
table_.move_insert_node_type(np, result);
|
||||
return boost::move(result);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
insert_return_type insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@ -464,6 +501,7 @@ template <class T, class H, class P, class A> class unordered_multiset
|
||||
typedef typename table::l_iterator local_iterator;
|
||||
typedef typename table::c_iterator const_iterator;
|
||||
typedef typename table::iterator iterator;
|
||||
typedef typename types::node_type node_type;
|
||||
|
||||
private:
|
||||
table table_;
|
||||
@ -604,6 +642,19 @@ template <class T, class H, class P, class A> class unordered_multiset
|
||||
|
||||
const_iterator cend() const BOOST_NOEXCEPT { return const_iterator(); }
|
||||
|
||||
// extract
|
||||
|
||||
node_type extract(const_iterator position)
|
||||
{
|
||||
return node_type(
|
||||
table_.extract_by_iterator(position), table_.node_alloc());
|
||||
}
|
||||
|
||||
node_type extract(const key_type& k)
|
||||
{
|
||||
return node_type(table_.extract_by_key(k), table_.node_alloc());
|
||||
}
|
||||
|
||||
// emplace
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
|
||||
@ -738,6 +789,25 @@ template <class T, class H, class P, class A> class unordered_multiset
|
||||
void insert(std::initializer_list<value_type>);
|
||||
#endif
|
||||
|
||||
iterator insert(BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type(np);
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, BOOST_RV_REF(node_type) np)
|
||||
{
|
||||
return table_.move_insert_node_type_with_hint(hint, np);
|
||||
}
|
||||
|
||||
#if defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
private:
|
||||
// Note: Use r-value node_type to insert.
|
||||
iterator insert(node_type&);
|
||||
iterator insert(const_iterator, node_type& np);
|
||||
|
||||
public:
|
||||
#endif
|
||||
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
iterator erase(const_iterator, const_iterator);
|
||||
@ -1494,6 +1564,197 @@ inline void swap(
|
||||
#endif
|
||||
m1.swap(m2);
|
||||
}
|
||||
|
||||
template <typename N, typename T, typename A> class node_handle_set
|
||||
{
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle_set)
|
||||
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::table_impl;
|
||||
template <typename Types>
|
||||
friend struct ::boost::unordered::detail::grouped_table_impl;
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
|
||||
value_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<value_allocator>
|
||||
value_allocator_traits;
|
||||
typedef N node;
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, node>::type
|
||||
node_allocator;
|
||||
typedef boost::unordered::detail::allocator_traits<node_allocator>
|
||||
node_allocator_traits;
|
||||
typedef typename node_allocator_traits::pointer node_pointer;
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef A allocator_type;
|
||||
|
||||
private:
|
||||
node_pointer ptr_;
|
||||
bool has_alloc_;
|
||||
boost::unordered::detail::value_base<value_allocator> alloc_;
|
||||
|
||||
public:
|
||||
BOOST_CONSTEXPR node_handle_set() BOOST_NOEXCEPT : ptr_(), has_alloc_(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*BOOST_CONSTEXPR */ node_handle_set(
|
||||
node_pointer ptr, allocator_type const& a)
|
||||
: ptr_(ptr), has_alloc_(false)
|
||||
{
|
||||
if (ptr_) {
|
||||
new ((void*)&alloc_) value_allocator(a);
|
||||
has_alloc_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
~node_handle_set()
|
||||
{
|
||||
if (has_alloc_ && ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
}
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_set(BOOST_RV_REF(node_handle_set) n) BOOST_NOEXCEPT
|
||||
: ptr_(n.ptr_),
|
||||
has_alloc_(false)
|
||||
{
|
||||
if (n.has_alloc_) {
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
has_alloc_ = true;
|
||||
n.ptr_ = node_pointer();
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_set& operator=(BOOST_RV_REF(node_handle_set) n)
|
||||
{
|
||||
BOOST_ASSERT(!has_alloc_ ||
|
||||
value_allocator_traits::
|
||||
propagate_on_container_move_assignment::value ||
|
||||
(n.has_alloc_ && alloc_.value() == n.alloc_.value()));
|
||||
|
||||
if (ptr_) {
|
||||
node_allocator node_alloc(alloc_.value());
|
||||
boost::unordered::detail::node_tmp<node_allocator> tmp(
|
||||
ptr_, node_alloc);
|
||||
ptr_ = node_pointer();
|
||||
}
|
||||
|
||||
if (has_alloc_) {
|
||||
alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = false;
|
||||
}
|
||||
|
||||
if (!has_alloc_ && n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
|
||||
ptr_ = n.ptr_;
|
||||
n.ptr_ = node_pointer();
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
value_type& value() const { return ptr_->value(); }
|
||||
|
||||
allocator_type get_allocator() const { return alloc_.value(); }
|
||||
|
||||
BOOST_EXPLICIT_OPERATOR_BOOL_NOEXCEPT()
|
||||
|
||||
bool operator!() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
bool empty() const BOOST_NOEXCEPT { return ptr_ ? 0 : 1; }
|
||||
|
||||
void swap(node_handle_set& n) BOOST_NOEXCEPT_IF(
|
||||
value_allocator_traits::propagate_on_container_swap::value
|
||||
/* || value_allocator_traits::is_always_equal::value */)
|
||||
{
|
||||
if (!has_alloc_) {
|
||||
if (n.has_alloc_) {
|
||||
move_allocator(n);
|
||||
}
|
||||
} else if (!n.has_alloc_) {
|
||||
n.move_allocator(*this);
|
||||
} else {
|
||||
swap_impl(n, boost::unordered::detail::integral_constant<bool,
|
||||
value_allocator_traits::
|
||||
propagate_on_container_swap::value>());
|
||||
}
|
||||
boost::swap(ptr_, n.ptr_);
|
||||
}
|
||||
|
||||
private:
|
||||
void move_allocator(node_handle_set& n)
|
||||
{
|
||||
new ((void*)&alloc_) value_allocator(boost::move(n.alloc_.value()));
|
||||
n.alloc_.value_ptr()->~value_allocator();
|
||||
has_alloc_ = true;
|
||||
n.has_alloc_ = false;
|
||||
}
|
||||
|
||||
void swap_impl(node_handle_set&, boost::unordered::detail::false_type) {}
|
||||
|
||||
void swap_impl(node_handle_set& n, boost::unordered::detail::true_type)
|
||||
{
|
||||
boost::swap(alloc_, n.alloc_);
|
||||
}
|
||||
};
|
||||
|
||||
template <typename N, typename T, typename A>
|
||||
void swap(node_handle_set<N, T, A>& x, node_handle_set<N, T, A>& y)
|
||||
BOOST_NOEXCEPT_IF(BOOST_NOEXCEPT_EXPR(x.swap(y)))
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <typename N, typename T, typename A> struct insert_return_type_set
|
||||
{
|
||||
private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type_set)
|
||||
|
||||
typedef typename boost::unordered::detail::rebind_wrap<A, T>::type
|
||||
value_allocator;
|
||||
typedef N node_;
|
||||
|
||||
public:
|
||||
bool inserted;
|
||||
boost::unordered::iterator_detail::c_iterator<node_> position;
|
||||
boost::unordered::node_handle_set<N, T, A> node;
|
||||
|
||||
insert_return_type_set() : inserted(false), position(), node() {}
|
||||
|
||||
insert_return_type_set(BOOST_RV_REF(insert_return_type_set)
|
||||
x) BOOST_NOEXCEPT : inserted(x.inserted),
|
||||
position(x.position),
|
||||
node(boost::move(x.node))
|
||||
{
|
||||
}
|
||||
|
||||
insert_return_type_set& operator=(BOOST_RV_REF(insert_return_type_set) x)
|
||||
{
|
||||
inserted = x.inserted;
|
||||
position = x.position;
|
||||
node = boost::move(x.node);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename N, typename T, typename A>
|
||||
void swap(
|
||||
insert_return_type_set<N, T, A>& x, insert_return_type_set<N, T, A>& y)
|
||||
{
|
||||
boost::swap(x.node, y.node);
|
||||
boost::swap(x.inserted, y.inserted);
|
||||
boost::swap(x.position, y.position);
|
||||
}
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
|
@ -44,6 +44,9 @@ inline bool operator!=(unordered_multiset<T, H, P, A> const&,
|
||||
template <class T, class H, class P, class A>
|
||||
inline void swap(
|
||||
unordered_multiset<T, H, P, A>& m1, unordered_multiset<T, H, P, A>& m2);
|
||||
|
||||
template <class N, class T, class A> class node_handle_set;
|
||||
template <class N, class T, class A> struct insert_return_type_set;
|
||||
}
|
||||
|
||||
using boost::unordered::unordered_set;
|
||||
|
@ -47,6 +47,12 @@ test-suite unordered
|
||||
[ run unordered/unnecessary_copy_tests.cpp ]
|
||||
[ run unordered/erase_tests.cpp ]
|
||||
[ run unordered/erase_equiv_tests.cpp ]
|
||||
[ run unordered/extract_tests.cpp ]
|
||||
[ run unordered/node_handle_tests.cpp ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MAP : insert_node_type_fail_map ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTIMAP : insert_node_type_fail_multimap ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_SET : insert_node_type_fail_set ]
|
||||
[ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ]
|
||||
[ run unordered/find_tests.cpp ]
|
||||
[ run unordered/at_tests.cpp ]
|
||||
[ run unordered/bucket_tests.cpp ]
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "./list.hpp"
|
||||
#include "./metafunctions.hpp"
|
||||
#include <algorithm>
|
||||
#include <boost/detail/lightweight_test.hpp>
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
|
@ -19,18 +19,21 @@
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class boost::unordered_map<int, int, boost::hash<int>,
|
||||
std::equal_to<int>, test::minimal::allocator<int> >;
|
||||
template class boost::unordered_multimap<int const, int const, boost::hash<int>,
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
|
||||
INSTANTIATE(map)<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multimap)<int const, int const, boost::hash<int>,
|
||||
std::equal_to<int>, test::minimal::allocator<int> >;
|
||||
|
||||
template class boost::unordered_map<test::minimal::assignable const,
|
||||
INSTANTIATE(map)<test::minimal::assignable const,
|
||||
test::minimal::default_assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
template class boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
INSTANTIATE(multimap)<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
|
@ -19,16 +19,19 @@
|
||||
|
||||
// Explicit instantiation to catch compile-time errors
|
||||
|
||||
template class boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
template class boost::unordered_multiset<int const, boost::hash<int>,
|
||||
std::equal_to<int>, test::minimal::allocator<int> >;
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
|
||||
template class boost::unordered_set<test::minimal::assignable const,
|
||||
INSTANTIATE(set)<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
INSTANTIATE(multiset)<int const, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
INSTANTIATE(set)<test::minimal::assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
template class boost::unordered_multiset<test::minimal::assignable,
|
||||
INSTANTIATE(multiset)<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
@ -50,6 +50,8 @@ template <class X, class T> void container_test(X& r, T const&)
|
||||
typedef BOOST_DEDUCED_TYPENAME X::reference reference;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::const_reference const_reference;
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
|
||||
|
||||
// value_type
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T, value_type>::value));
|
||||
@ -72,6 +74,9 @@ template <class X, class T> void container_test(X& r, T const&)
|
||||
boost::function_requires<boost::InputIteratorConcept<const_iterator> >();
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T, const_iterator_value_type>::value));
|
||||
|
||||
// node_type
|
||||
// TODO?
|
||||
|
||||
// difference_type
|
||||
|
||||
BOOST_STATIC_ASSERT(std::numeric_limits<difference_type>::is_signed);
|
||||
@ -140,6 +145,24 @@ template <class X, class T> void container_test(X& r, T const&)
|
||||
sink(X(rvalue(a_const), m));
|
||||
X c3(rvalue(a_const), m);
|
||||
|
||||
// node_type
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
|
||||
BOOST_STATIC_ASSERT(boost::is_same<allocator_type,
|
||||
BOOST_DEDUCED_TYPENAME node_type::allocator_type>::value);
|
||||
|
||||
node_type n1;
|
||||
node_type n2(rvalue_default<node_type>());
|
||||
node_type n3;
|
||||
n3 = boost::move(n2);
|
||||
n1.swap(n3);
|
||||
swap(n1, n3);
|
||||
|
||||
node_type const n_const;
|
||||
BOOST_TEST(n_const ? 0 : 1);
|
||||
test::check_return_type<bool>::equals(!n_const);
|
||||
test::check_return_type<bool>::equals(n_const.empty());
|
||||
|
||||
// Avoid unused variable warnings:
|
||||
|
||||
sink(u);
|
||||
@ -197,7 +220,7 @@ template <class X> void unordered_destructible_test(X&)
|
||||
test::check_return_type<allocator_type>::equals(a_const.get_allocator());
|
||||
}
|
||||
|
||||
template <class X, class Key> void unordered_set_test(X&, Key const&)
|
||||
template <class X, class Key> void unordered_set_test(X& r, Key const&)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME X::value_type value_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::key_type key_type;
|
||||
@ -227,6 +250,18 @@ template <class X, class Key> void unordered_set_test(X&, Key const&)
|
||||
(boost::is_same<value_type const*, local_iterator_pointer>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<value_type const*,
|
||||
const_local_iterator_pointer>::value));
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME node_type::value_type node_value_type;
|
||||
BOOST_STATIC_ASSERT((boost::is_same<value_type, node_value_type>::value));
|
||||
|
||||
// Call node_type functions.
|
||||
|
||||
test::minimal::constructor_param v;
|
||||
Key k_lvalue(v);
|
||||
r.emplace(boost::move(k_lvalue));
|
||||
node_type n1 = r.extract(r.begin());
|
||||
test::check_return_type<value_type>::equals_ref(n1.value());
|
||||
}
|
||||
|
||||
template <class X, class Key, class T>
|
||||
@ -261,6 +296,13 @@ void unordered_map_test(X& r, Key const& k, T const& v)
|
||||
BOOST_STATIC_ASSERT((boost::is_same<value_type const*,
|
||||
const_local_iterator_pointer>::value));
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME node_type::key_type node_key_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME node_type::mapped_type node_mapped_type;
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<Key, node_key_type>::value));
|
||||
BOOST_STATIC_ASSERT((boost::is_same<T, node_mapped_type>::value));
|
||||
|
||||
// Calling functions
|
||||
|
||||
r.insert(std::pair<Key const, T>(k, v));
|
||||
@ -274,6 +316,19 @@ void unordered_map_test(X& r, Key const& k, T const& v)
|
||||
|
||||
r.emplace(boost::unordered::piecewise_construct, boost::make_tuple(k),
|
||||
boost::make_tuple(v));
|
||||
|
||||
test::check_return_type<node_type>::equals(r.extract(r.begin()));
|
||||
|
||||
r.emplace(k, v);
|
||||
test::check_return_type<node_type>::equals(r.extract(k));
|
||||
|
||||
r.emplace(k, v);
|
||||
node_type n1 = r.extract(r.begin());
|
||||
test::check_return_type<key_type>::equals_ref(n1.key());
|
||||
test::check_return_type<T>::equals_ref(n1.mapped());
|
||||
|
||||
r.insert(boost::move(n1));
|
||||
r.insert(r.end(), r.extract(r.begin()));
|
||||
}
|
||||
|
||||
template <class X> void equality_test(X& r)
|
||||
@ -291,6 +346,28 @@ template <class X, class T> void unordered_unique_test(X& r, T const& t)
|
||||
typedef BOOST_DEDUCED_TYPENAME X::iterator iterator;
|
||||
test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t));
|
||||
test::check_return_type<std::pair<iterator, bool> >::equals(r.emplace(t));
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::insert_return_type insert_return_type;
|
||||
|
||||
// insert_return_type
|
||||
|
||||
// TODO;
|
||||
// boost::function_requires<boost::MoveConstructibleConcept<insert_return_type>
|
||||
// >();
|
||||
// TODO;
|
||||
// boost::function_requires<boost::MoveAssignableConcept<insert_return_type>
|
||||
// >();
|
||||
boost::function_requires<
|
||||
boost::DefaultConstructibleConcept<insert_return_type> >();
|
||||
// TODO:
|
||||
// boost::function_requires<boost::DestructibleConcept<insert_return_type>
|
||||
// >();
|
||||
insert_return_type insert_return, insert_return2;
|
||||
test::check_return_type<bool>::equals(insert_return.inserted);
|
||||
test::check_return_type<iterator>::equals(insert_return.position);
|
||||
test::check_return_type<node_type>::equals_ref(insert_return.node);
|
||||
boost::swap(insert_return, insert_return2);
|
||||
}
|
||||
|
||||
template <class X, class T> void unordered_equivalent_test(X& r, T const& t)
|
||||
@ -580,6 +657,11 @@ void unordered_copyable_test(X& x, Key& k, T& t, Hash& hf, Pred& eq)
|
||||
sink(a6a);
|
||||
sink(a7a);
|
||||
sink(a9a);
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME X::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME X::allocator_type allocator_type;
|
||||
node_type const n_const = a.extract(a.begin());
|
||||
test::check_return_type<allocator_type>::equals(n_const.get_allocator());
|
||||
}
|
||||
|
||||
template <class X, class Key, class T, class Hash, class Pred>
|
||||
|
140
test/unordered/extract_tests.cpp
Normal file
140
test/unordered/extract_tests.cpp
Normal file
@ -0,0 +1,140 @@
|
||||
|
||||
// Copyright 2016 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include <boost/next_prior.hpp>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
namespace extract_tests {
|
||||
|
||||
test::seed_t initialize_seed(85638);
|
||||
|
||||
template <class Container>
|
||||
void extract_tests1(Container*, test::random_generator generator)
|
||||
{
|
||||
std::cerr << "Extract by key.\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
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) {
|
||||
std::size_t count = x.count(test::get_key<Container>(*it));
|
||||
std::size_t old_size = x.size();
|
||||
std::size_t new_count = count ? count - 1 : count;
|
||||
std::size_t new_size = count ? old_size - 1 : old_size;
|
||||
typename Container::node_type n =
|
||||
x.extract(test::get_key<Container>(*it));
|
||||
BOOST_TEST((bool)n == (bool)count);
|
||||
BOOST_TEST(x.size() == new_size);
|
||||
BOOST_TEST(x.count(test::get_key<Container>(*it)) == new_count);
|
||||
if (!new_count) {
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) == x.end());
|
||||
} else {
|
||||
BOOST_TEST(x.find(test::get_key<Container>(*it)) != x.end());
|
||||
}
|
||||
if (++iterations % 20 == 0)
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
BOOST_TEST(x.empty());
|
||||
}
|
||||
|
||||
std::cerr << "extract(begin()).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
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 key =
|
||||
test::get_key<Container>(*x.begin());
|
||||
std::size_t count = x.count(key);
|
||||
typename Container::node_type n = x.extract(x.begin());
|
||||
BOOST_TEST(n);
|
||||
--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());
|
||||
}
|
||||
|
||||
std::cerr << "extract(random position).\n";
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
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;
|
||||
int index = rand() % (int)x.size();
|
||||
BOOST_DEDUCED_TYPENAME Container::const_iterator prev, pos, next;
|
||||
if (index == 0) {
|
||||
prev = pos = x.begin();
|
||||
} else {
|
||||
prev = boost::next(x.begin(), index - 1);
|
||||
pos = boost::next(prev);
|
||||
}
|
||||
next = boost::next(pos);
|
||||
BOOST_DEDUCED_TYPENAME Container::key_type key =
|
||||
test::get_key<Container>(*pos);
|
||||
std::size_t count = x.count(key);
|
||||
typename Container::node_type n = x.extract(pos);
|
||||
BOOST_TEST(n);
|
||||
--size;
|
||||
if (size > 0)
|
||||
BOOST_TEST(
|
||||
index == 0 ? next == x.begin() : 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());
|
||||
}
|
||||
|
||||
std::cerr << "\n";
|
||||
}
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_multiset;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(
|
||||
extract_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)))
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
29
test/unordered/insert_node_type_fail.cpp
Normal file
29
test/unordered/insert_node_type_fail.cpp
Normal file
@ -0,0 +1,29 @@
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
int main()
|
||||
{
|
||||
#if defined(UNORDERED_TEST_MAP)
|
||||
typedef boost::unordered_map<int, int> container;
|
||||
container x;
|
||||
x.emplace(1, 1);
|
||||
#elif defined(UNORDERED_TEST_MULTIMAP)
|
||||
typedef boost::unordered_multimap<int, int> container;
|
||||
container x;
|
||||
#elif defined(UNORDERED_TEST_SET)
|
||||
typedef boost::unordered_set<int> container;
|
||||
container x;
|
||||
x.emplace(1);
|
||||
#elif defined(UNORDERED_TEST_MULTISET)
|
||||
typedef boost::unordered_multiset<int> container;
|
||||
container x;
|
||||
x.emplace(1);
|
||||
#else
|
||||
#define UNORDERED_ERROR
|
||||
#endif
|
||||
|
||||
#if !defined(UNORDERED_ERROR)
|
||||
container::node_type n = x.extract(x.begin());
|
||||
x.insert(n);
|
||||
#endif
|
||||
}
|
436
test/unordered/node_handle_tests.cpp
Normal file
436
test/unordered/node_handle_tests.cpp
Normal file
@ -0,0 +1,436 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "../helpers/postfix.hpp"
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
UNORDERED_AUTO_TEST(example1)
|
||||
{
|
||||
typedef boost::unordered_map<int, std::string>::insert_return_type
|
||||
insert_return_type;
|
||||
|
||||
boost::unordered_map<int, std::string> src;
|
||||
src.emplace(1, "one");
|
||||
src.emplace(2, "two");
|
||||
src.emplace(3, "buckle my shoe");
|
||||
boost::unordered_map<int, std::string> dst;
|
||||
dst.emplace(3, "three");
|
||||
|
||||
dst.insert(src.extract(src.find(1)));
|
||||
dst.insert(src.extract(2));
|
||||
insert_return_type r = dst.insert(src.extract(3));
|
||||
|
||||
BOOST_TEST(src.empty());
|
||||
BOOST_TEST(dst.size() == 3);
|
||||
BOOST_TEST(dst[1] == "one");
|
||||
BOOST_TEST(dst[2] == "two");
|
||||
BOOST_TEST(dst[3] == "three");
|
||||
BOOST_TEST(!r.inserted);
|
||||
BOOST_TEST(r.position == dst.find(3));
|
||||
BOOST_TEST(r.node.mapped() == "buckle my shoe");
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(example2)
|
||||
{
|
||||
boost::unordered_set<int> src;
|
||||
src.insert(1);
|
||||
src.insert(3);
|
||||
src.insert(5);
|
||||
boost::unordered_set<int> dst;
|
||||
dst.insert(2);
|
||||
dst.insert(4);
|
||||
dst.insert(5);
|
||||
// dst.merge(src);
|
||||
// Merge src into dst.
|
||||
// src == {5}
|
||||
// dst == {1, 2, 3, 4, 5}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(example3)
|
||||
{
|
||||
typedef boost::unordered_set<int>::iterator iterator;
|
||||
|
||||
boost::unordered_set<int> src;
|
||||
src.insert(1);
|
||||
src.insert(3);
|
||||
src.insert(5);
|
||||
boost::unordered_set<int> dst;
|
||||
dst.insert(2);
|
||||
dst.insert(4);
|
||||
dst.insert(5);
|
||||
for (iterator i = src.begin(); i != src.end();) {
|
||||
std::pair<iterator, iterator> p = dst.equal_range(*i);
|
||||
if (p.first == p.second)
|
||||
dst.insert(p.first, src.extract(i++));
|
||||
else
|
||||
++i;
|
||||
}
|
||||
BOOST_TEST(src.size() == 1);
|
||||
BOOST_TEST(*src.begin() == 5);
|
||||
|
||||
std::set<int> dst2(dst.begin(), dst.end());
|
||||
std::set<int>::iterator it = dst2.begin();
|
||||
BOOST_TEST(*it++ == 1);
|
||||
BOOST_TEST(*it++ == 2);
|
||||
BOOST_TEST(*it++ == 3);
|
||||
BOOST_TEST(*it++ == 4);
|
||||
BOOST_TEST(*it++ == 5);
|
||||
BOOST_TEST(it == dst2.end());
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(failed_insertion_with_hint)
|
||||
{
|
||||
{
|
||||
boost::unordered_set<int> src;
|
||||
boost::unordered_set<int> dst;
|
||||
src.emplace(10);
|
||||
src.emplace(20);
|
||||
dst.emplace(10);
|
||||
dst.emplace(20);
|
||||
|
||||
boost::unordered_set<int>::node_type nh = src.extract(10);
|
||||
|
||||
BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10));
|
||||
BOOST_TEST(nh);
|
||||
BOOST_TEST(!nh.empty());
|
||||
BOOST_TEST(nh.value() == 10);
|
||||
|
||||
BOOST_TEST(dst.insert(dst.find(20), boost::move(nh)) == dst.find(10));
|
||||
BOOST_TEST(nh);
|
||||
BOOST_TEST(!nh.empty());
|
||||
BOOST_TEST(nh.value() == 10);
|
||||
|
||||
BOOST_TEST(src.count(10) == 0);
|
||||
BOOST_TEST(src.count(20) == 1);
|
||||
BOOST_TEST(dst.count(10) == 1);
|
||||
BOOST_TEST(dst.count(20) == 1);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map<int, int> src;
|
||||
boost::unordered_map<int, int> dst;
|
||||
src.emplace(10, 30);
|
||||
src.emplace(20, 5);
|
||||
dst.emplace(10, 20);
|
||||
dst.emplace(20, 2);
|
||||
|
||||
boost::unordered_map<int, int>::node_type nh = src.extract(10);
|
||||
BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10));
|
||||
BOOST_TEST(nh);
|
||||
BOOST_TEST(!nh.empty());
|
||||
BOOST_TEST(nh.key() == 10);
|
||||
BOOST_TEST(nh.mapped() == 30);
|
||||
BOOST_TEST(dst[10] == 20);
|
||||
|
||||
BOOST_TEST(dst.insert(dst.find(20), boost::move(nh)) == dst.find(10));
|
||||
BOOST_TEST(nh);
|
||||
BOOST_TEST(!nh.empty());
|
||||
BOOST_TEST(nh.key() == 10);
|
||||
BOOST_TEST(nh.mapped() == 30);
|
||||
BOOST_TEST(dst[10] == 20);
|
||||
|
||||
BOOST_TEST(src.count(10) == 0);
|
||||
BOOST_TEST(src.count(20) == 1);
|
||||
BOOST_TEST(dst.count(10) == 1);
|
||||
BOOST_TEST(dst.count(20) == 1);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename NodeHandle>
|
||||
bool node_handle_compare(NodeHandle const& nh,
|
||||
BOOST_DEDUCED_TYPENAME NodeHandle::value_type const& x)
|
||||
{
|
||||
return x == nh.value();
|
||||
}
|
||||
|
||||
template <typename NodeHandle>
|
||||
bool node_handle_compare(
|
||||
NodeHandle const& nh,
|
||||
std::pair<BOOST_DEDUCED_TYPENAME NodeHandle::key_type const,
|
||||
BOOST_DEDUCED_TYPENAME NodeHandle::mapped_type> const& x)
|
||||
{
|
||||
return x.first == nh.key() && x.second == nh.mapped();
|
||||
}
|
||||
|
||||
template <typename Container> void node_handle_tests_impl(Container& c)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Container::node_type node_type;
|
||||
|
||||
BOOST_DEDUCED_TYPENAME Container::value_type value = *c.begin();
|
||||
|
||||
node_type n1;
|
||||
BOOST_TEST(!n1);
|
||||
BOOST_TEST(n1.empty());
|
||||
|
||||
node_type n2 = c.extract(c.begin());
|
||||
BOOST_TEST(n2);
|
||||
BOOST_TEST(!n2.empty());
|
||||
node_handle_compare(n2, value);
|
||||
|
||||
node_type n3 = boost::move(n2);
|
||||
BOOST_TEST(n3);
|
||||
BOOST_TEST(!n2);
|
||||
node_handle_compare(n3, value);
|
||||
// TODO: Check that n2 doesn't have an allocator?
|
||||
// Maybe by swapping and observing that the allocator is
|
||||
// swapped rather than moved?
|
||||
|
||||
n1 = boost::move(n3);
|
||||
BOOST_TEST(n1);
|
||||
BOOST_TEST(!n3);
|
||||
node_handle_compare(n1, value);
|
||||
|
||||
// Self move-assignment empties the node_handle.
|
||||
n1 = boost::move(n1);
|
||||
BOOST_TEST(!n1);
|
||||
|
||||
n3 = boost::move(n3);
|
||||
BOOST_TEST(!n3);
|
||||
|
||||
BOOST_DEDUCED_TYPENAME Container::value_type value1 = *c.begin();
|
||||
n1 = c.extract(c.begin());
|
||||
BOOST_DEDUCED_TYPENAME Container::value_type value2 = *c.begin();
|
||||
n2 = c.extract(c.begin());
|
||||
n3 = node_type();
|
||||
|
||||
node_handle_compare(n1, value1);
|
||||
node_handle_compare(n2, value2);
|
||||
n1.swap(n2);
|
||||
BOOST_TEST(n1);
|
||||
BOOST_TEST(n2);
|
||||
node_handle_compare(n1, value2);
|
||||
node_handle_compare(n2, value1);
|
||||
|
||||
BOOST_TEST(n1);
|
||||
BOOST_TEST(!n3);
|
||||
n1.swap(n3);
|
||||
BOOST_TEST(!n1);
|
||||
BOOST_TEST(n3);
|
||||
node_handle_compare(n3, value2);
|
||||
|
||||
BOOST_TEST(!n1);
|
||||
BOOST_TEST(n2);
|
||||
n1.swap(n2);
|
||||
BOOST_TEST(n1);
|
||||
BOOST_TEST(!n2);
|
||||
node_handle_compare(n1, value1);
|
||||
|
||||
node_type n4;
|
||||
BOOST_TEST(!n2);
|
||||
BOOST_TEST(!n4);
|
||||
n2.swap(n4);
|
||||
BOOST_TEST(!n2);
|
||||
BOOST_TEST(!n4);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(node_handle_tests)
|
||||
{
|
||||
boost::unordered_set<int> x1;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
node_handle_tests_impl(x1);
|
||||
|
||||
boost::unordered_map<int, std::string> x2;
|
||||
x2.emplace(10, "ten");
|
||||
x2.emplace(-23, "twenty");
|
||||
x2.emplace(-76, "thirty");
|
||||
node_handle_tests_impl(x2);
|
||||
}
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
void insert_node_handle_unique(Container1& c1, Container2& c2)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_type;
|
||||
BOOST_STATIC_ASSERT(boost::is_same<node_type,
|
||||
BOOST_DEDUCED_TYPENAME Container2::node_type>::value);
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::insert_return_type
|
||||
insert_return_type1;
|
||||
typedef BOOST_DEDUCED_TYPENAME Container2::insert_return_type
|
||||
insert_return_type2;
|
||||
|
||||
insert_return_type1 r1 = c1.insert(node_type());
|
||||
insert_return_type2 r2 = c2.insert(node_type());
|
||||
BOOST_TEST(!r1.inserted);
|
||||
BOOST_TEST(!r1.node);
|
||||
BOOST_TEST(r1.position == c1.end());
|
||||
BOOST_TEST(!r2.inserted);
|
||||
BOOST_TEST(!r2.node);
|
||||
BOOST_TEST(r2.position == c2.end());
|
||||
|
||||
while (!c1.empty()) {
|
||||
value_type v = *c1.begin();
|
||||
value_type const* v_ptr = boost::addressof(*c1.begin());
|
||||
std::size_t count = c2.count(test::get_key<Container1>(v));
|
||||
insert_return_type2 r = c2.insert(c1.extract(c1.begin()));
|
||||
if (!count) {
|
||||
BOOST_TEST(r.inserted);
|
||||
BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count + 1);
|
||||
BOOST_TEST(r.position != c2.end());
|
||||
BOOST_TEST(boost::addressof(*r.position) == v_ptr);
|
||||
BOOST_TEST(!r.node);
|
||||
} else {
|
||||
BOOST_TEST(!r.inserted);
|
||||
BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count);
|
||||
BOOST_TEST(r.position != c2.end());
|
||||
BOOST_TEST(test::get_key<Container2>(*r.position) ==
|
||||
test::get_key<Container2>(v));
|
||||
BOOST_TEST(r.node);
|
||||
node_handle_compare(r.node, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
void insert_node_handle_unique2(Container1& c1, Container2& c2)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_type;
|
||||
BOOST_STATIC_ASSERT(boost::is_same<node_type,
|
||||
BOOST_DEDUCED_TYPENAME Container2::node_type>::value);
|
||||
|
||||
// typedef BOOST_DEDUCED_TYPENAME Container1::insert_return_type
|
||||
// insert_return_type1;
|
||||
typedef BOOST_DEDUCED_TYPENAME Container2::insert_return_type
|
||||
insert_return_type2;
|
||||
|
||||
while (!c1.empty()) {
|
||||
value_type v = *c1.begin();
|
||||
value_type const* v_ptr = boost::addressof(*c1.begin());
|
||||
std::size_t count = c2.count(test::get_key<Container1>(v));
|
||||
insert_return_type2 r =
|
||||
c2.insert(c1.extract(test::get_key<Container1>(v)));
|
||||
if (r.inserted) {
|
||||
BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count + 1);
|
||||
BOOST_TEST(r.position != c2.end());
|
||||
BOOST_TEST(boost::addressof(*r.position) == v_ptr);
|
||||
BOOST_TEST(!r.node);
|
||||
} else {
|
||||
BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count);
|
||||
BOOST_TEST(r.position != c2.end());
|
||||
BOOST_TEST(test::get_key<Container2>(*r.position) ==
|
||||
test::get_key<Container2>(v));
|
||||
BOOST_TEST(r.node);
|
||||
node_handle_compare(r.node, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
void insert_node_handle_equiv(Container1& c1, Container2& c2)
|
||||
{
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::node_type node_type;
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::value_type value_type;
|
||||
BOOST_STATIC_ASSERT(boost::is_same<node_type,
|
||||
BOOST_DEDUCED_TYPENAME Container2::node_type>::value);
|
||||
|
||||
typedef BOOST_DEDUCED_TYPENAME Container1::iterator iterator1;
|
||||
typedef BOOST_DEDUCED_TYPENAME Container2::iterator iterator2;
|
||||
|
||||
iterator1 r1 = c1.insert(node_type());
|
||||
iterator2 r2 = c2.insert(node_type());
|
||||
BOOST_TEST(r1 == c1.end());
|
||||
BOOST_TEST(r2 == c2.end());
|
||||
|
||||
while (!c1.empty()) {
|
||||
value_type v = *c1.begin();
|
||||
value_type const* v_ptr = boost::addressof(*c1.begin());
|
||||
std::size_t count = c2.count(test::get_key<Container1>(v));
|
||||
iterator2 r = c2.insert(c1.extract(c1.begin()));
|
||||
BOOST_TEST_EQ(c2.count(test::get_key<Container1>(v)), count + 1);
|
||||
BOOST_TEST(r != c2.end());
|
||||
BOOST_TEST(boost::addressof(*r) == v_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
struct hash_thing
|
||||
{
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
return static_cast<std::size_t>(x * 13 + 5);
|
||||
}
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_node_handle_unique_tests)
|
||||
{
|
||||
{
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_set<int> x2;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
x2.emplace(140);
|
||||
insert_node_handle_unique(x1, x2);
|
||||
BOOST_TEST(x2.size() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map<int, int, hash_thing> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_unique(x1, x2);
|
||||
BOOST_TEST(x2.size() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_node_handle_equiv_tests)
|
||||
{
|
||||
{
|
||||
boost::unordered_multimap<int, int, hash_thing> x1;
|
||||
boost::unordered_multimap<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(67, 100);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_equiv(x1, x2);
|
||||
BOOST_TEST(x2.size() == 6);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST(insert_node_handle_unique_tests2)
|
||||
{
|
||||
{
|
||||
boost::unordered_set<int> x1;
|
||||
boost::unordered_set<int> x2;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
x2.emplace(140);
|
||||
insert_node_handle_unique2(x1, x2);
|
||||
BOOST_TEST(x2.size() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map<int, int, hash_thing> x1;
|
||||
boost::unordered_map<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_unique2(x1, x2);
|
||||
BOOST_TEST(x2.size() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
Loading…
x
Reference in New Issue
Block a user