implemented node extraction/insertion (#27)

This commit is contained in:
joaquintides
2020-05-09 20:25:41 +02:00
parent a766a08573
commit e69466039d
28 changed files with 1417 additions and 70 deletions

View File

@@ -200,8 +200,12 @@ together, with minor differences explicitly stated when they exist.
Except where noted or if the corresponding interface does not exist, hashed indices
(both unique and non-unique) satisfy the C++ requirements for unordered associative
containers at <b>[unord.req]</b> (supporting unique and equivalent keys, respectively.)
Validity of iterators and references to
elements is preserved in all cases. Occasionally, the exception safety guarantees provided
Iterators (including to the end of the index) and pointers and references to an element
remain valid during the lifetime of the associated container (which can change
upon swapping), or until the referred-to element is erased or extracted;
pointers and references to an extracted element, but not so for iterators,
become valid again once the element is re-inserted.
Occasionally, the exception safety guarantees provided
are actually stronger than required by the standard. We only provide descriptions of
those types and operations that do not exactly conform to or are not mandated by the standard
requirements.
@@ -240,6 +244,8 @@ requirements.
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>const_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>local_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined </b><span class=identifier>const_local_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>same as owning container </b><span class=identifier>node_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>following [container.insert.return] spec </b><span class=identifier>insert_return_type</span><span class=special>;</span>
<span class=comment>// construct/destroy/copy:</span>
@@ -280,6 +286,11 @@ requirements.
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>InputIterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>last</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>initializer_list</span><span class=special>&lt;</span><span class=identifier>value_type</span><span class=special>&gt;</span> <span class=identifier>list</span><span class=special>);</span>
<span class=identifier>insert_return_type</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>node_type</span><span class=special>&amp;&amp;</span> <span class=identifier>nh</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>node_type</span><span class=special>&amp;&amp;</span> <span class=identifier>nh</span><span class=special>);</span>
<span class=identifier>node_type</span> <span class=identifier>extract</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>node_type</span> <span class=identifier>extract</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>key_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>size_type</span> <span class=identifier>erase</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>key_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
@@ -643,6 +654,86 @@ to which this index belongs if
</pre></blockquote>
</blockquote>
<code>insert_return_type insert(node_type&amp;&amp; nh);</code>
<blockquote>
<b>Requires:</b> <code>nh.empty() || get_allocator()==nh.get_allocator()</code>.<br>
<b>Effects:</b> Does nothing if <code>nh</code> is empty; otherwise,
inserts the node owned by <code>nh</code> into the
<code>multi_index_container</code> to which the index belongs if
<ul>
<li>the index is non-unique OR no other element exists with
equivalent key,</li>
<li>AND insertion is allowed by all other indices of the
<code>multi_index_container</code>.</li>
</ul>
<b>Postconditions:</b> <code>nh</code> is empty.<br>
<b>Returns:</b> A value <code>p</code> of type <code>insert_return_type</code>.
If <code>nh</code> is empty, <code>p.position</code> is <code>end()</code>,
<code>p.inserted</code> is <code>false</code> and <code>p.node</code> is empty;
on successful insertion, <code>p.position</code> points to the element inserted,
<code>p.inserted</code> is <code>true</code> and <code>p.node</code>
is empty;
if the insertion failed, <code>p.position</code> points to an element that caused
the insertion to be banned, <code>p.inserted</code> is <code>false</code> and
<code>p.node</code> owns the original node.
Note that more than one element can be causing insertion not to be allowed.<br>
<b>Complexity:</b> <code>O(I(n))</code>.<br>
<b>Exception safety:</b> Strong, except that rehashing may occur even if the
operation fails. If an exception is thrown, <code>nh</code> is not changed.<br>
</blockquote>
<code>iterator insert(const_iterator position,node_type&amp;&amp; nh);</code>
<blockquote>
<b>Requires:</b> <code>nh.empty() || get_allocator()==nh.get_allocator()</code>.
<code>position</code> is a valid iterator of the index.<br>
<b>Effects:</b> Does nothing if <code>nh</code> is empty; otherwise,
inserts the node owned by <code>nh</code> into the
<code>multi_index_container</code> to which the index belongs if
<ul>
<li>the index is non-unique OR no other element exists with
equivalent key,</li>
<li>AND insertion is allowed by all other indices of the
<code>multi_index_container</code>.</li>
</ul>
<code>position</code> is used as a hint to improve the efficiency of the
operation.<br>
<b>Postconditions:</b> <code>nh</code> is empty if insertion succeeds,
and is not changed otherwise.<br>
<b>Returns:</b> <code>end()</code> if <code>nh</code> is empty.
On successful insertion, an iterator to the newly inserted
element; otherwise, an iterator to an element that caused the insertion to be
banned. Note that more than one element can be causing insertion not to be
allowed.<br>
<b>Complexity:</b> <code>O(H(n))</code>.<br>
<b>Exception safety:</b> Strong, except that rehashing may occur even if the
operation fails.
If an exception is thrown, <code>nh</code> is not changed.<br>
</blockquote>
<code>node_type extract(const_iterator position);</code>
<blockquote>
<b>Requires:</b> <code>position</code> is a valid dereferenceable iterator
of the index.<br>
<b>Effects:</b> Extracts the node of the element pointed to by <code>position</code>.<br>
<b>Returns:</b> A node handle owning the extracted node.<br>
<b>Complexity:</b> <code>O(D(n))</code>.<br>
<b>Exception safety:</b> <code>nothrow</code>.<br>
</blockquote>
<code>node_type extract(const key_type& x);</code>
<blockquote>
<b>Effects:</b> Extracts the node of the first element
with key equivalent to <code>x</code>, if there is any.<br>
<b>Returns:</b> A node handle owning the extracted node, or empty otherwise.<br>
<b>Complexity:</b> Average case <code>O(1 + D(n))</code>, worst case
<code>O(n<sub>dist</sub> + D(n))</code>.<br>
<b>Exception safety:</b> Strong.<br>
</blockquote>
<code>iterator erase(iterator position);</code>
<blockquote>
@@ -661,7 +752,7 @@ if no such element exists.<br>
<blockquote>
<b>Effects:</b> Deletes the elements with key equivalent to <code>x</code>.<br>
<b>Returns:</b> Number of elements deleted.<br>
<b>Complexity:</b> Average case, <code>O(1 + m*D(n))</code>, worst case
<b>Complexity:</b> Average case <code>O(1 + m*D(n))</code>, worst case
<code>O(n<sub>dist</sub> + m*D(n))</code>, where <code>m</code> is
the number of elements deleted.<br>
<b>Exception safety:</b> Basic.<br>
@@ -1146,9 +1237,9 @@ Sequenced indices
<br>
<p>Revised August 25th 2017</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2017 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -264,6 +264,7 @@ operators and functions associated with the index (vg. comparison and
<span class=keyword>typedef</span> <b>implementation defined</b> <span class=identifier>iterator_type_list</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined</b> <span class=identifier>const_iterator_type_list</span><span class=special>;</span>
<span class=keyword>typedef</span> <span class=identifier>Allocator</span> <span class=identifier>allocator_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>implementation defined</b> <span class=identifier>node_type</span><span class=special>;</span>
<span class=comment>// nested class templates:</span>
@@ -562,6 +563,11 @@ duplicate <a href="indices.html#tags">tags</a>, either within a single
index or in two different indices.
</p>
<p>
In what follows, the number of indices of the <code>multi_index_container</code>
is named <code>I</code>.
</p>
<h4><a name="types">Nested types</a></h4>
<code>ctor_args_list</code>
@@ -624,6 +630,22 @@ iterators of the indices held by the <code>multi_index_container</code>, in the
as they were specified.
</blockquote>
<a name="node_type"><code>node_type</code></a>
<blockquote>
Node handle class following the standard specification at
<b>[container.node]</b> (version for set containers).
Two instantiations of <code>multi_index_container</code>
have compatible nodes (i.e., the same <code>node_type</code>) if and only if
they are of the form
<code>multi_index_container&lt;Value,IndexSpecifierList1,Allocator&gt;</code> and
<code>multi_index_container&lt;Value,IndexSpecifierList2,Allocator&gt;</code>,
have the same number <code>I</code> of index specifiers, and, for <code>i</code> =
<code>0</code>, ... , <code>I-1</code>, the respective <code>i</code>-th index specifiers
refer to the same <a href="indices.html#index_catalog">type of index</a>, regardless
of unique/non-unique variants and particular configuration type arguments.
</blockquote>
<h4><a name="nested_templates">Nested class templates</a></h4>
<code>template&lt;int N> struct nth_index</code>
@@ -632,7 +654,7 @@ as they were specified.
<code>nth_index&lt;N>::type</code> yields the type of the
<code>N</code>-th (0-based) index held by the <code>multi_index_container</code>, in
the same order as they were specified.<br>
<b>Requires:</b> <code>0 &lt;= N &lt; I</code>.
<b>Requires:</b> <code>0 &lt;= N &lt; I-1</code>.
</blockquote>
<code>template&lt;typename Tag> struct index</code>
@@ -885,7 +907,7 @@ the <code>multi_index_container</code>.<br>
<code>template&lt;int N> typename nth_index&lt;N>::type&amp; get()noexcept;</code>
<blockquote>
<b>Requires:</b> <code>0 &lt;= N &lt; I</code>.<br>
<b>Requires:</b> <code>0 &lt;= N &lt; I-1</code>.<br>
<b>Effects:</b> Returns a reference to the
<code>nth_index&lt;N>::type</code> index held by <code>*this</code>.<br>
<b>Complexity:</b> Constant.<br>
@@ -894,7 +916,7 @@ the <code>multi_index_container</code>.<br>
<code>template&lt;int N> const typename nth_index&lt;N>::type&amp; get()const noexcept;</code>
<blockquote>
<b>Requires:</b> <code>0 &lt;= N &lt; I</code>.<br>
<b>Requires:</b> <code>0 &lt;= N &lt; I-1</code>.<br>
<b>Effects:</b> Returns a <code>const</code> reference to the
<code>nth_index&lt;N>::type</code> index held by <code>*this</code>.<br>
<b>Complexity:</b> Constant.<br>
@@ -940,7 +962,7 @@ are <i>equivalent</i> if:
typename nth_index&lt;N>::type::iterator project(IteratorType it);</code>
<blockquote>
<b>Requires:</b> <code>0 &lt;= N &lt; I</code>. <code>IteratorType</code>
<b>Requires:</b> <code>0 &lt;= N &lt; I-1</code>. <code>IteratorType</code>
belongs to <code>iterator_type_list</code>. <code>it</code> is a valid
iterator of some index of <code>*this</code> (i.e. does not refer to some
other <code>multi_index_container</code>.)<br>
@@ -954,7 +976,7 @@ equivalent to <code>it</code>.<br>
typename nth_index&lt;N>::type::const_iterator project(IteratorType it)const;</code>
<blockquote>
<b>Requires:</b> <code>0 &lt;= N &lt; I</code>. <code>IteratorType</code>
<b>Requires:</b> <code>0 &lt;= N &lt; I-1</code>. <code>IteratorType</code>
belongs to <code>const_iterator_type_list</code> or
<code>iterator_type_list</code>. <code>it</code> is a
valid (constant or non-constant) iterator of some index of <code>*this</code>
@@ -1060,7 +1082,7 @@ Index reference
<br>
<p>Revised January 25th 2020</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software

View File

@@ -196,8 +196,12 @@ Except where noted or if the corresponding interface does not exist,
ordered indices (both unique and non-unique) satisfy the C++ requirements
for associative containers at <b>[associative.reqmts]</b>
(supporting unique and equivalent keys, respectively.)
Accordingly, validity of iterators and references to elements is
preserved. We only provide descriptions of those types and operations that
Iterators (including to the end of the index) and pointers and references to an element
remain valid during the lifetime of the associated container (which can change
upon swapping), or until the referred-to element is erased or extracted;
pointers and references to an extracted element, but not so for iterators,
become valid again once the element is re-inserted.
We only provide descriptions of those types and operations that
do not exactly conform to or are not mandated by the standard requirements.
</p>
@@ -237,6 +241,8 @@ do not exactly conform to or are not mandated by the standard requirements.
std::reverse_iterator&lt;iterator&gt;</b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>equivalent to
std::reverse_iterator&lt;const_iterator&gt;</b> <span class=identifier>const_reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>same as owning container </b><span class=identifier>node_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>following [container.insert.return] spec </b><span class=identifier>insert_return_type</span><span class=special>;</span>
<span class=comment>// construct/copy/destroy:</span>
@@ -282,6 +288,11 @@ do not exactly conform to or are not mandated by the standard requirements.
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>InputIterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>last</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>initializer_list</span><span class=special>&lt;</span><span class=identifier>value_type</span><span class=special>&gt;</span> <span class=identifier>list</span><span class=special>);</span>
<span class=identifier>insert_return_type</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>node_type</span><span class=special>&amp;&amp;</span> <span class=identifier>nh</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>node_type</span><span class=special>&amp;&amp;</span> <span class=identifier>nh</span><span class=special>);</span>
<span class=identifier>node_type</span> <span class=identifier>extract</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>node_type</span> <span class=identifier>extract</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>key_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>size_type</span> <span class=identifier>erase</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>key_type</span><span class=special>&amp;</span> <span class=identifier>x</span><span class=special>);</span>
@@ -635,10 +646,89 @@ to which this index belongs if
</pre></blockquote>
</blockquote>
<code>insert_return_type insert(node_type&amp;&amp; nh);</code>
<blockquote>
<b>Requires:</b> <code>nh.empty() || get_allocator()==nh.get_allocator()</code>.<br>
<b>Effects:</b> Does nothing if <code>nh</code> is empty; otherwise,
inserts the node owned by <code>nh</code> into the
<code>multi_index_container</code> to which the index belongs if
<ul>
<li>the index is non-unique OR no other element exists with
equivalent key,</li>
<li>AND insertion is allowed by all other indices of the
<code>multi_index_container</code>.</li>
</ul>
<b>Postconditions:</b> <code>nh</code> is empty.<br>
<b>Returns:</b> A value <code>p</code> of type <code>insert_return_type</code>.
If <code>nh</code> is empty, <code>p.position</code> is <code>end()</code>,
<code>p.inserted</code> is <code>false</code> and <code>p.node</code> is empty;
on successful insertion, <code>p.position</code> points to the element inserted,
<code>p.inserted</code> is <code>true</code> and <code>p.node</code>
is empty;
if the insertion failed, <code>p.position</code> points to an element that caused
the insertion to be banned, <code>p.inserted</code> is <code>false</code> and
<code>p.node</code> owns the original node.
Note that more than one element can be causing insertion not to be allowed.<br>
<b>Complexity:</b> <code>O(I(n))</code>.<br>
<b>Exception safety:</b> Strong. If an exception
is thrown, <code>nh</code> is not changed.<br>
</blockquote>
<code>iterator insert(const_iterator position,node_type&amp;&amp; nh);</code>
<blockquote>
<b>Requires:</b> <code>nh.empty() || get_allocator()==nh.get_allocator()</code>.
<code>position</code> is a valid iterator of the index.<br>
<b>Effects:</b> Does nothing if <code>nh</code> is empty; otherwise,
inserts the node owned by <code>nh</code> into the
<code>multi_index_container</code> to which the index belongs if
<ul>
<li>the index is non-unique OR no other element exists with
equivalent key,</li>
<li>AND insertion is allowed by all other indices of the
<code>multi_index_container</code>.</li>
</ul>
<code>position</code> is used as a hint to improve the efficiency of the
operation. If successful, insertion happens as close as possible to the
location just prior to <code>position</code>.<br>
<b>Postconditions:</b> <code>nh</code> is empty if insertion succeeds,
and is not changed otherwise.<br>
<b>Returns:</b> <code>end()</code> if <code>nh</code> is empty.
On successful insertion, an iterator to the newly inserted
element; otherwise, an iterator to an element that caused the insertion to be
banned. Note that more than one element can be causing insertion not to be
allowed.<br>
<b>Complexity:</b> <code>O(H(n))</code>.<br>
<b>Exception safety:</b> Strong. If an exception
is thrown, <code>nh</code> is not changed.<br>
</blockquote>
<code>node_type extract(const_iterator position);</code>
<blockquote>
<b>Requires:</b> <code>position</code> is a valid dereferenceable iterator
of the index.<br>
<b>Effects:</b> Extracts the node of the element pointed to by <code>position</code>.<br>
<b>Returns:</b> A node handle owning the extracted node.<br>
<b>Complexity:</b> <code>O(D(n))</code>.<br>
<b>Exception safety:</b> <code>nothrow</code>.<br>
</blockquote>
<code>node_type extract(const key_type& x);</code>
<blockquote>
<b>Effects:</b> Extracts the node of the first element
with key equivalent to <code>x</code>, if there is any.<br>
<b>Returns:</b> A node handle owning the extracted node, or empty otherwise.<br>
<b>Complexity:</b> <code>O(log(n) + D(n))</code>.<br>
<b>Exception safety:</b> Strong.<br>
</blockquote>
<code>iterator erase(iterator position);</code>
<blockquote>
<b>Requires:</b> <code>position</code> is a valid dereferenceable iterator
<b>Requires:</b> <code>position</code> is a valid dereferenceable iterator
of the index.<br>
<b>Effects:</b> Deletes the element pointed to by <code>position</code>.<br>
<b>Returns:</b> An iterator pointing to the element immediately following
@@ -1120,9 +1210,9 @@ Ranked indices
<br>
<p>Revised August 24th 2017</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2017 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -158,8 +158,12 @@ random access indices includes that of
<a href="seq_indices.html">sequenced indices</a>, with differences in
the complexity of the operations, plus extra operations for
positional access (<code>operator[]</code> and <code>at()</code>) and
for capacity handling. Validity of iterators and references to elements
is preserved in all operations, regardless of the capacity status.
for capacity handling.
Iterators (including to the end of the index) and pointers and references to an element
remain valid during the lifetime of the associated container (which can change
upon swapping) regardless of the capacity status, or until the referred-to element
is erased or extracted; pointers and references to an extracted element,
but not so for iterators, become valid again once the element is re-inserted.
</p>
<p>
@@ -181,8 +185,8 @@ plus the requirements for <code>std::list</code> specific list operations at
of the operations provided with respect to their analogues in
<code>std::vector</code>.
</li>
<li>Elements in a randon access index are not mutable, and can only be changed
by means of <a href="#replace"><code>replace</code></a> and
<li>Elements in a random access index are not mutable, and can only be changed
in place by means of <a href="#replace"><code>replace</code></a> and
<a href="#modify"><code>modify</code></a> member functions.
</li>
<li><code>push_front</code> and <code>pop_front</code> are provided for
@@ -219,6 +223,8 @@ plus the requirements for <code>std::list</code> specific list operations at
std::reverse_iterator&lt;iterator&gt;</b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>equivalent to
std::reverse_iterator&lt;const_iterator&gt;</b> <span class=identifier>const_reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>same as owning container </b><span class=identifier>node_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>following [container.insert.return] spec </b><span class=identifier>insert_return_type</span><span class=special>;</span>
<span class=comment>// construct/copy/destroy:</span>
@@ -291,6 +297,9 @@ plus the requirements for <code>std::list</code> specific list operations at
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>last</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>initializer_list</span><span class=special>&lt;</span><span class=identifier>value_type</span><span class=special>&gt;</span> <span class=identifier>list</span><span class=special>);</span>
<span class=identifier>insert_return_type</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>node_type</span><span class=special>&amp;&amp;</span> <span class=identifier>nh</span><span class=special>);</span>
<span class=identifier>node_type</span> <span class=identifier>extract</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>iterator</span> <span class=identifier>last</span><span class=special>);</span>
@@ -645,7 +654,7 @@ is <code>true</code> if and only if insertion took place. On successful insertio
<code>p.first</code> points to the element inserted; otherwise, <code>p.first</code>
points to an element that caused the insertion to be banned. Note that more than
one element can be causing insertion not to be allowed.<br>
<b>Complexity:</b> <code>O(I(n))</code>.<br>
<b>Complexity:</b> <code>O(shl(end()-position,1) + I(n))</code>.<br>
<b>Exception safety:</b> Strong.<br>
</blockquote>
@@ -666,7 +675,7 @@ is <code>true</code> if and only if insertion took place. On successful
insertion, <code>p.first</code> points to the element inserted; otherwise,
<code>p.first</code> points to an element that caused the insertion to be banned.
Note that more than one element can be causing insertion not to be allowed.<br>
<b>Complexity:</b> <code>O(I(n))</code>.<br>
<b>Complexity:</b> <code>O(shl(end()-position,1) + I(n))</code>.<br>
<b>Exception safety:</b> Strong.
</blockquote>
@@ -712,6 +721,40 @@ where <code>m</code> is the number of elements in
</pre></blockquote>
</blockquote>
<code>insert_return_type insert(const_iterator position,node_type&amp;&amp; nh);</code>
<blockquote>
<b>Requires:</b> <code>nh.empty() || get_allocator()==nh.get_allocator()</code>.<br>
<b>Effects:</b> Does nothing if <code>nh</code> is empty; otherwise,
inserts the node owned by <code>nh</code> before <code>position</code> if insertion
is allowed by all other indices of the <code>multi_index_container</code>.<br>
<b>Postconditions:</b> <code>nh</code> is empty.<br>
<b>Returns:</b> A value <code>p</code> of type <code>insert_return_type</code>.
If <code>nh</code> is empty, <code>p.position</code> is <code>end()</code>,
<code>p.inserted</code> is <code>false</code> and <code>p.node</code> is empty;
on successful insertion, <code>p.position</code> points to the element inserted,
<code>p.inserted</code> is <code>true</code> and <code>p.node</code>
is empty;
if the insertion failed, <code>p.position</code> points to an element that caused
the insertion to be banned, <code>p.inserted</code> is <code>false</code> and
<code>p.node</code> owns the original node.
Note that more than one element can be causing insertion not to be allowed.<br>
<b>Complexity:</b> <code>O(shl(end()-position,1) + I(n))</code>.<br>
<b>Exception safety:</b> Strong. If an exception
is thrown, <code>nh</code> is not changed.<br>
</blockquote>
<code>node_type extract(const_iterator position);</code>
<blockquote>
<b>Requires:</b> <code>position</code> is a valid dereferenceable iterator
of the index.<br>
<b>Effects:</b> Extracts the node of the element pointed to by <code>position</code>.<br>
<b>Returns:</b> A node handle owning the extracted node.<br>
<b>Complexity:</b> <code>O(D(n))</code>.<br>
<b>Exception safety:</b> <code>nothrow</code>.<br>
</blockquote>
<code>iterator erase(iterator position);</code>
<blockquote>
@@ -1117,9 +1160,9 @@ Key extraction
<br>
<p>Revised December 29th 2018</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2018 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -152,8 +152,12 @@ like <code>std::list</code>. Elements in a sequenced index are by default
sorted according to their order of insertion: this means that new elements
inserted through a different index of the <code>multi_index_container</code> are appended
to the end of the sequenced index. Additionally, the index allows for free
reordering of elements in the same vein as <code>std::list</code> does. Validity
of iterators and references to elements is preserved in all operations.
reordering of elements in the same vein as <code>std::list</code> does.
Iterators (including to the end of the index) and pointers and references to an element
remain valid during the lifetime of the associated container (which can change
upon swapping), or until the referred-to element is erased or extracted;
pointers and references to an extracted element, but not so for iterators,
become valid again once the element is re-inserted.
</p>
<p>
@@ -172,7 +176,7 @@ most important differences are:
<code>std::list</code>.
</li>
<li>Elements in a sequenced index are not mutable, and can only be changed
by means of <a href="#replace"><code>replace</code></a> and
in place by means of <a href="#replace"><code>replace</code></a> and
<a href="#modify"><code>modify</code></a> member functions.
</li>
</ul>
@@ -207,6 +211,8 @@ most important differences are:
std::reverse_iterator&lt;iterator&gt;</b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>equivalent to
std::reverse_iterator&lt;const_iterator&gt;</b> <span class=identifier>const_reverse_iterator</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>same as owning container </b><span class=identifier>node_type</span><span class=special>;</span>
<span class=keyword>typedef</span> <b>following [container.insert.return] spec </b><span class=identifier>insert_return_type</span><span class=special>;</span>
<span class=comment>// construct/copy/destroy:</span>
@@ -274,6 +280,9 @@ most important differences are:
<span class=keyword>template</span><span class=special>&lt;</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>&gt;</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>InputIterator</span> <span class=identifier>last</span><span class=special>);</span>
<span class=keyword>void</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>initializer_list</span><span class=special>&lt;</span><span class=identifier>value_type</span><span class=special>&gt;</span> <span class=identifier>list</span><span class=special>);</span>
<span class=identifier>insert_return_type</span> <span class=identifier>insert</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>node_type</span><span class=special>&amp;&amp;</span> <span class=identifier>nh</span><span class=special>);</span>
<span class=identifier>node_type</span> <span class=identifier>extract</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>);</span>
<span class=identifier>iterator</span> <span class=identifier>erase</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>first</span><span class=special>,</span><span class=identifier>iterator</span> <span class=identifier>last</span><span class=special>);</span>
@@ -644,6 +653,40 @@ number of elements in [<code>first</code>,<code>last</code>).<br>
</pre></blockquote>
</blockquote>
<code>insert_return_type insert(const_iterator position,node_type&amp;&amp; nh);</code>
<blockquote>
<b>Requires:</b> <code>nh.empty() || get_allocator()==nh.get_allocator()</code>.<br>
<b>Effects:</b> Does nothing if <code>nh</code> is empty; otherwise,
inserts the node owned by <code>nh</code> before <code>position</code> if insertion
is allowed by all other indices of the <code>multi_index_container</code>.<br>
<b>Postconditions:</b> <code>nh</code> is empty.<br>
<b>Returns:</b> A value <code>p</code> of type <code>insert_return_type</code>.
If <code>nh</code> is empty, <code>p.position</code> is <code>end()</code>,
<code>p.inserted</code> is <code>false</code> and <code>p.node</code> is empty;
on successful insertion, <code>p.position</code> points to the element inserted,
<code>p.inserted</code> is <code>true</code> and <code>p.node</code>
is empty;
if the insertion failed, <code>p.position</code> points to an element that caused
the insertion to be banned, <code>p.inserted</code> is <code>false</code> and
<code>p.node</code> owns the original node.
Note that more than one element can be causing insertion not to be allowed.<br>
<b>Complexity:</b> <code>O(I(n))</code>.<br>
<b>Exception safety:</b> Strong. If an exception
is thrown, <code>nh</code> is not changed.<br>
</blockquote>
<code>node_type extract(const_iterator position);</code>
<blockquote>
<b>Requires:</b> <code>position</code> is a valid dereferenceable iterator
of the index.<br>
<b>Effects:</b> Extracts the node of the element pointed to by <code>position</code>.<br>
<b>Returns:</b> A node handle owning the extracted node.<br>
<b>Complexity:</b> <code>O(D(n))</code>.<br>
<b>Exception safety:</b> <code>nothrow</code>.<br>
</blockquote>
<code>iterator erase(iterator position);</code>
<blockquote>
@@ -1052,9 +1095,9 @@ Random access indices
<br>
<p>Revised December 29th 2018</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2018 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -67,6 +67,12 @@ Acknowledgements
<p>
<ul>
<li>
Added <a href="tutorial/basics.html#node_handling">node extraction and insertion</a>
following the analogous interface of associative containers as introduced in C++17.
This feature has also been extended to non key-based indices, in contrast to C++
standard library sequence containers, which do not provide such funcionality.
</li>
<li>Clarified documentation on read/write key extractors
(<a href="https://github.com/boostorg/multi_index/issues/32">issue #32</a>).
</li>
@@ -669,7 +675,7 @@ Acknowledgements
<br>
<p>Revised April 19th 2020</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software

View File

@@ -104,44 +104,48 @@ with some of the least common features offered by Boost.MultiIndex.
<td>Metaprogramming manipulations of <code>multi_index_container</code> types.</td>
</tr>
<tr>
<td><a href="../test/test_node_handling.cpp"><code>test_node_handling.cpp</code></a></td>
<td>Operations involving node extraction and insertion.</td>
</tr>
<tr class="odd_tr">
<td><a href="../test/test_observers.cpp"><code>test_observers.cpp</code></a></td>
<td>Checks observer member functions of ordered and hashed indices.</td>
</tr>
<tr class="odd_tr">
<tr>
<td><a href="../test/test_projection.cpp"><code>test_projection.cpp</code></a></td>
<td>Projection of iterators among indices.</td>
</tr>
<tr>
<tr class="odd_tr">
<td><a href="../test/test_range.cpp"><code>test_range.cpp</code></a></td>
<td>Exercises the <code>range</code> facility (ordered indices only).</td>
</tr>
<tr class="odd_tr">
<tr>
<td><a href="../test/test_rank_ops.cpp"><code>test_rank_ops.cpp</code></a></td>
<td>Specific operations of ranked indices.</td>
</tr>
<tr>
<tr class="odd_tr">
<td><a href="../test/test_rearrange.cpp"><code>test_rearrange.cpp</code></a></td>
<td>Rearrange functions of sequenced and random access indices.</td>
</tr>
<tr class="odd_tr">
<tr>
<td><a href="../test/test_safe_mode.cpp"><code>test_safe_mode.cpp</code></a></td>
<td>Comprehensive coverage of all conditions checked in safe mode.</td>
</tr>
<tr>
<tr class="odd_tr">
<td><a href="../test/test_serialization1.cpp"><code>test_serialization1.cpp</code></a><br>
<a href="../test/test_serialization2.cpp"><code>test_serialization2.cpp</code></a><br>
<a href="../test/test_serialization3.cpp"><code>test_serialization3.cpp</code></a></td>
<td>Serialization support.</td>
</tr>
<tr class="odd_tr">
<tr>
<td><a href="../test/test_set_ops.cpp"><code>test_set_ops.cpp</code></a></td>
<td>Set-like operations particular to ordered indices.</td>
</tr>
<tr>
<tr class="odd_tr">
<td><a href="../test/test_special_set_ops.cpp"><code>test_special_set_ops.cpp</code></a></td>
<td>Checks special lookup operations using compatible sorting criteria.</td>
</tr>
<tr class="odd_tr">
<tr>
<td><a href="../test/test_update.cpp"><code>test_update.cpp</code></a></td>
<td><code>replace</code>, <code>modify</code> and <code>modify_key</code>.</td>
</tr>
@@ -162,7 +166,7 @@ Future work
<br>
<p>Revised January 25th 2020</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software

View File

@@ -62,6 +62,7 @@ Index types
</ul>
</li>
<li><a href="#projection">Projection of iterators</a></li>
<li><a href="#node_handling">Node handling operations</a></li>
<li><a href="#complexity">Complexity and exception safety</a></li>
</ul>
@@ -1216,6 +1217,72 @@ When provided, <code>project</code> can also be used with
<a href="#tagging">tags</a>.
</p>
<h2><a name="node_handling">Node handling operations</a></h2>
<p>
Using direct node manipulation, elements can be passed between
<code>multi_index_container</code>s without actually copying them:
</p>
<blockquote><pre>
<span class=comment>// move an employee to the retiree archive</span>
<span class=keyword>void</span> <span class=identifier>move_to_retirement</span><span class=special>(</span><span class=keyword>int</span> <span class=identifier>ssnumber</span><span class=special>,</span><span class=identifier>employee_set</span><span class=special>&amp;</span> <span class=identifier>es</span><span class=special>,</span><span class=identifier>employee_set</span><span class=special>&amp;</span> <span class=identifier>archive</span><span class=special>)</span>
<span class=special>{</span>
<span class=comment>// extract the employee with given SS number to a node handle</span>
<span class=identifier>employee_set_by_ssn</span><span class=special>::</span><span class=identifier>node_type</span> <span class=identifier>node</span><span class=special>=</span><span class=identifier>es</span><span class=special>.</span><span class=identifier>get</span><span class=special>&lt;</span><span class=identifier>ssn</span><span class=special>&gt;().</span><span class=identifier>extract</span><span class=special>(</span><span class=identifier>ssnumber</span><span class=special>);</span>
<span class=keyword>if</span><span class=special>(!</span><span class=identifier>node</span><span class=special>.</span><span class=identifier>empty</span><span class=special>()){</span> <span class=comment>// employee found
// re-insert into archive (note the use of std::move)</span>
<span class=identifier>archive</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=identifier>std</span><span class=special>::</span><span class=identifier>move</span><span class=special>(</span><span class=identifier>node</span><span class=special>));</span>
<span class=special>}</span>
<span class=special>}</span>
</pre></blockquote>
<p>
In the example, the internal node is transferred as-is from <code>es</code> to <code>archive</code>,
which is more efficient than erasing from the source and recreating in destination.
<code>node_type</code> is a move-only class used to pass nodes around, and its interface follows
that of the <a href="https://en.cppreference.com/w/cpp/container/node_handle">homonym type</a>
for C++ associative containers (set containers version). Boost.MultiIndex provides node extraction
and insertion operations for all index types, including sequenced ones (by contrast,
<code>std::list</code> does not have such features):
</p>
<blockquote><pre>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;,</span>
<span class=identifier>ordered_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>src</span><span class=special>;</span>
<span class=identifier>multi_index_container</span><span class=special>&lt;</span>
<span class=keyword>int</span><span class=special>,</span>
<span class=identifier>indexed_by</span><span class=special>&lt;</span>
<span class=identifier>sequenced</span><span class=special>&lt;&gt;,</span>
<span class=identifier>ordered_non_unique</span><span class=special>&lt;</span><span class=identifier>identity</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;,</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special>&lt;</span><span class=keyword>int</span><span class=special>&gt;</span> <span class=special>&gt;</span>
<span class=special>&gt;</span>
<span class=special>&gt;</span> <span class=identifier>dst</span><span class=special>;</span>
<span class=special>...</span>
<span class=comment>// transfer even numbers from src to dst</span>
<span class=keyword>for</span><span class=special>(</span><span class=keyword>auto</span> <span class=identifier>first</span><span class=special>=</span><span class=identifier>src</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>last</span><span class=special>=</span><span class=identifier>src</span><span class=special>.</span><span class=identifier>end</span><span class=special>();</span><span class=identifier>first</span><span class=special>!=</span><span class=identifier>last</span><span class=special>;){</span>
<span class=keyword>if</span><span class=special>(*</span><span class=identifier>first</span><span class=special>%</span><span class=number>2</span><span class=special>==</span><span class=number>0</span><span class=special>)</span> <span class=identifier>dst</span><span class=special>.</span><span class=identifier>insert</span><span class=special>(</span><span class=identifier>dst</span><span class=special>.</span><span class=identifier>end</span><span class=special>(),</span><span class=identifier>src</span><span class=special>.</span><span class=identifier>extract</span><span class=special>(</span><span class=identifier>first</span><span class=special>++));</span>
<span class=keyword>else</span> <span class=special>++</span><span class=identifier>first</span><span class=special>;</span>
<span class=special>}</span>
</pre></blockquote>
<p>
Note that <code>src</code> and <code>dst</code> are of different types,
yet transfer is possible. Two <code>multi_index_container</code>s are
node-compatible (that is, they use the same <code>node_type</code>) if
they have the same element and allocator types and their respective indices match
one by one without regard to whether they are unique or non-unique or to
their particular configuration parameters: they are both ordered, or
both sequenced, etc.
</p>
<h2><a name="complexity">Complexity and exception safety</a></h2>
<p>
@@ -1250,9 +1317,9 @@ Index types
<br>
<p>Revised February 20th 2019</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2019 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -125,7 +125,8 @@ is one value of the <code>safe_mode::error_code</code> enumeration:
<span class=identifier>invalid_range</span><span class=special>,</span> <span class=comment>// last not reachable from first</span>
<span class=identifier>inside_range</span><span class=special>,</span> <span class=comment>// iterator lies within a range (and it mustn't)</span>
<span class=identifier>out_of_bounds</span><span class=special>,</span> <span class=comment>// move attempted beyond container limits</span>
<span class=identifier>same_container</span> <span class=comment>// containers ought to be different</span>
<span class=identifier>same_container</span><span class=special>,</span> <span class=comment>// containers ought to be different</span>
<span class=identifier>unequal_allocators</span> <span class=comment>// allocators ought to be equal</span>
<span class=special>};</span>
<span class=special>}</span> <span class=comment>// namespace multi_index::safe_mode</span>
@@ -239,9 +240,9 @@ Techniques
<br>
<p>Revised July 07th 2017</p>
<p>Revised May 9th 2020</p>
<p>&copy; Copyright 2003-2017 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
<p>&copy; Copyright 2003-2020 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz.
Distributed under the Boost Software
License, Version 1.0. (See accompanying file <a href="../../../../LICENSE_1_0.txt">
LICENSE_1_0.txt</a> or copy at <a href="http://www.boost.org/LICENSE_1_0.txt">

View File

@@ -0,0 +1,32 @@
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#include <boost/config.hpp>
#if !defined(BOOST_MULTI_INDEX_DETAIL_UNDEF_IF_CONSTEXPR_MACRO)
#if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
#define BOOST_MULTI_INDEX_IF_CONSTEXPR if constexpr
#else
#define BOOST_MULTI_INDEX_IF_CONSTEXPR if
#if defined(BOOST_MSVC)
#define BOOST_MULTI_INDEX_DETAIL_C4127_DISABLED
#pragma warning(push)
#pragma warning(disable:4127) /* conditional expression is constant */
#endif
#endif
#else
#undef BOOST_MULTI_INDEX_IF_CONSTEXPR
#if defined(BOOST_MULTI_INDEX_DETAIL_C4127_DISABLED)
#pragma warning(pop)
#undef BOOST_MULTI_INDEX_DETAIL_C4127_DISABLED
#endif
#endif

View File

@@ -23,6 +23,7 @@
#include <boost/multi_index/detail/allocator_traits.hpp>
#include <boost/multi_index/detail/copy_map.hpp>
#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
#include <boost/multi_index/detail/node_handle.hpp>
#include <boost/multi_index/detail/node_type.hpp>
#include <boost/multi_index/detail/vartempl_support.hpp>
#include <boost/multi_index_container_fwd.hpp>
@@ -65,6 +66,8 @@ protected:
typedef typename rebind_alloc_for<
Allocator,typename Allocator::value_type
>::type final_allocator_type;
typedef node_handle<
final_node_type,final_allocator_type> final_node_handle_type;
typedef mpl::vector0<> index_type_list;
typedef mpl::vector0<> iterator_type_list;
typedef mpl::vector0<> const_iterator_type_list;
@@ -217,6 +220,8 @@ protected:
template<typename T>
std::pair<final_node_type*,bool> final_insert_ref_(T& t)
{return final().insert_ref_(t);}
std::pair<final_node_type*,bool> final_insert_nh_(final_node_handle_type& nh)
{return final().insert_nh_(nh);}
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
std::pair<final_node_type*,bool> final_emplace_(
@@ -239,6 +244,9 @@ protected:
std::pair<final_node_type*,bool> final_insert_ref_(
T& t,final_node_type* position)
{return final().insert_ref_(t,position);}
std::pair<final_node_type*,bool> final_insert_nh_(
final_node_handle_type& nh,final_node_type* position)
{return final().insert_nh_(nh,position);}
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
std::pair<final_node_type*,bool> final_emplace_hint_(
@@ -248,6 +256,11 @@ protected:
position,BOOST_MULTI_INDEX_FORWARD_PARAM_PACK);
}
final_node_handle_type final_extract_(final_node_type* x)
{
return final().extract_(x);
}
void final_erase_(final_node_type* x){final().erase_(x);}
void final_delete_node_(final_node_type* x){final().delete_node_(x);}

View File

@@ -0,0 +1,237 @@
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_DETAIL_NODE_HANDLE_HPP
#define BOOST_MULTI_INDEX_DETAIL_NODE_HANDLE_HPP
#if defined(_MSC_VER)
#pragma once
#endif
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
#include <boost/core/addressof.hpp>
#include <boost/move/core.hpp>
#include <boost/multi_index_container_fwd.hpp>
#include <boost/multi_index/detail/allocator_traits.hpp>
#include <boost/type_traits/aligned_storage.hpp>
#include <boost/type_traits/alignment_of.hpp>
#include <new>
namespace boost{
namespace multi_index{
namespace detail{
/* Node handle template class following [container.node] specs.
*/
#include <boost/multi_index/detail/define_if_constexpr_macro.hpp>
template<typename Node,typename Allocator>
class node_handle
{
public:
typedef typename Node::value_type value_type;
typedef Allocator allocator_type;
private:
typedef allocator_traits<allocator_type> alloc_traits;
public:
node_handle()BOOST_NOEXCEPT:node(0){}
node_handle(BOOST_RV_REF(node_handle) x)BOOST_NOEXCEPT:node(x.node)
{
if(!x.empty()){
move_construct_allocator(boost::move(x));
x.destroy_allocator();
x.node=0;
}
}
~node_handle()
{
if(!empty()){
delete_node();
destroy_allocator();
}
}
node_handle& operator=(BOOST_RV_REF(node_handle) x)
{
if(this!=&x){
if(!empty()){
delete_node();
if(!x.empty()){
BOOST_MULTI_INDEX_IF_CONSTEXPR(
alloc_traits::propagate_on_container_move_assignment::value){
move_assign_allocator(boost::move(x));
}
x.destroy_allocator();
}
else{
destroy_allocator();
}
}
else if(!x.empty()){
move_construct_allocator(boost::move(x));
x.destroy_allocator();
}
node=x.node;
x.node=0;
}
return *this;
}
value_type& value()const{return node->value();}
allocator_type get_allocator()const{return *allocator_ptr();}
#if !defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
explicit
#endif
operator bool()const BOOST_NOEXCEPT{return (node!=0);}
BOOST_ATTRIBUTE_NODISCARD bool empty()const BOOST_NOEXCEPT{return (node==0);}
void swap(node_handle& x)
BOOST_NOEXCEPT_IF(
alloc_traits::propagate_on_container_swap::value||
alloc_traits::is_always_equal::value)
{
if(!empty()){
if(!x.empty()){
BOOST_MULTI_INDEX_IF_CONSTEXPR(
alloc_traits::propagate_on_container_swap::value){
using std::swap;
swap(*allocator_ptr(),*x.allocator_ptr());
}
}
else{
x.move_construct_allocator(boost::move(*this));
destroy_allocator();
}
}
else if(!x.empty()){
move_construct_allocator(boost::move(x));
x.destroy_allocator();
}
std::swap(node,x.node);
}
friend void swap(node_handle& x,node_handle& y)
BOOST_NOEXCEPT_IF(noexcept(x.swap(y)))
{
x.swap(y);
}
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(node_handle)
template <typename,typename,typename>
friend class boost::multi_index::multi_index_container;
node_handle(Node* node_,const allocator_type& al):node(node_)
{
::new (static_cast<void*>(allocator_ptr())) allocator_type(al);
}
void release_node()
{
if(!empty()){
node=0;
destroy_allocator();
}
}
#include <boost/multi_index/detail/ignore_wstrict_aliasing.hpp>
const allocator_type* allocator_ptr()const
{
return reinterpret_cast<const allocator_type*>(&space);
}
allocator_type* allocator_ptr()
{
return reinterpret_cast<allocator_type*>(&space);
}
#include <boost/multi_index/detail/restore_wstrict_aliasing.hpp>
void move_construct_allocator(BOOST_RV_REF(node_handle) x)
{
::new (static_cast<void*>(allocator_ptr()))
allocator_type(boost::move(*x.allocator_ptr()));
}
void move_assign_allocator(BOOST_RV_REF(node_handle) x)
{
*allocator_ptr()=boost::move(*x.allocator_ptr());
}
void destroy_allocator(){allocator_ptr()->~allocator_type();}
void delete_node()
{
typedef typename rebind_alloc_for<
allocator_type,Node
>::type node_allocator;
typedef detail::allocator_traits<node_allocator> node_alloc_traits;
typedef typename node_alloc_traits::pointer node_pointer;
alloc_traits::destroy(*allocator_ptr(),boost::addressof(node->value()));
node_allocator nal(*allocator_ptr());
node_alloc_traits::deallocate(nal,static_cast<node_pointer>(node),1);
}
Node* node;
typename aligned_storage<
sizeof(allocator_type),
alignment_of<allocator_type>::value
>::type space;
};
#include <boost/multi_index/detail/undef_if_constexpr_macro.hpp>
/* node handle insert return type template class following
* [container.insert.return] specs.
*/
template<typename Iterator,typename NodeHandle>
struct insert_return_type
{
insert_return_type(
Iterator position_,bool inserted_,BOOST_RV_REF(NodeHandle) node_):
position(position_),inserted(inserted_),node(boost::move(node_)){}
insert_return_type(BOOST_RV_REF(insert_return_type) x):
position(x.position),inserted(x.inserted),node(boost::move(x.node)){}
insert_return_type& operator=(BOOST_RV_REF(insert_return_type) x)
{
position=x.position;
inserted=x.inserted;
node=boost::move(x.node);
return *this;
}
Iterator position;
bool inserted;
NodeHandle node;
private:
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type)
};
} /* namespace multi_index::detail */
} /* namespace multi_index */
} /* namespace boost */
#endif

View File

@@ -59,6 +59,7 @@
#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
#include <boost/multi_index/detail/index_node_base.hpp>
#include <boost/multi_index/detail/modify_key_adaptor.hpp>
#include <boost/multi_index/detail/node_handle.hpp>
#include <boost/multi_index/detail/ord_index_node.hpp>
#include <boost/multi_index/detail/ord_index_ops.hpp>
#include <boost/multi_index/detail/safe_mode.hpp>
@@ -189,6 +190,9 @@ public:
boost::reverse_iterator<iterator> reverse_iterator;
typedef typename
boost::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename super::final_node_handle_type node_type;
typedef detail::insert_return_type<
iterator,node_type> insert_return_type;
typedef TagList tag_list;
protected:
@@ -351,6 +355,42 @@ public:
}
#endif
insert_return_type insert(BOOST_RV_REF(node_type) nh)
{
if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
std::pair<final_node_type*,bool> p=this->final_insert_nh_(nh);
return insert_return_type(make_iterator(p.first),p.second,boost::move(nh));
}
iterator insert(const_iterator position,BOOST_RV_REF(node_type) nh)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
std::pair<final_node_type*,bool> p=this->final_insert_nh_(
nh,static_cast<final_node_type*>(position.get_node()));
return make_iterator(p.first);
}
node_type extract(const_iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
return this->final_extract_(
static_cast<final_node_type*>(position.get_node()));
}
node_type extract(key_param_type x)
{
iterator position=lower_bound(x);
if(position==end()||comp_(x,key(*position)))return node_type();
else return extract(position);
}
iterator erase(iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);

View File

@@ -105,6 +105,11 @@
safe_mode::check_different_container(cont0,cont1), \
safe_mode::same_container);
#define BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(cont0,cont1) \
BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
safe_mode::check_equal_allocators(cont0,cont1), \
safe_mode::unequal_allocators);
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <algorithm>
@@ -229,6 +234,13 @@ inline bool check_different_container(
return &cont0!=&cont1;
}
template<typename Container0,typename Container1>
inline bool check_equal_allocators(
const Container0& cont0,const Container1& cont1)
{
return cont0.get_allocator()==cont1.get_allocator();
}
/* Invalidates all iterators equivalent to that given. Safe containers
* must call this when deleting elements: the safe mode framework cannot
* perform this operation automatically without outside help.

View File

@@ -0,0 +1,11 @@
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#define BOOST_MULTI_INDEX_DETAIL_UNDEF_IF_CONSTEXPR_MACRO
#include <boost/multi_index/detail/define_if_constexpr_macro.hpp>
#undef BOOST_MULTI_INDEX_DETAIL_UNDEF_IF_CONSTEXPR_MACRO

View File

@@ -34,6 +34,7 @@
#include <boost/multi_index/detail/hash_index_iterator.hpp>
#include <boost/multi_index/detail/index_node_base.hpp>
#include <boost/multi_index/detail/modify_key_adaptor.hpp>
#include <boost/multi_index/detail/node_handle.hpp>
#include <boost/multi_index/detail/promotes_arg.hpp>
#include <boost/multi_index/detail/safe_mode.hpp>
#include <boost/multi_index/detail/scope_guard.hpp>
@@ -161,6 +162,9 @@ public:
Category,hashed_index_local_iterator_tag> local_iterator;
typedef local_iterator const_local_iterator;
typedef typename super::final_node_handle_type node_type;
typedef detail::insert_return_type<
iterator,node_type> insert_return_type;
typedef TagList tag_list;
protected:
@@ -321,6 +325,42 @@ public:
}
#endif
insert_return_type insert(BOOST_RV_REF(node_type) nh)
{
if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
std::pair<final_node_type*,bool> p=this->final_insert_nh_(nh);
return insert_return_type(make_iterator(p.first),p.second,boost::move(nh));
}
iterator insert(const_iterator position,BOOST_RV_REF(node_type) nh)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
std::pair<final_node_type*,bool> p=this->final_insert_nh_(
nh,static_cast<final_node_type*>(position.get_node()));
return make_iterator(p.first);
}
node_type extract(const_iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
return this->final_extract_(
static_cast<final_node_type*>(position.get_node()));
}
node_type extract(key_param_type x)
{
iterator position=find(x);
if(position==end())return node_type();
else return extract(position);
}
iterator erase(iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);

View File

@@ -31,6 +31,7 @@
#include <boost/multi_index/detail/allocator_traits.hpp>
#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
#include <boost/multi_index/detail/index_node_base.hpp>
#include <boost/multi_index/detail/node_handle.hpp>
#include <boost/multi_index/detail/rnd_node_iterator.hpp>
#include <boost/multi_index/detail/rnd_index_node.hpp>
#include <boost/multi_index/detail/rnd_index_ops.hpp>
@@ -139,6 +140,9 @@ public:
boost::reverse_iterator<iterator> reverse_iterator;
typedef typename
boost::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename super::final_node_handle_type node_type;
typedef detail::insert_return_type<
iterator,node_type> insert_return_type;
typedef TagList tag_list;
protected:
@@ -397,6 +401,29 @@ public:
}
#endif
insert_return_type insert(const_iterator position,BOOST_RV_REF(node_type) nh)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
BOOST_MULTI_INDEX_RND_INDEX_CHECK_INVARIANT;
std::pair<final_node_type*,bool> p=this->final_insert_nh_(nh);
if(p.second&&position.get_node()!=header()){
relocate(position.get_node(),p.first);
}
return insert_return_type(make_iterator(p.first),p.second,boost::move(nh));
}
node_type extract(const_iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
BOOST_MULTI_INDEX_RND_INDEX_CHECK_INVARIANT;
return this->final_extract_(
static_cast<final_node_type*>(position.get_node()));
}
iterator erase(iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);

View File

@@ -1,4 +1,4 @@
/* Copyright 2003-2013 Joaquin M Lopez Munoz.
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
* 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)
@@ -36,7 +36,8 @@ enum error_code
invalid_range,
inside_range,
out_of_bounds,
same_container
same_container,
unequal_allocators
};
} /* namespace multi_index::safe_mode */

View File

@@ -31,6 +31,7 @@
#include <boost/multi_index/detail/bidir_node_iterator.hpp>
#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
#include <boost/multi_index/detail/index_node_base.hpp>
#include <boost/multi_index/detail/node_handle.hpp>
#include <boost/multi_index/detail/safe_mode.hpp>
#include <boost/multi_index/detail/scope_guard.hpp>
#include <boost/multi_index/detail/seq_index_node.hpp>
@@ -126,6 +127,9 @@ public:
boost::reverse_iterator<iterator> reverse_iterator;
typedef typename
boost::reverse_iterator<const_iterator> const_reverse_iterator;
typedef typename super::final_node_handle_type node_type;
typedef detail::insert_return_type<
iterator,node_type> insert_return_type;
typedef TagList tag_list;
protected:
@@ -348,6 +352,29 @@ public:
}
#endif
insert_return_type insert(const_iterator position,BOOST_RV_REF(node_type) nh)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
if(nh)BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,nh);
BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT;
std::pair<final_node_type*,bool> p=this->final_insert_nh_(nh);
if(p.second&&position.get_node()!=header()){
relink(position.get_node(),p.first);
}
return insert_return_type(make_iterator(p.first),p.second,boost::move(nh));
}
node_type extract(const_iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(position);
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT;
return this->final_extract_(
static_cast<final_node_type*>(position.get_node()));
}
iterator erase(iterator position)
{
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);

View File

@@ -365,15 +365,7 @@ public:
multi_index_container<Value,IndexSpecifierList,Allocator>& operator=(
BOOST_RV_REF(multi_index_container) x)
{
#if !defined(BOOST_NO_CXX17_IF_CONSTEXPR)
#define BOOST_MULTI_INDEX_IF_CONSTEXPR if constexpr
#else
#define BOOST_MULTI_INDEX_IF_CONSTEXPR if
#if defined(BOOST_MSVC)
#pragma warning(push)
#pragma warning(disable:4127) /* conditional expression is constant */
#endif
#endif
#include <boost/multi_index/detail/define_if_constexpr_macro.hpp>
BOOST_MULTI_INDEX_IF_CONSTEXPR(
node_alloc_traits::propagate_on_container_move_assignment::value){
@@ -388,10 +380,7 @@ public:
}
return *this;
#undef BOOST_MULTI_INDEX_IF_CONSTEXPR
#if defined(BOOST_NO_CXX17_IF_CONSTEXPR)&&defined(BOOST_MSVC)
#pragma warning(pop) /* C4127 */
#endif
#include <boost/multi_index/detail/undef_if_constexpr_macro.hpp>
}
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
@@ -578,7 +567,8 @@ public:
#endif
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
typedef typename super::copy_map_type copy_map_type;
typedef typename super::final_node_handle_type final_node_handle_type;
typedef typename super::copy_map_type copy_map_type;
multi_index_container(
multi_index_container<Value,IndexSpecifierList,Allocator>& x,
@@ -761,6 +751,22 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
return insert_(x);
}
std::pair<final_node_type*,bool> insert_nh_(final_node_handle_type& nh)
{
if(!nh)return std::pair<final_node_type*,bool>(header(),false);
else{
final_node_type* x=nh.node;
final_node_type* res=super::insert_(
x->value(),x,detail::emplaced_tag());
if(res==x){
nh.release_node();
++node_count;
return std::pair<final_node_type*,bool>(res,true);
}
else return std::pair<final_node_type*,bool>(res,false);
}
}
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
std::pair<final_node_type*,bool> emplace_(
BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
@@ -864,6 +870,23 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
return insert_(x,position);
}
std::pair<final_node_type*,bool> insert_nh_(
final_node_handle_type& nh,final_node_type* position)
{
if(!nh)return std::pair<final_node_type*,bool>(header(),false);
else{
final_node_type* x=nh.node;
final_node_type* res=super::insert_(
x->value(),position,x,detail::emplaced_tag());
if(res==x){
nh.release_node();
++node_count;
return std::pair<final_node_type*,bool>(res,true);
}
else return std::pair<final_node_type*,bool>(res,false);
}
}
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
std::pair<final_node_type*,bool> emplace_hint_(
final_node_type* position,
@@ -897,6 +920,13 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
BOOST_CATCH_END
}
final_node_handle_type extract_(final_node_type* x)
{
--node_count;
super::extract_(x);
return final_node_handle_type(x,get_allocator());
}
void erase_(final_node_type* x)
{
--node_count;

View File

@@ -56,6 +56,7 @@ test-suite "multi_index" :
[ run test_list_ops.cpp test_list_ops_main.cpp ]
[ run test_modifiers.cpp test_modifiers_main.cpp ]
[ run test_mpl_ops.cpp test_mpl_ops_main.cpp ]
[ run test_node_handling.cpp test_node_handling_main.cpp ]
[ run test_observers.cpp test_observers_main.cpp ]
[ run test_projection.cpp test_projection_main.cpp ]
[ run test_range.cpp test_range_main.cpp ]

61
test/count_allocator.hpp Normal file
View File

@@ -0,0 +1,61 @@
/* Used in Boost.MultiIndex tests.
*
* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#ifndef BOOST_MULTI_INDEX_TEST_COUNT_ALLOCATOR_HPP
#define BOOST_MULTI_INDEX_TEST_COUNT_ALLOCATOR_HPP
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <memory>
template<typename T>
struct count_allocator:std::allocator<T>
{
typedef std::allocator<T> super;
template<class U>
struct rebind{typedef count_allocator<U> other;};
count_allocator(std::size_t& element_count,std::size_t& allocator_count):
pelement_count(&element_count),pallocator_count(&allocator_count)
{++(*pallocator_count);}
count_allocator(const count_allocator<T>& x):
super(x),
pelement_count(x.pelement_count),pallocator_count(x.pallocator_count)
{++(*pallocator_count);}
template<class U>count_allocator(const count_allocator<U>& x):
super(x),
pelement_count(x.pelement_count),pallocator_count(x.pallocator_count)
{++(*pallocator_count);}
~count_allocator()
{--(*pallocator_count);}
count_allocator& operator=(const count_allocator<T>& x)
{
pelement_count=x.pelement_count;
pallocator_count=x.pallocator_count;
return *this;
}
T* allocate(std::size_t n)
{
*pelement_count+=n;
return super::allocate(n);
}
void deallocate(T* p,std::size_t n)
{
super::deallocate(p,n);
*pelement_count-=n;
}
std::size_t* pelement_count;
std::size_t* pallocator_count;
};
#endif

View File

@@ -110,10 +110,12 @@ public:
typedef T value_type;
template<class U>struct rebind{typedef non_std_allocator<U> other;};
non_std_allocator(){}
non_std_allocator(const non_std_allocator<T>&){}
template<class U>non_std_allocator(const non_std_allocator<U>&,int=0){}
non_std_allocator& operator=(const non_std_allocator<T>&){return *this;}
non_std_allocator(int id_=0):id(id_){}
non_std_allocator(const non_std_allocator<T>& x):id(x.id){}
template<class U>non_std_allocator(const non_std_allocator<U>& x,int=0):
id(x.id){}
non_std_allocator& operator=(const non_std_allocator<T>& x)
{id=x.id; return *this;}
pointer allocate(size_type n)
{
@@ -127,15 +129,17 @@ public:
size_type max_size() const{return (size_type )(-1);}
friend bool operator==(const non_std_allocator&,const non_std_allocator&)
friend bool operator==(const non_std_allocator& x,const non_std_allocator& y)
{
return true;
return x.id==y.id;
}
friend bool operator!=(const non_std_allocator&,const non_std_allocator&)
friend bool operator!=(const non_std_allocator& x,const non_std_allocator& y)
{
return false;
return !(x==y);
}
int id;
};
#endif

View File

@@ -23,6 +23,7 @@
#include "test_list_ops.hpp"
#include "test_modifiers.hpp"
#include "test_mpl_ops.hpp"
#include "test_node_handling.hpp"
#include "test_observers.hpp"
#include "test_projection.hpp"
#include "test_range.hpp"
@@ -50,6 +51,7 @@ int main()
test_list_ops();
test_modifiers();
test_mpl_ops();
test_node_handling();
test_observers();
test_projection();
test_range();

382
test/test_node_handling.cpp Normal file
View File

@@ -0,0 +1,382 @@
/* Boost.MultiIndex test for node handling operations.
*
* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#include "test_node_handling.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/detail/lightweight_test.hpp>
#include <boost/move/core.hpp>
#include "pre_multi_index.hpp"
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/random_access_index.hpp>
#include <boost/multi_index/ranked_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/next_prior.hpp>
#include <boost/type_traits/integral_constant.hpp>
#include <functional>
#include "count_allocator.hpp"
using namespace boost::multi_index;
void test_node_handle()
{
typedef count_allocator<int> allocator;
typedef multi_index_container<
int,
indexed_by<
ordered_unique<identity<int> >
>,
allocator
> container;
typedef container::node_type node_type;
std::size_t element_count=0,allocator_count=0;
container c((allocator(element_count,allocator_count)));
element_count=0; /* ignore non element-related allocations */
allocator_count=0; /* ignore internal allocator(s) */
c.insert(0);
c.insert(1);
c.insert(2);
const int* addr0=&*c.find(0);
const int* addr1=&*c.find(1);
BOOST_TEST(element_count==3);
node_type n1;
BOOST_TEST(n1.empty());
BOOST_TEST(!n1);
BOOST_TEST(allocator_count==0);
node_type n2=c.extract(0);
BOOST_TEST(!n2.empty());
BOOST_TEST((bool)n2);
BOOST_TEST(n2.value()==0);
BOOST_TEST(&n2.value()==addr0);
BOOST_TEST(allocator_count==1);
node_type n3(boost::move(n2));
BOOST_TEST(n2.empty());
BOOST_TEST(!n3.empty());
BOOST_TEST(&n3.value()==addr0);
BOOST_TEST(allocator_count==1);
node_type n4(boost::move(n2));
BOOST_TEST(n4.empty());
BOOST_TEST(allocator_count==1);
n1=boost::move(n3);
BOOST_TEST(!n1.empty());
BOOST_TEST(&n1.value()==addr0);
BOOST_TEST(n3.empty());
BOOST_TEST(allocator_count==1);
BOOST_TEST(n1.get_allocator()==c.get_allocator());
node_type n5=c.extract(1);
BOOST_TEST(n5.value()==1);
BOOST_TEST(&n5.value()==addr1);
BOOST_TEST(allocator_count==2);
n1.swap(n5);
BOOST_TEST(&n1.value()==addr1);
BOOST_TEST(&n5.value()==addr0);
BOOST_TEST(allocator_count==2);
using std::swap;
swap(n2,n3);
BOOST_TEST(n2.empty());
BOOST_TEST(n3.empty());
BOOST_TEST(allocator_count==2);
swap(n1,n2);
BOOST_TEST(!n2.empty());
BOOST_TEST(&n2.value()==addr1);
BOOST_TEST(allocator_count==2);
swap(n1,n2);
BOOST_TEST(&n1.value()==addr1);
BOOST_TEST(n2.empty());
BOOST_TEST(allocator_count==2);
n2=boost::move(n3);
BOOST_TEST(n2.empty());
BOOST_TEST(n3.empty());
BOOST_TEST(allocator_count==2);
BOOST_TEST(element_count==3);
n1=boost::move(n5);
BOOST_TEST(&n1.value()==addr0);
BOOST_TEST(n5.empty());
BOOST_TEST(element_count==2);
BOOST_TEST(allocator_count==1);
n1=boost::move(n5);
BOOST_TEST(n1.empty());
BOOST_TEST(element_count==1);
BOOST_TEST(allocator_count==0);
c.extract(2);
BOOST_TEST(element_count==0);
}
template<typename Index>
struct is_key_based:boost::integral_constant<
bool,
/* rather fragile if new index types are included in the library */
(boost::tuples::length<typename Index::ctor_args>::value > 0)
>
{};
template<typename Dst,typename Ret,typename NodeHandle,typename Value>
void test_transfer_result(Dst&,Ret res,const NodeHandle& n,const Value& x)
{
BOOST_TEST(*(res.position)==x);
if(res.inserted){
BOOST_TEST(res.node.empty());
}
else{
BOOST_TEST(res.node.value()==x);
}
BOOST_TEST(n.empty());
}
template<typename Dst,typename NodeHandle,typename Value>
void test_transfer_result(
Dst&,typename Dst::iterator res,const NodeHandle& n,const Value& x)
{
BOOST_TEST(*res==x);
if(n)BOOST_TEST(n.value()==x);
}
template<typename Dst,typename Ret>
void test_transfer_result_empty(Dst& dst,Ret res)
{
BOOST_TEST(res.position==dst.end());
BOOST_TEST(!res.inserted);
BOOST_TEST(res.node.empty());
}
template<typename Dst>
void test_transfer_result_empty(Dst& dst,typename Dst::iterator res)
{
BOOST_TEST(res==dst.end());
}
template<typename Dst,typename Ret,typename NodeHandle,typename Value>
void test_transfer_result(
Dst& dst,typename Dst::iterator pos,Ret res,
const NodeHandle& n,const Value& x)
{
if(res.inserted&&pos!=dst.end()&&
(!is_key_based<Dst>::value||*pos==x)){
BOOST_TEST(boost::next(res.position)==pos);
}
test_transfer_result(dst,boost::move(res),n,x);
}
template<typename Dst,typename NodeHandle,typename Value>
void test_transfer_result(
Dst& dst,typename Dst::iterator pos,
typename Dst::iterator res,const NodeHandle& n,const Value& x)
{
if(n.empty()&&pos!=dst.end()&&
(!is_key_based<Dst>::value||*pos==x)){
BOOST_TEST(boost::next(res)==pos);
}
test_transfer_result(dst,res,n,x);
}
template<typename Dst,typename Ret>
void test_transfer_result_empty(Dst& dst,typename Dst::iterator,Ret res)
{
test_transfer_result_empty(dst,boost::move(res));
}
template<typename Dst>
void test_transfer_result_empty(
Dst& dst,typename Dst::iterator pos,typename Dst::iterator res)
{
test_transfer_result_empty(dst,res);
}
template<typename Src,typename Key>
typename Src::node_type checked_extract(Src& src,Key k)
{
Src::node_type n=src.extract(k);
if(n)BOOST_TEST(src.key_extractor()(n.value())==k);
return boost::move(n);
}
template<typename Src>
typename Src::node_type checked_extract(Src& src,typename Src::iterator pos)
{
typename Src::value_type x=*pos;
Src::node_type n=src.extract(pos);
if(n)BOOST_TEST(n.value()==x);
return boost::move(n);
}
template<typename Src,typename Locator,typename Dst>
void test_transfer(Src& src,Locator loc,Dst& dst)
{
typename Dst::node_type n=checked_extract(src,loc);
if(n){
typename Dst::value_type x=n.value();
test_transfer_result(dst,dst.insert(boost::move(n)),n,x);
}
else{
test_transfer_result_empty(dst,dst.insert(boost::move(n)));
}
}
template<typename Src,typename Locator,typename Dst,typename Iterator>
void test_transfer(Src& src,Locator loc,Dst& dst,Iterator pos)
{
typename Dst::node_type n=checked_extract(src,loc);
if(n){
typename Dst::value_type x=n.value();
test_transfer_result(dst,pos,dst.insert(pos,boost::move(n)),n,x);
}
else{
test_transfer_result_empty(dst,pos,dst.insert(pos,boost::move(n)));
}
}
template<typename Src,typename Dst>
void test_transfer(
Src& src,Dst& dst0,Dst& /* dst1 */,Dst& /* dst2 */,Dst& /* dst3 */,
boost::false_type /* Src key-based */,boost::false_type /* Dst key-based */)
{
test_transfer(src,src.begin(),dst0,dst0.begin());
test_transfer(src,src.begin(),dst0,dst0.begin());
for(int i=0;i<6;++i)src.extract(src.begin());
}
template<typename Src,typename Dst>
void test_transfer(
Src& src,Dst& dst0,Dst& dst1,Dst& /* dst2 */,Dst& /* dst3 */,
boost::false_type /* Src key-based */,boost::true_type /* Dst key-based */)
{
test_transfer(src,src.begin(),dst0);
test_transfer(src,src.begin(),dst0);
test_transfer(src,src.begin(),dst1,dst1.find(*src.begin()));
test_transfer(src,src.begin(),dst1,dst1.find(*src.begin()));
for(int i=0;i<4;++i)src.extract(src.begin());
}
template<typename Src,typename Dst>
void test_transfer(
Src& src,Dst& dst0,Dst& dst1,Dst& /* dst2 */,Dst& /* dst3 */,
boost::true_type /* Src key-based */,boost::false_type /* Dst key-based */)
{
test_transfer(src, src.begin(),dst0,dst0.begin());
test_transfer(src, src.begin(),dst0,dst0.begin());
test_transfer(src,*src.begin(),dst1,dst1.begin());
test_transfer(src,*src.begin(),dst1,dst1.begin());
test_transfer(src, -1,dst1,dst1.begin());
for(int i=0;i<4;++i)src.extract(src.begin());
}
template<typename Src,typename Dst>
void test_transfer(
Src& src,Dst& dst0,Dst& dst1,Dst& dst2,Dst& dst3,
boost::true_type /* Src key-based */,boost::true_type /* Dst key-based */)
{
test_transfer(src, src.begin(),dst0);
test_transfer(src, src.begin(),dst0);
test_transfer(src,*src.begin(),dst1);
test_transfer(src,*src.begin(),dst1);
test_transfer(src, -1,dst1);
test_transfer(src, src.begin(),dst2,dst2.find(*src.begin()));
test_transfer(src, src.begin(),dst2,dst2.find(*src.begin()));
test_transfer(src,*src.begin(),dst3,dst3.find(*src.begin()));
test_transfer(src,*src.begin(),dst3,dst3.find(*src.begin()));
test_transfer(src, -1,dst3,dst3.begin());
}
template<typename Src,typename Dst>
void test_transfer(Src& src,Dst& dst0,Dst& dst1,Dst& dst2,Dst& dst3)
{
test_transfer(
src,dst0,dst1,dst2,dst3,is_key_based<Src>(),is_key_based<Dst>());
}
void test_transfer()
{
typedef multi_index_container<
int,
indexed_by<
hashed_non_unique<identity<int> >,
ordered_non_unique<identity<int> >,
random_access<>,
sequenced<>,
ranked_non_unique<identity<int> >
>
> container1;
typedef multi_index_container<
int,
indexed_by<
hashed_non_unique<identity<int> >,
ordered_unique<identity<int>,std::greater<int> >,
random_access<>,
sequenced<>,
ranked_unique<identity<int>,std::greater<int> >
>
> container2;
container1 src;
container1::nth_index<0>::type& src0=src.get<0>();
container1::nth_index<1>::type& src1=src.get<1>();
container1::nth_index<2>::type& src2=src.get<2>();
container1::nth_index<3>::type& src3=src.get<3>();
container1::nth_index<4>::type& src4=src.get<4>();
container2 dst0,dst1,dst2,dst3;
container2::nth_index<0>::type& dst00=dst0.get<0>(),
& dst10=dst1.get<0>(),
& dst20=dst2.get<0>(),
& dst30=dst3.get<0>();
container2::nth_index<1>::type& dst01=dst0.get<1>(),
& dst11=dst1.get<1>(),
& dst21=dst2.get<1>(),
& dst31=dst3.get<1>();
container2::nth_index<2>::type& dst02=dst0.get<2>(),
& dst12=dst1.get<2>(),
& dst22=dst2.get<2>(),
& dst32=dst3.get<2>();
container2::nth_index<3>::type& dst03=dst0.get<3>(),
& dst13=dst1.get<3>(),
& dst23=dst2.get<3>(),
& dst33=dst3.get<3>();
container2::nth_index<4>::type& dst04=dst0.get<4>(),
& dst14=dst1.get<4>(),
& dst24=dst2.get<4>(),
& dst34=dst3.get<4>();
for(int i=0;i<6;++i){
for(int j=0;j<8;++j)src.insert(i);
}
test_transfer(src0,dst01,dst11,dst21,dst31);
test_transfer(src1,dst02,dst12,dst22,dst32);
test_transfer(src2,dst03,dst13,dst23,dst33);
test_transfer(src3,dst04,dst14,dst24,dst34);
test_transfer(src4,dst00,dst10,dst20,dst30);
BOOST_TEST(src.size()==8);
}
void test_node_handling()
{
test_node_handle();
test_transfer();
}

View File

@@ -0,0 +1,11 @@
/* Boost.MultiIndex test for node handling operations.
*
* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
void test_node_handling();

View File

@@ -0,0 +1,18 @@
/* Boost.MultiIndex test for node handling operations.
*
* Copyright 2003-2020 Joaquin M Lopez Munoz.
* Distributed under the Boost Software License, Version 1.0.
* (See accompanying file LICENSE_1_0.txt or copy at
* http://www.boost.org/LICENSE_1_0.txt)
*
* See http://www.boost.org/libs/multi_index for library home page.
*/
#include <boost/detail/lightweight_test.hpp>
#include "test_node_handling.hpp"
int main()
{
test_node_handling();
return boost::report_errors();
}

View File

@@ -1,6 +1,6 @@
/* Boost.MultiIndex test for safe_mode.
*
* Copyright 2003-2018 Joaquin M Lopez Munoz.
* Copyright 2003-2020 Joaquin M Lopez Munoz.
* 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)
@@ -11,6 +11,7 @@
#include "test_safe_mode.hpp"
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
#include <boost/move/core.hpp>
#include "pre_multi_index.hpp"
#include "employee.hpp"
#include "pair_of_ints.hpp"
@@ -37,9 +38,11 @@ static void local_test_safe_mode(
BOOST_APPEND_EXPLICIT_TEMPLATE_TYPE(Policy))
{
typedef typename Policy::container container;
typedef typename Policy::allocator_type allocator_type;
typedef typename Policy::index_type index_type;
typedef typename index_type::value_type value_type;
typedef typename index_type::iterator iterator;
typedef typename index_type::node_type node_type;
container c,c2;
index_type& i=Policy::index_from_container(c);
@@ -193,6 +196,21 @@ static void local_test_safe_mode(
value_type e=*it2;
CATCH_SAFE_MODE(safe_mode::invalid_iterator)
TRY_SAFE_MODE
iterator it=Policy::insert(i,Policy::another_value());
node_type nh=i.extract(it);
value_type e=*it;
(void)nh;
CATCH_SAFE_MODE(safe_mode::invalid_iterator)
TRY_SAFE_MODE
iterator it=Policy::insert(i,Policy::another_value());
node_type nh=i.extract(it);
container c3(c2,allocator_type(-1));
index_type& i3=Policy::index_from_container(c3);
Policy::insert(i3,boost::move(nh));
CATCH_SAFE_MODE(safe_mode::unequal_allocators)
/* testcase for bug reported at
* http://lists.boost.org/boost-users/2006/02/17230.php
*/
@@ -327,6 +345,7 @@ template<typename MultiIndexContainer,int N>
struct index_policy_base
{
typedef MultiIndexContainer container;
typedef typename container::allocator_type allocator_type;
typedef typename nth_index<container,N>::type index_type;
static index_type& index_from_container(container& c){return get<N>(c);}
@@ -342,6 +361,7 @@ struct key_based_index_policy_base:
typedef typename super::index_type index_type;
typedef typename index_type::value_type value_type;
typedef typename index_type::iterator iterator;
typedef typename index_type::node_type node_type;
static iterator insert(index_type& i,const value_type& v)
{
@@ -352,6 +372,11 @@ struct key_based_index_policy_base:
{
return i.insert(it,v);
}
static void insert(index_type& i,BOOST_RV_REF(node_type) nh)
{
i.insert(boost::move(nh));
}
};
template<typename MultiIndexContainer,int N>
@@ -364,6 +389,7 @@ struct non_key_based_index_policy_base:
typedef typename super::index_type index_type;
typedef typename index_type::value_type value_type;
typedef typename index_type::iterator iterator;
typedef typename index_type::node_type node_type;
static iterator insert(index_type& i,const value_type& v)
{
@@ -374,6 +400,11 @@ struct non_key_based_index_policy_base:
{
return i.insert(it,v).first;
}
static void insert(index_type& i,BOOST_RV_REF(node_type) nh)
{
i.insert(i.end(),boost::move(nh));
}
};
struct employee_set_policy_base