mirror of
https://github.com/boostorg/multi_index.git
synced 2026-01-19 04:22:11 +00:00
implemented node extraction/insertion (#27)
This commit is contained in:
@@ -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><</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>></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><</span><span class=identifier>value_type</span><span class=special>></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>&&</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>&&</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>&</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>&</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&& 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&& 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>© Copyright 2003-2017 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñ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">
|
||||
|
||||
@@ -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<Value,IndexSpecifierList1,Allocator></code> and
|
||||
<code>multi_index_container<Value,IndexSpecifierList2,Allocator></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<int N> struct nth_index</code>
|
||||
@@ -632,7 +654,7 @@ as they were specified.
|
||||
<code>nth_index<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 <= N < I</code>.
|
||||
<b>Requires:</b> <code>0 <= N < I-1</code>.
|
||||
</blockquote>
|
||||
|
||||
<code>template<typename Tag> struct index</code>
|
||||
@@ -885,7 +907,7 @@ the <code>multi_index_container</code>.<br>
|
||||
<code>template<int N> typename nth_index<N>::type& get()noexcept;</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>0 <= N < I</code>.<br>
|
||||
<b>Requires:</b> <code>0 <= N < I-1</code>.<br>
|
||||
<b>Effects:</b> Returns a reference to the
|
||||
<code>nth_index<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<int N> const typename nth_index<N>::type& get()const noexcept;</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>0 <= N < I</code>.<br>
|
||||
<b>Requires:</b> <code>0 <= N < I-1</code>.<br>
|
||||
<b>Effects:</b> Returns a <code>const</code> reference to the
|
||||
<code>nth_index<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<N>::type::iterator project(IteratorType it);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>0 <= N < I</code>. <code>IteratorType</code>
|
||||
<b>Requires:</b> <code>0 <= N < 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<N>::type::const_iterator project(IteratorType it)const;</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>0 <= N < I</code>. <code>IteratorType</code>
|
||||
<b>Requires:</b> <code>0 <= N < 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>© Copyright 2003-2020 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
||||
@@ -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<iterator></b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
|
||||
<span class=keyword>typedef</span> <b>equivalent to
|
||||
std::reverse_iterator<const_iterator></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><</span><span class=keyword>typename</span> <span class=identifier>InputIterator</span><span class=special>></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><</span><span class=identifier>value_type</span><span class=special>></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>&&</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>&&</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>&</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>&</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&& 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&& 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>© Copyright 2003-2017 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñ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">
|
||||
|
||||
@@ -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<iterator></b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
|
||||
<span class=keyword>typedef</span> <b>equivalent to
|
||||
std::reverse_iterator<const_iterator></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><</span><span class=keyword>typename</span> <span class=identifier>InputIterator</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>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><</span><span class=identifier>value_type</span><span class=special>></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>&&</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&& 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>© Copyright 2003-2018 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñ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">
|
||||
|
||||
@@ -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<iterator></b> <span class=identifier>reverse_iterator</span><span class=special>;</span>
|
||||
<span class=keyword>typedef</span> <b>equivalent to
|
||||
std::reverse_iterator<const_iterator></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><</span><span class=keyword>typename</span> <span class=identifier>InputIterator</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>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><</span><span class=identifier>value_type</span><span class=special>></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>&&</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&& 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>© Copyright 2003-2018 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñ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">
|
||||
|
||||
@@ -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>© Copyright 2003-2020 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
||||
@@ -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>© Copyright 2003-2020 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
||||
@@ -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>&</span> <span class=identifier>es</span><span class=special>,</span><span class=identifier>employee_set</span><span class=special>&</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><</span><span class=identifier>ssn</span><span class=special>>().</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><</span>
|
||||
<span class=keyword>int</span><span class=special>,</span>
|
||||
<span class=identifier>indexed_by</span><span class=special><</span>
|
||||
<span class=identifier>sequenced</span><span class=special><>,</span>
|
||||
<span class=identifier>ordered_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=special>></span>
|
||||
<span class=special>></span>
|
||||
<span class=special>></span> <span class=identifier>src</span><span class=special>;</span>
|
||||
|
||||
<span class=identifier>multi_index_container</span><span class=special><</span>
|
||||
<span class=keyword>int</span><span class=special>,</span>
|
||||
<span class=identifier>indexed_by</span><span class=special><</span>
|
||||
<span class=identifier>sequenced</span><span class=special><>,</span>
|
||||
<span class=identifier>ordered_non_unique</span><span class=special><</span><span class=identifier>identity</span><span class=special><</span><span class=keyword>int</span><span class=special>>,</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>greater</span><span class=special><</span><span class=keyword>int</span><span class=special>></span> <span class=special>></span>
|
||||
<span class=special>></span>
|
||||
<span class=special>></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>© Copyright 2003-2019 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñ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">
|
||||
|
||||
@@ -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>© Copyright 2003-2017 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñ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">
|
||||
|
||||
@@ -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
|
||||
@@ -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);}
|
||||
|
||||
237
include/boost/multi_index/detail/node_handle.hpp
Normal file
237
include/boost/multi_index/detail/node_handle.hpp
Normal 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
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
61
test/count_allocator.hpp
Normal 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
|
||||
@@ -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
|
||||
|
||||
@@ -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
382
test/test_node_handling.cpp
Normal 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();
|
||||
}
|
||||
11
test/test_node_handling.hpp
Normal file
11
test/test_node_handling.hpp
Normal 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();
|
||||
18
test/test_node_handling_main.cpp
Normal file
18
test/test_node_handling_main.cpp
Normal 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();
|
||||
}
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user