mirror of
https://github.com/boostorg/multi_index.git
synced 2025-05-09 15:04:03 +00:00
implemented merge operations (#49)
* initial draft * modified appveyor.yml for this branch * dropped BOOST_RV_REF as it doesn't handle lvalue refs * befriended index_base from all indices so as to be grant access to final_extract_for_merge_ from an external container * added rvalue ref merge (test expected to fail in C++03) * added explicit boost::move on rvalue ref for the benefit of C++03 compilers * fixed previous workaround * refactored merge algorithm into multi_index_container * added hashed_index::merge * reimplemented sequenced_index::splice(position,x) * added missing this->'s * refactored SFINAEing code * made sequenced_index::splice(position,x) exception robust * reimplemented random_access_index::splice(position,x) * micro-optimized legacy code in random_access_index::splice(position,x) * added missing #include * reimplemented sequenced_index::splice(position,x,i) * reimplemented random_access_index::splice(position,x,i) * reimplemented sequenced_index::splice(position,x,first,last) * reimplemented random_access_index::splice(position,x,first,last) * re-engineered sequenced_index::splice(position,x,i) so that it works when source and destination belong to the same container * stylistic * re-engineered random_access_index::splice(position,x,i) so that it works when source and destination belong to the same container * re-engineered sequenced_index::splice(position,x,first,last) so that it works when source and destination belong to the same container * stylistic * fixed bug in rvalue ref overload of sequenced_index::splice(position,x,first,last) * fixed internal sequenced_index::splice(position,x,first,last) across different indices * re-engineered random_access_index::splice(position,x,first,last) the same way as done with sequenced_index * replaced multi_index_container::merge_ with transfer_range_ so as to refactor some code in non-key-based indices * fixed safe mode check for different-type containers * hardened merge/splice tests * s/BOOST_RV_REF/BOOST_FWD_REF * called the right merge_different overload * fixed problem with Boost.Move C++03 perfect fwd emulation * updated (C) year * allowed intra-container full splice * required position==end() in intra-container full splice * made pointwise splice return a pair<iterator,bool> * added partial merge functionality to key-based indices plus fixed a compile-time error with legacy splice code when applied to different-type indices * suppressed unused variable * fixed wrong signature in splice memfun * made safe-mode iterators SCARY * refactored any_container_view * implemented safe iterator transfer in merge/splice * reorganized internal deps * stylistic * automatically checked iterator invalidation upon merge/splice * removed commented-out code * checked allocator equality * reimplemented random_access_index internal, cross-index splice in linear time * updated docs * reverted appveyor.yml
This commit is contained in:
parent
2a2282b270
commit
a52810fc3d
@ -1,4 +1,4 @@
|
||||
# Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
# Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
# 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)
|
||||
@ -34,4 +34,4 @@ build: off
|
||||
|
||||
test_script:
|
||||
- if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
- b2 address-model=32 libs/multi_index/test toolset=%TOOLSET% %CXXSTD%
|
||||
- b2 address-model=32 libs/multi_index/test toolset=%TOOLSET% %CXXSTD%
|
||||
|
@ -308,6 +308,16 @@ requirements.
|
||||
<span class=keyword>void</span> <span class=identifier>clear</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
|
||||
<span class=keyword>void</span> <span class=identifier>swap</span><span class=special>(</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span> <span class=keyword>void</span> <span class=identifier>merge</span><span class=special>(</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>></span> <span class=identifier>merge</span><span class=special>(</span>
|
||||
<span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>i</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=keyword>void</span> <span class=identifier>merge</span><span class=special>(</span>
|
||||
<span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>first</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>last</span><span class=special>);</span>
|
||||
|
||||
<span class=comment>// observers:</span>
|
||||
|
||||
<span class=identifier>key_from_value</span> <span class=identifier>key_extractor</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
|
||||
@ -474,7 +484,9 @@ local_iterator<br>
|
||||
const_local_iterator</code>
|
||||
|
||||
<blockquote>
|
||||
These types are forward iterators.
|
||||
These types are forward iterators. They depend only on <code>node_type</code> and whether
|
||||
the index is unique or not (this implies that, for instance, iterators to elements transferred
|
||||
from a unique index to a non-unique one will become invalid).
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="constructors">Constructors, copy and assignment</a></h4>
|
||||
@ -925,6 +937,89 @@ with <code>mod'</code> and <code>back</code> defined in such a way that
|
||||
<code>key</code> is the internal <code>KeyFromValue</code> object of the index.
|
||||
</blockquote>
|
||||
|
||||
<code>template<typename Index> void merge(Index&& x);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>. <code>get_allocator()==x.get_allocator()</code>.<br>
|
||||
<b>Effects:</b>
|
||||
<blockquote><pre>
|
||||
<span class=identifier>merge</span><span class=special>(</span><span class=identifier>x</span><span class=special>,</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</span>
|
||||
</pre></blockquote>
|
||||
</blockquote>
|
||||
|
||||
<code>
|
||||
template<typename Index> std::pair<iterator,bool> merge(<br>
|
||||
Index&& x,typename std::remove_reference_t<Index>::const_iterator i);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>. <code>get_allocator()==x.get_allocator()</code>.
|
||||
<code>i</code> is a valid dereferenceable iterator of <code>x</code>.<br>
|
||||
<b>Effects:</b> Does nothing if the source and destination containers are the same;
|
||||
otherwise, transfers the node of the element referred to by <code>i</code> into the
|
||||
<code>multi_index_container</code> to which the destination 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>
|
||||
Note that no element is copied or destroyed in the process.<br>
|
||||
<b>Postconditions:</b> If transfer succeeds, for any index in the source container
|
||||
having the same <code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to <code>*i</code>
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Returns:</b> The return value is a pair <code>p</code>. <code>p.second</code>
|
||||
is <code>true</code> if and only if transfer took place or the source and destination
|
||||
containers are the same. If <code>p.second</code> is <code>true</code>,
|
||||
<code>p.first</code> points to <code>*i</code>; 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> If the source and destination containers are the same,
|
||||
constant; otherwise, <code>O(I(n)+D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise strong.
|
||||
</blockquote>
|
||||
|
||||
<code>
|
||||
template<typename Index> void merge(<br>
|
||||
Index&& x,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator first,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator last);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>. <code>get_allocator()==x.get_allocator()</code>.
|
||||
[<code>first</code>,<code>last</code>) is a valid range of <code>x</code>.<br>
|
||||
<b>Effects:</b> Does nothing if the source and destination containers are the same;
|
||||
otherwise, for each node in [<code>first</code>,<code>last</code>), in this order,
|
||||
the node is transferred to the <code>multi_index_container</code> to which the
|
||||
destination 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>
|
||||
Note that no element is copied or destroyed in the process.<br>
|
||||
<b>Postconditions:</b> For any index in the source container having the same
|
||||
<code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to the transferred elements
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Complexity:</b> If the source and destination containers are the same,
|
||||
constant; otherwise, <code>O(m*(I(n+m)+D(x.size())))</code>, where
|
||||
<code>m</code> is the number of elements in [<code>first</code>,
|
||||
<code>last</code>).<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise basic.
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="observers">Observers</a></h4>
|
||||
|
||||
<p>Apart from standard <code>hash_function</code> and <code>key_eq</code>,
|
||||
@ -1275,7 +1370,7 @@ Sequenced indices
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised July 29th 2021</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
@ -42,6 +42,7 @@ Ranked indices
|
||||
<ul>
|
||||
<li><a href="#complexity_signature">Complexity signature</a></li>
|
||||
<li><a href="#instantiation_types">Instantiation types</a></li>
|
||||
<li><a href="#types">Nested types</a></li>
|
||||
<li><a href="#constructors">Constructors, copy and assignment</a></li>
|
||||
<li><a href="#iterators">Iterators</a></li>
|
||||
<li><a href="#modifiers">Modifiers</a></li>
|
||||
@ -310,6 +311,16 @@ do not exactly conform to or are not mandated by the standard requirements.
|
||||
<span class=keyword>void</span> <span class=identifier>swap</span><span class=special>(</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>void</span> <span class=identifier>clear</span><span class=special>()</span><span class=keyword>noexcept</span><span class=special>;</span>
|
||||
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span> <span class=keyword>void</span> <span class=identifier>merge</span><span class=special>(</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>></span> <span class=identifier>merge</span><span class=special>(</span>
|
||||
<span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span><span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>i</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=keyword>void</span> <span class=identifier>merge</span><span class=special>(</span>
|
||||
<span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>first</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>last</span><span class=special>);</span>
|
||||
|
||||
<span class=comment>// observers:</span>
|
||||
|
||||
<span class=identifier>key_from_value</span> <span class=identifier>key_extractor</span><span class=special>()</span><span class=keyword>const</span><span class=special>;</span>
|
||||
@ -465,6 +476,15 @@ must be a model of <a href="key_extraction.html#key_extractors">
|
||||
on elements of <code>KeyFromValue::result_type</code>.
|
||||
</p>
|
||||
|
||||
<h4><a name="types">Nested types</a></h4>
|
||||
|
||||
<code>iterator<br>
|
||||
const_iterator</code>
|
||||
|
||||
<blockquote>
|
||||
These types depend only on <code>node_type</code>.
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="constructors">Constructors, copy and assignment</a></h4>
|
||||
|
||||
<p>
|
||||
@ -911,6 +931,89 @@ with <code>mod'</code> and <code>back</code> defined in such a way that
|
||||
<code>key</code> is the internal <code>KeyFromValue</code> object of the index.
|
||||
</blockquote>
|
||||
|
||||
<a name="merge"><code>template<typename Index> void merge(Index&& x);</code></a>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>. <code>get_allocator()==x.get_allocator()</code>.<br>
|
||||
<b>Effects:</b>
|
||||
<blockquote><pre>
|
||||
<span class=identifier>merge</span><span class=special>(</span><span class=identifier>x</span><span class=special>,</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</span>
|
||||
</pre></blockquote>
|
||||
</blockquote>
|
||||
|
||||
<code>
|
||||
template<typename Index> std::pair<iterator,bool> merge(<br>
|
||||
Index&& x,typename std::remove_reference_t<Index>::const_iterator i);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>. <code>get_allocator()==x.get_allocator()</code>.
|
||||
<code>i</code> is a valid dereferenceable iterator of <code>x</code>.<br>
|
||||
<b>Effects:</b> Does nothing if the source and destination containers are the same;
|
||||
otherwise, transfers the node of the element referred to by <code>i</code> into the
|
||||
<code>multi_index_container</code> to which the destination 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>
|
||||
Note that no element is copied or destroyed in the process.<br>
|
||||
<b>Postconditions:</b> If transfer succeeds, for any index in the source container
|
||||
having the same <code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to <code>*i</code>
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Returns:</b> The return value is a pair <code>p</code>. <code>p.second</code>
|
||||
is <code>true</code> if and only if transfer took place or the source and destination
|
||||
containers are the same. If <code>p.second</code> is <code>true</code>,
|
||||
<code>p.first</code> points to <code>*i</code>; 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> If the source and destination containers are the same,
|
||||
constant; otherwise, <code>O(I(n)+D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise strong.
|
||||
</blockquote>
|
||||
|
||||
<code>
|
||||
template<typename Index> void merge(<br>
|
||||
Index&& x,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator first,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator last);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>. <code>get_allocator()==x.get_allocator()</code>.
|
||||
[<code>first</code>,<code>last</code>) is a valid range of <code>x</code>.<br>
|
||||
<b>Effects:</b> Does nothing if the source and destination containers are the same;
|
||||
otherwise, for each node in [<code>first</code>,<code>last</code>), in this order,
|
||||
the node is transferred to the <code>multi_index_container</code> to which the
|
||||
destination 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>
|
||||
Note that no element is copied or destroyed in the process.<br>
|
||||
<b>Postconditions:</b> For any index in the source container having the same
|
||||
<code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to the transferred elements
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Complexity:</b> If the source and destination containers are the same,
|
||||
constant; otherwise, <code>O(m*(I(n+m)+D(x.size())))</code>, where
|
||||
<code>m</code> is the number of elements in [<code>first</code>,
|
||||
<code>last</code>).<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise basic.
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="observers">Observers</a></h4>
|
||||
|
||||
<p>Apart from standard <code>key_comp</code> and <code>value_comp</code>,
|
||||
@ -1237,7 +1340,7 @@ Ranked indices
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised July 29th 2021</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
@ -40,6 +40,7 @@ Key extraction
|
||||
<ul>
|
||||
<li><a href="#complexity_signature">Complexity signature</a></li>
|
||||
<li><a href="#instantiation_types">Instantiation types</a></li>
|
||||
<li><a href="#types">Nested types</a></li>
|
||||
<li><a href="#constructors">Constructors, copy and assignment</a></li>
|
||||
<li><a href="#iterators">Iterators</a></li>
|
||||
<li><a href="#capacity">Capacity operations</a></li>
|
||||
@ -316,10 +317,16 @@ plus the requirements for <code>std::list</code> specific list operations at
|
||||
|
||||
<span class=comment>// list operations:</span>
|
||||
|
||||
<span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</span><span class=special>,</span><span class=identifier>iterator</span> <span class=identifier>i</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span> <span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>></span> <span class=identifier>splice</span><span class=special>(</span>
|
||||
<span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>i</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span>
|
||||
<span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</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>
|
||||
<span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>first</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>last</span><span class=special>);</span>
|
||||
|
||||
<span class=keyword>void</span> <span class=identifier>remove</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&</span> <span class=identifier>value</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Predicate</span><span class=special>></span> <span class=keyword>void</span> <span class=identifier>remove_if</span><span class=special>(</span><span class=identifier>Predicate</span> <span class=identifier>pred</span><span class=special>);</span>
|
||||
@ -450,6 +457,15 @@ index specifier. Instantiations are dependent on the following types:
|
||||
<a href="indices.html#tag"><code>tag</code></a>.
|
||||
</p>
|
||||
|
||||
<h4><a name="types">Nested types</a></h4>
|
||||
|
||||
<code>iterator<br>
|
||||
const_iterator</code>
|
||||
|
||||
<blockquote>
|
||||
These types depend only on <code>node_type</code>.
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="constructors">Constructors, copy and assignment</a></h4>
|
||||
|
||||
<p>
|
||||
@ -875,56 +891,116 @@ The syntax and behavior of these operations exactly matches those
|
||||
of sequenced indices, but the associated complexity bounds differ in general.
|
||||
</p>
|
||||
|
||||
<code>void splice(iterator position,<b>index class name</b>& x);</code>
|
||||
<code>template<typename Index> void splice(const_iterator position,Index&& x);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>position</code> is a valid iterator of the index.
|
||||
<code>&x!=this</code>.<br>
|
||||
<b>Effects:</b> Inserts the contents of <code>x</code> before <code>position</code>,
|
||||
in the same order as they were in <code>x</code>. Those elements successfully
|
||||
inserted are erased from <code>x</code>.<br>
|
||||
<b>Complexity:</b> <code>O(shl(end()-position,x.size()) + x.size()*I(n+x.size()) + x.size()*D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> Basic.<br>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>.
|
||||
<code>position</code> is a valid iterator of the index, and must be exactly <code>end()</code>
|
||||
if the source and destination containers are the same.<br>
|
||||
<b>Effects:</b>
|
||||
<blockquote><pre>
|
||||
<span class=identifier>splice</span><span class=special>(</span><span class=identifier>position</span><span class=special>,</span><span class=identifier>x</span><span class=special>,</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</span>
|
||||
</pre></blockquote>
|
||||
</blockquote>
|
||||
|
||||
<code>void splice(iterator position,<b>index class name</b>& x,iterator i);</code>
|
||||
<code>
|
||||
template<typename Index> std::pair<iterator,bool> splice(<br>
|
||||
const_iterator position,Index&& x,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator i);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>position</code> is a valid iterator of the index.
|
||||
<code>i</code> is a valid dereferenceable iterator <code>x</code>.<br>
|
||||
<b>Effects:</b> Inserts the element pointed to by <code>i</code> before
|
||||
<code>position</code>: if insertion is successful, the element is erased from
|
||||
<code>x</code>. In the special case <code>&x==this</code>, no copy or
|
||||
deletion is performed, and the operation is always successful. If
|
||||
<code>position==i</code>, no operation is performed.<br>
|
||||
<b>Postconditions:</b> If <code>&x==this</code>, no iterator or reference
|
||||
is invalidated.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, <code>O(rel(position,i,i+1))</code>;
|
||||
otherwise <code>O(shl(end()-position,1) + I(n) + D(n))</code>.<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
otherwise, strong.<br>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>.
|
||||
If <code>get_allocator()!=x.get_allocator()</code>,
|
||||
<code>value_type</code> must be <code>CopyInsertable</code> into the destination
|
||||
<code>multi_index_container</code>.
|
||||
<code>position</code> is a valid iterator of the index.
|
||||
<code>i</code> is a valid dereferenceable iterator of <code>x</code>.<br>
|
||||
<b>Effects:</b>
|
||||
<ul>
|
||||
<li><b>(Same container)</b> if the source and destination containers are the same, repositions
|
||||
the element pointed to by <code>i</code> before <code>position</code> unless both
|
||||
iterators refer to the same element.</li>
|
||||
<li><b>(Transfer splice)</b> else, if <code>get_allocator()==x.get_allocator()</code>,
|
||||
transfers the node of the element referred to by <code>i</code> into the
|
||||
destination <code>multi_index_container</code> right before <code>position</code>
|
||||
if insertion is allowed by all other indices of the <code>multi_index_container</code>.</li>
|
||||
<li><b>(Destructive splice)</b> else, insertion of <code>*i</code> is tried before
|
||||
<code>position</code>; if the operation is successful, the element is erased from <code>x</code>.
|
||||
</li>
|
||||
</ul>
|
||||
<b>Postconditions:</b> If transfer succeeds, for any index in the source container
|
||||
having the same <code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to <code>*i</code>
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Returns:</b> The return value is a pair <code>p</code>. <code>p.second</code>
|
||||
is <code>true</code> if and only if insertion (either through transfer or copy insertion)
|
||||
took place or the source and destination containers are the same.
|
||||
If <code>p.second</code> is <code>true</code>,
|
||||
<code>p.first</code> points to the inserted element or to <code>*i</code> if the
|
||||
source and destination containers are the same; 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> If the source and destination containers are the same,
|
||||
<code>O(rel(position,i',i'+1))</code>, where <code>i'</code> is the projection
|
||||
of <code>i</code> into the index of <code>position</code>;
|
||||
otherwise, <code>O(shl(end()-position,1) + I(n) + D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise strong.<br>
|
||||
<b>Implementation note:</b> The destructive variant of this operation is provided
|
||||
for reasons of backwards compatibility with previous versions of this library where
|
||||
allocator equality was not required.
|
||||
</blockquote>
|
||||
|
||||
<code>void splice(iterator position,<b>index class name&</b> x,iterator first,iterator last);</code>
|
||||
<code>
|
||||
template<typename Index> void splice(<br>
|
||||
const_iterator position,Index&& x,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator first,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator last);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>position</code> is a valid iterator of the index.
|
||||
<code>first</code> and <code>last</code> are valid iterators of <code>x</code>.
|
||||
<code>last</code> is reachable from <code>first</code>. <code>position</code>
|
||||
is not in the range [<code>first</code>,<code>last</code>).<br>
|
||||
<b>Effects:</b> For each element in the range [<code>first</code>,<code>last</code>),
|
||||
insertion is tried before <code>position</code>; if the operation is successful,
|
||||
the element is erased from <code>x</code>. In the special case
|
||||
<code>&x==this</code>, no copy or deletion is performed, and insertions are
|
||||
always successful.<br>
|
||||
<b>Postconditions:</b> If <code>&x==this</code>, no iterator or reference
|
||||
is invalidated.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>,
|
||||
<code>O(rel(position,first,last))</code>; otherwise
|
||||
<code>O(shl(end()-position,m) + m*I(n+m) + m*D(x.size()))</code>
|
||||
where <code>m</code> is the number of elements in [<code>first</code>,<code>last</code>).<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
otherwise, basic.<br>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>.
|
||||
If <code>get_allocator()!=x.get_allocator()</code>,
|
||||
<code>value_type</code> must be <code>CopyInsertable</code> into the destination
|
||||
<code>multi_index_container</code>.
|
||||
<code>position</code> is a valid iterator of the index and does not point to any element in
|
||||
[<code>first</code>,<code>last</code>).
|
||||
[<code>first</code>,<code>last</code>) is a valid range of <code>x</code>.<br>
|
||||
<b>Effects:</b>
|
||||
<ul>
|
||||
<li><b>(Same container)</b> if the source and destination containers are the same, repositions all the elements
|
||||
of [<code>first</code>,<code>last</code>), in this order, before <code>position</code>.
|
||||
</li>
|
||||
<li><b>(Transfer splice)</b> else, if <code>get_allocator()==x.get_allocator()</code>, then, for each node in
|
||||
[<code>first</code>,<code>last</code>), in this order, the node is transferred to the
|
||||
<code>multi_index_container</code> right before <code>position</code>
|
||||
if insertion is allowed by all other indices of the
|
||||
<code>multi_index_container</code>.</li>
|
||||
<li><b>(Destructive splice)</b> else, for each element in [<code>first</code>,<code>last</code>), in this order,
|
||||
insertion is tried before <code>position</code>; if the operation is successful, the
|
||||
element is erased from <code>x</code>.
|
||||
</li>
|
||||
</ul>
|
||||
<b>Postconditions:</b> For any index in the source container having the same
|
||||
<code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to the transferred elements
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, <code>O(rel(position,first,last))</code>;
|
||||
else, if the source and destination containers are the same, <code>O(n)</code>;
|
||||
otherwise, <code>O(shl(end()-position,m) + m*(I(n+m) + D(x.size())))</code>, where
|
||||
<code>m</code> is the number of elements in [<code>first</code>,<code>last</code>).<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise basic.<br>
|
||||
<b>Implementation note:</b> The destructive variant of this operation is provided
|
||||
for reasons of backwards compatibility with previous versions of this library where
|
||||
allocator equality was not required.
|
||||
</blockquote>
|
||||
|
||||
<code>void remove(const value_type& value);</code>
|
||||
@ -973,20 +1049,22 @@ is the number of elements erased.<br>
|
||||
<code>void merge(index class name& x);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>std::less<value_type></code> induces a
|
||||
<b>Requires:</b>
|
||||
Either <code>get_allocator()==x.get_allocator()</code> or <code>value_type</code>
|
||||
is <code>CopyInsertable</code> into the <code>multi_index_container</code>.
|
||||
<code>std::less<value_type></code> induces a
|
||||
strict weak ordering over <code>value_type</code>.
|
||||
Both the index and <code>x</code> are sorted according to
|
||||
<code>std::less<value_type></code>.<br>
|
||||
<b>Effects:</b> Attempts to insert every element of <code>x</code> into the
|
||||
corresponding position of the index (according to the order). Elements
|
||||
successfully inserted are erased from <code>x</code>. The resulting sequence
|
||||
<b>Effects:</b> Attempts to splice every element of <code>x</code> into the
|
||||
corresponding position of the index (according to the order). The resulting sequence
|
||||
is stable, i.e. equivalent elements of either container preserve their
|
||||
relative position. In the special case <code>&x==this</code>, no operation
|
||||
is performed.<br>
|
||||
<b>Postconditions:</b> Elements in the index and remaining elements in
|
||||
<code>x</code> are sorted.
|
||||
Validity of iterators to the index and of non-erased elements of <code>x</code>
|
||||
references is preserved.<br>
|
||||
Validity of iterators and references is preserved, except to elements removed
|
||||
from <code>x</code> if <code>get_allocator()!=x.get_allocator()</code>.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; otherwise
|
||||
<code>O(n + x.size()*I(n+x.size()) + x.size()*D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
@ -996,19 +1074,20 @@ otherwise, basic.<br>
|
||||
<code>template <typename Compare> void merge(index class name& x,Compare comp);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>Compare</code> induces a
|
||||
strict weak ordering over <code>value_type</code>.
|
||||
<b>Requires:</b>
|
||||
Either <code>get_allocator()==x.get_allocator()</code> or <code>value_type</code>
|
||||
is <code>CopyInsertable</code> into the <code>multi_index_container</code>.
|
||||
<code>Compare</code> induces a strict weak ordering over <code>value_type</code>.
|
||||
Both the index and <code>x</code> are sorted according to <code>comp</code>.<br>
|
||||
<b>Effects:</b> Attempts to insert every element of <code>x</code> into the
|
||||
corresponding position of the index (according to <code>comp</code>).
|
||||
Elements successfully inserted are erased from <code>x</code>. The resulting
|
||||
<b>Effects:</b> Attempts to splice every element of <code>x</code> into the
|
||||
corresponding position of the index (according to <code>comp</code>). The resulting
|
||||
sequence is stable, i.e. equivalent elements of either container preserve
|
||||
their relative position. In the special case <code>&x==this</code>, no
|
||||
operation is performed.<br>
|
||||
<b>Postconditions:</b> Elements in the index and remaining elements in
|
||||
<code>x</code> are sorted according to <code>comp</code>.
|
||||
Validity of iterators to the index and of non-erased elements of <code>x</code>
|
||||
references is preserved.<br>
|
||||
Validity of iterators and references is preserved, except to elements removed
|
||||
from <code>x</code> if <code>get_allocator()!=x.get_allocator()</code>.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; otherwise
|
||||
<code>O(n + x.size()*I(n+x.size()) + x.size()*D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
@ -1160,9 +1239,9 @@ Key extraction
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised May 9th 2020</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2021 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">
|
||||
|
@ -42,6 +42,7 @@ Hashed indices
|
||||
<ul>
|
||||
<li><a href="#complexity_signature">Complexity signature</a></li>
|
||||
<li><a href="#instantiation_types">Instantiation types</a></li>
|
||||
<li><a href="#types">Nested types</a></li>
|
||||
<li><a href="#rank_operations">Rank operations</a></li>
|
||||
<li><a href="#serialization">Serialization</a></li>
|
||||
</ul>
|
||||
@ -473,6 +474,15 @@ These types are subject to the same requirements as specified for
|
||||
<a href="ord_indices.html#instantiation_types">ordered indices</a>.
|
||||
</p>
|
||||
|
||||
<h4><a name="types">Nested types</a></h4>
|
||||
|
||||
<code>iterator<br>
|
||||
const_iterator</code>
|
||||
|
||||
<blockquote>
|
||||
These types depend only on <code>node_type</code>.
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="rank_operations">Rank operations</a></h4>
|
||||
|
||||
<p>
|
||||
@ -637,7 +647,7 @@ Hashed indices
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised July 29th 2021</p>
|
||||
<p>Revised August 14th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
@ -40,6 +40,7 @@ Random access indices
|
||||
<ul>
|
||||
<li><a href="#complexity_signature">Complexity signature</a></li>
|
||||
<li><a href="#instantiation_types">Instantiation types</a></li>
|
||||
<li><a href="#types">Nested types</a></li>
|
||||
<li><a href="#constructors">Constructors, copy and assignment</a></li>
|
||||
<li><a href="#iterators">Iterators</a></li>
|
||||
<li><a href="#capacity">Capacity operations</a></li>
|
||||
@ -299,10 +300,16 @@ most important differences are:
|
||||
|
||||
<span class=comment>// list operations:</span>
|
||||
|
||||
<span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span><span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</span><span class=special>,</span><span class=identifier>iterator</span> <span class=identifier>i</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span> <span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span><span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=identifier>std</span><span class=special>::</span><span class=identifier>pair</span><span class=special><</span><span class=identifier>iterator</span><span class=special>,</span><span class=keyword>bool</span><span class=special>></span> <span class=identifier>splice</span><span class=special>(</span>
|
||||
<span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>i</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Index</span><span class=special>></span>
|
||||
<span class=keyword>void</span> <span class=identifier>splice</span><span class=special>(</span>
|
||||
<span class=identifier>iterator</span> <span class=identifier>position</span><span class=special>,</span><b>index class name</b><span class=special>&</span> <span class=identifier>x</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>
|
||||
<span class=identifier>const_iterator</span> <span class=identifier>position</span><span class=special>,</span><span class=identifier>Index</span><span class=special>&&</span> <span class=identifier>x</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>first</span><span class=special>,</span>
|
||||
<span class=keyword>typename</span> <span class=identifier>std</span><span class=special>::</span><span class=identifier>remove_reference_t</span><span class=special><</span><span class=identifier>Index</span><span class=special>>::</span><span class=identifier>const_iterator</span> <span class=identifier>last</span><span class=special>);</span>
|
||||
|
||||
<span class=keyword>void</span> <span class=identifier>remove</span><span class=special>(</span><span class=keyword>const</span> <span class=identifier>value_type</span><span class=special>&</span> <span class=identifier>value</span><span class=special>);</span>
|
||||
<span class=keyword>template</span><span class=special><</span><span class=keyword>typename</span> <span class=identifier>Predicate</span><span class=special>></span> <span class=keyword>void</span> <span class=identifier>remove_if</span><span class=special>(</span><span class=identifier>Predicate</span> <span class=identifier>pred</span><span class=special>);</span>
|
||||
@ -420,6 +427,15 @@ index specifier. Instantiations are dependent on the following types:
|
||||
<a href="indices.html#tag"><code>tag</code></a>.
|
||||
</p>
|
||||
|
||||
<h4><a name="types">Nested types</a></h4>
|
||||
|
||||
<code>iterator<br>
|
||||
const_iterator</code>
|
||||
|
||||
<blockquote>
|
||||
These types depend only on <code>node_type</code>.
|
||||
</blockquote>
|
||||
|
||||
<h4><a name="constructors">Constructors, copy and assignment</a></h4>
|
||||
|
||||
<p>
|
||||
@ -802,62 +818,122 @@ is rethrown.
|
||||
|
||||
<p>
|
||||
Sequenced indices provide the full set of list operations found in
|
||||
<code>std::list</code>; the semantics of these member functions, however,
|
||||
differ from that of <code>std::list</code> in some cases as insertions
|
||||
might not succeed due to banning by other indices. Similarly, the complexity
|
||||
<code>std::list</code>, extended in some cases such as <code>splice</code>;
|
||||
the semantics of these member functions, however,
|
||||
typically differs from that of <code>std::list</code> as insertions
|
||||
may not succeed due to banning by other indices. Similarly, the complexity
|
||||
of the operations may depend on the other indices belonging to the
|
||||
same <code>multi_index_container</code>.
|
||||
</p>
|
||||
|
||||
<code>void splice(iterator position,<b>index class name</b>& x);</code>
|
||||
<a name="splice"><code>template<typename Index> void splice(const_iterator position,Index&& x);</code></a>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>position</code> is a valid iterator of the index.
|
||||
<code>&x!=this</code>.<br>
|
||||
<b>Effects:</b> Inserts the contents of <code>x</code> before <code>position</code>,
|
||||
in the same order as they were in <code>x</code>. Those elements successfully
|
||||
inserted are erased from <code>x</code>.<br>
|
||||
<b>Complexity:</b> <code>O(x.size()*I(n+x.size()) + x.size()*D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> Basic.<br>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>.
|
||||
<code>position</code> is a valid iterator of the index, and must be exactly <code>end()</code>
|
||||
if the source and destination containers are the same.<br>
|
||||
<b>Effects:</b>
|
||||
<blockquote><pre>
|
||||
<span class=identifier>splice</span><span class=special>(</span><span class=identifier>position</span><span class=special>,</span><span class=identifier>x</span><span class=special>,</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>begin</span><span class=special>(),</span><span class=identifier>x</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</span>
|
||||
</pre></blockquote>
|
||||
</blockquote>
|
||||
|
||||
<code>void splice(iterator position,<b>index class name</b>& x,iterator i);</code>
|
||||
<code>
|
||||
template<typename Index> std::pair<iterator,bool> splice(<br>
|
||||
const_iterator position,Index&& x,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator i);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>position</code> is a valid iterator of the index.
|
||||
<code>i</code> is a valid dereferenceable iterator <code>x</code>.<br>
|
||||
<b>Effects:</b> Inserts the element pointed to by <code>i</code> before
|
||||
<code>position</code>: if insertion is successful, the element is erased from
|
||||
<code>x</code>. In the special case <code>&x==this</code>, no copy or
|
||||
deletion is performed, and the operation is always successful. If
|
||||
<code>position==i</code>, no operation is performed.<br>
|
||||
<b>Postconditions:</b> If <code>&x==this</code>, no iterator or reference
|
||||
is invalidated.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; otherwise
|
||||
<code>O(I(n) + D(n))</code>.<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
otherwise, strong.<br>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>.
|
||||
If <code>get_allocator()!=x.get_allocator()</code>,
|
||||
<code>value_type</code> must be <code>CopyInsertable</code> into the destination
|
||||
<code>multi_index_container</code>.
|
||||
<code>position</code> is a valid iterator of the index.
|
||||
<code>i</code> is a valid dereferenceable iterator of <code>x</code>.<br>
|
||||
<b>Effects:</b>
|
||||
<ul>
|
||||
<li><b>(Same container)</b> if the source and destination containers are the same, repositions
|
||||
the element pointed to by <code>i</code> before <code>position</code> unless both
|
||||
iterators refer to the same element.</li>
|
||||
<li><b>(Transfer splice)</b> else, if <code>get_allocator()==x.get_allocator()</code>,
|
||||
transfers the node of the element referred to by <code>i</code> into the
|
||||
destination <code>multi_index_container</code> right before <code>position</code>
|
||||
if insertion is allowed by all other indices of the <code>multi_index_container</code>.</li>
|
||||
<li><b>(Destructive splice)</b> else, insertion of <code>*i</code> is tried before
|
||||
<code>position</code>; if the operation is successful, the element is erased from <code>x</code>.
|
||||
</li>
|
||||
</ul>
|
||||
<b>Postconditions:</b> If transfer succeeds, for any index in the source container
|
||||
having the same <code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to <code>*i</code>
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Returns:</b> The return value is a pair <code>p</code>. <code>p.second</code>
|
||||
is <code>true</code> if and only if insertion (either through transfer or copy insertion)
|
||||
took place or the source and destination containers are the same.
|
||||
If <code>p.second</code> is <code>true</code>,
|
||||
<code>p.first</code> points to the inserted element or to <code>*i</code> if the
|
||||
source and destination containers are the same; 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> If the source and destination containers are the same,
|
||||
constant; otherwise, <code>O(I(n)+D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise strong.<br>
|
||||
<b>Implementation note:</b> The destructive variant of this operation is provided
|
||||
for reasons of backwards compatibility with previous versions of this library where
|
||||
allocator equality was not required.
|
||||
</blockquote>
|
||||
|
||||
<code>void splice(iterator position,<b>index class name&</b> x,iterator first,iterator last);</code>
|
||||
<code>
|
||||
template<typename Index> void splice(<br>
|
||||
const_iterator position,Index&& x,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator first,<br>
|
||||
typename std::remove_reference_t<Index>::const_iterator last);
|
||||
</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>position</code> is a valid iterator of the index.
|
||||
<code>first</code> and <code>last</code> are valid iterators of <code>x</code>.
|
||||
<code>last</code> is reachable from <code>first</code>. <code>position</code>
|
||||
is not in the range [<code>first</code>,<code>last</code>).<br>
|
||||
<b>Effects:</b> For each element in the range [<code>first</code>,<code>last</code>),
|
||||
insertion is tried before <code>position</code>; if the operation is successful,
|
||||
the element is erased from <code>x</code>. In the special case
|
||||
<code>&x==this</code>, no copy or deletion is performed, and insertions are
|
||||
always successful.<br>
|
||||
<b>Postconditions:</b> If <code>&x==this</code>, no iterator or reference
|
||||
is invalidated.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; otherwise
|
||||
<code>O(m*I(n+m) + m*D(x.size()))</code> where <code>m</code> is the number
|
||||
of elements in [<code>first</code>,<code>last</code>).<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
otherwise, basic.<br>
|
||||
<b>Requires:</b> <code>x</code> is a non-const reference to an index of a
|
||||
<a href="multi_index_container.html#node_type">node-compatible</a>
|
||||
<code>multi_index_container</code>.
|
||||
If <code>get_allocator()!=x.get_allocator()</code>,
|
||||
<code>value_type</code> must be <code>CopyInsertable</code> into the destination
|
||||
<code>multi_index_container</code>.
|
||||
<code>position</code> is a valid iterator of the index and does not point to any element in
|
||||
[<code>first</code>,<code>last</code>).
|
||||
[<code>first</code>,<code>last</code>) is a valid range of <code>x</code>.<br>
|
||||
<b>Effects:</b>
|
||||
<ul>
|
||||
<li><b>(Same container)</b> if the source and destination containers are the same, repositions all the elements
|
||||
of [<code>first</code>,<code>last</code>), in this order, before <code>position</code>.
|
||||
</li>
|
||||
<li><b>(Transfer splice)</b> else, if <code>get_allocator()==x.get_allocator()</code>, then, for each node in
|
||||
[<code>first</code>,<code>last</code>), in this order, the node is transferred to the
|
||||
<code>multi_index_container</code> right before <code>position</code>
|
||||
if insertion is allowed by all other indices of the
|
||||
<code>multi_index_container</code>.</li>
|
||||
<li><b>(Destructive splice)</b> else, for each element in [<code>first</code>,<code>last</code>), in this order,
|
||||
insertion is tried before <code>position</code>; if the operation is successful, the
|
||||
element is erased from <code>x</code>.
|
||||
</li>
|
||||
</ul>
|
||||
<b>Postconditions:</b> For any index in the source container having the same
|
||||
<code>iterator</code>/<code>const_iterator</code> types as the corresponding
|
||||
index in the destination container, iterators referring to the transferred elements
|
||||
remain valid and behave as iterators of the destination index.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; else, if
|
||||
the source and destination containers are the same, <code>O(m)</code>;
|
||||
otherwise, <code>O(m*(I(n+m)+D(x.size())))</code>, where
|
||||
<code>m</code> is the number of elements in [<code>first</code>,<code>last</code>).<br>
|
||||
<b>Exception safety:</b> If the source and destination containers are the same,
|
||||
<code>nothrow</code>; otherwise basic.<br>
|
||||
<b>Implementation note:</b> The destructive variant of this operation is provided
|
||||
for reasons of backwards compatibility with previous versions of this library where
|
||||
allocator equality was not required.
|
||||
</blockquote>
|
||||
|
||||
<code>void remove(const value_type& value);</code>
|
||||
@ -906,20 +982,22 @@ is the number of elements erased.<br>
|
||||
<code>void merge(index class name& x);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>std::less<value_type></code> induces a
|
||||
<b>Requires:</b>
|
||||
Either <code>get_allocator()==x.get_allocator()</code> or <code>value_type</code>
|
||||
is <code>CopyInsertable</code> into the <code>multi_index_container</code>.
|
||||
<code>std::less<value_type></code> induces a
|
||||
strict weak ordering over <code>value_type</code>.
|
||||
Both the index and <code>x</code> are sorted according to
|
||||
<code>std::less<value_type></code>.<br>
|
||||
<b>Effects:</b> Attempts to insert every element of <code>x</code> into the
|
||||
corresponding position of the index (according to the order). Elements
|
||||
successfully inserted are erased from <code>x</code>. The resulting sequence
|
||||
<b>Effects:</b> Attempts to splice every element of <code>x</code> into the
|
||||
corresponding position of the index (according to the order). The resulting sequence
|
||||
is stable, i.e. equivalent elements of either container preserve their
|
||||
relative position. In the special case <code>&x==this</code>, no operation
|
||||
is performed.<br>
|
||||
<b>Postconditions:</b> Elements in the index and remaining elements in
|
||||
<code>x</code> are sorted.
|
||||
Validity of iterators to the index and of non-erased elements of <code>x</code>
|
||||
references is preserved.<br>
|
||||
Validity of iterators and references is preserved, except to elements removed
|
||||
from <code>x</code> if <code>get_allocator()!=x.get_allocator()</code>.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; otherwise
|
||||
<code>O(n + x.size()*I(n+x.size()) + x.size()*D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
@ -929,19 +1007,20 @@ otherwise, basic.<br>
|
||||
<code>template <typename Compare> void merge(index class name& x,Compare comp);</code>
|
||||
|
||||
<blockquote>
|
||||
<b>Requires:</b> <code>Compare</code> induces a
|
||||
strict weak ordering over <code>value_type</code>.
|
||||
<b>Requires:</b>
|
||||
Either <code>get_allocator()==x.get_allocator()</code> or <code>value_type</code>
|
||||
is <code>CopyInsertable</code> into the <code>multi_index_container</code>.
|
||||
<code>Compare</code> induces a strict weak ordering over <code>value_type</code>.
|
||||
Both the index and <code>x</code> are sorted according to <code>comp</code>.<br>
|
||||
<b>Effects:</b> Attempts to insert every element of <code>x</code> into the
|
||||
corresponding position of the index (according to <code>comp</code>).
|
||||
Elements successfully inserted are erased from <code>x</code>. The resulting
|
||||
<b>Effects:</b> Attempts to splice every element of <code>x</code> into the
|
||||
corresponding position of the index (according to <code>comp</code>). The resulting
|
||||
sequence is stable, i.e. equivalent elements of either container preserve
|
||||
their relative position. In the special case <code>&x==this</code>, no
|
||||
operation is performed.<br>
|
||||
<b>Postconditions:</b> Elements in the index and remaining elements in
|
||||
<code>x</code> are sorted according to <code>comp</code>.
|
||||
Validity of iterators to the index and of non-erased elements of <code>x</code>
|
||||
references is preserved.<br>
|
||||
Validity of iterators and references is preserved, except to elements removed
|
||||
from <code>x</code> if <code>get_allocator()!=x.get_allocator()</code>.<br>
|
||||
<b>Complexity:</b> If <code>&x==this</code>, constant; otherwise
|
||||
<code>O(n + x.size()*I(n+x.size()) + x.size()*D(x.size()))</code>.<br>
|
||||
<b>Exception safety:</b> If <code>&x==this</code>, <code>nothrow</code>;
|
||||
@ -1095,9 +1174,9 @@ Random access indices
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised May 9th 2020</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2021 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">
|
||||
|
@ -72,6 +72,34 @@ Acknowledgements
|
||||
<li>Added <code>contains</code> to key-based indices
|
||||
(<a href="https://github.com/boostorg/multi_index/issues/35">issue #35</a>).
|
||||
</li>
|
||||
<li>Added <code>merge</code> operations to key-based indices. The functionality goes beyond
|
||||
the standard specification for (unordered) associative containers in a number of ways,
|
||||
most notably:
|
||||
<ul>
|
||||
<li>The source index can be of any type, including non key-based indices.</li>
|
||||
<li>Partial merge is provided: for instance, <code>x.merge(y,first,last)</code>
|
||||
merges only the elements of <code>y</code> within [<code>first</code>,<code>last</code>).
|
||||
</li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>Previous versions of <code>splice</code> for sequenced and random access indices
|
||||
were destructive, i.e. elements were copy-inserted into the destination and then erased
|
||||
from the source. Now, <code>splice</code> is based on node transfer much as <code>merge</code>
|
||||
in key-based indices, and has been similarly extended to accept source indices of any type:
|
||||
in fact, <code>splice</code> can be regarded as a frontend to the same functionality
|
||||
provided by <code>merge</code> in key-based indices. For reasons of backwards compatibility,
|
||||
the destructive behavior of <code>splice</code> has been retained in the case that the
|
||||
source and destination containers have unequal allocators.
|
||||
</li>
|
||||
<li>The fact has been documented that index iterator types do only depend on <code>node_type</code>,
|
||||
(except for hashed indices, where uniqueness/non-uniqueness is also a dependency). This has
|
||||
implications on the validity of iterators to elements transferred by <code>merge</code> or
|
||||
<code>splice</code>. This property is a variant of what has been called
|
||||
<a href="https://wg21.link/n2980">SCARY iterators</a> in the C++ standard mailing lists.
|
||||
SCARYness is currently (August 2021) not mandated for standard containers.
|
||||
</li>
|
||||
<li>Iterator SCARYness is now also preserved in <a href="tutorial/debug.html#safe_mode">safe mode</a>.
|
||||
</li>
|
||||
</ul>
|
||||
</p>
|
||||
|
||||
@ -88,7 +116,7 @@ Acknowledgements
|
||||
<p>
|
||||
<ul>
|
||||
<li>
|
||||
Added <a href="tutorial/basics.html#node_handling">node extraction and insertion</a>
|
||||
Added <a href="tutorial/indices.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 functionality.
|
||||
@ -695,7 +723,7 @@ Acknowledgements
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised July 29th 2021</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
@ -62,7 +62,6 @@ 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>
|
||||
|
||||
@ -1217,72 +1216,6 @@ 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>
|
||||
@ -1317,9 +1250,9 @@ Index types
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised May 9th 2020</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2020 Joaquín M López Muñoz.
|
||||
<p>© Copyright 2003-2021 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">
|
||||
|
@ -55,6 +55,7 @@ Key extraction
|
||||
</li>
|
||||
<li><a href="#rearrange">Index rearranging</a></li>
|
||||
<li><a href="#iterator_to"><code>iterator_to</code></a></li>
|
||||
<li><a href="#node_handling">Node handling operations</a></li>
|
||||
<li><a href="#ordered_node_compression">Ordered indices node compression</a></li>
|
||||
</ul>
|
||||
|
||||
@ -282,7 +283,7 @@ determining whether a hashed index is preferred over an ordered one.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
Hashed indices replicate the interface as <code>std::unordered_set</code> and
|
||||
Hashed indices replicate the interface of <code>std::unordered_set</code> and
|
||||
<code>std::unordered_multiset</code>, with only minor differences where required
|
||||
by the general constraints of <code>multi_index_container</code>s, and provide
|
||||
additional useful capabilities like in-place updating of elements.
|
||||
@ -774,6 +775,113 @@ in scenarios where access via iterators is not suitable or desireable:
|
||||
</ul>
|
||||
</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>// assume employee_set has an index on SS number(not shown before)</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>
|
||||
|
||||
<p>
|
||||
Alternatively, direct node transfer between two containers can be done without
|
||||
keeping intervening <code>node_type</code>s thanks to <code>merge</code> (key-based
|
||||
indices) and <code>splice</code> (non key-based indices).
|
||||
</p>
|
||||
|
||||
<blockquote><pre>
|
||||
<span class=comment>// move older employees to retirement</span>
|
||||
<span class=keyword>void</span> <span class=identifier>move_to_retirement_by_age</span><span class=special>(
|
||||
</span><span class=keyword>int</span> <span class=identifier>max_age</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>// assume employee_set has an index on age (not shown before)</span>
|
||||
<span class=identifier>employee_set_by_age</span><span class=special>&</span> <span class=identifier>ea</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>age</span><span class=special>>();</span>
|
||||
|
||||
<span class=comment>// archive employees with age>max_age</span>
|
||||
<span class=identifier>archive</span><span class=special>.</span><span class=identifier>merge</span><span class=special>(</span><span class=identifier>ea</span><span class=special>,</span><span class=identifier>ea</span><span class=special>.</span><span class=identifier>upper_bound</span><span class=special>(</span><span class=identifier>max_age</span><span class=special>),</span><span class=identifier>ea</span><span class=special>.</span><span class=identifier>end</span><span class=special>());</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>splice</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>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>
|
||||
There are overloads of <code>merge</code>/<code>splice</code> for transferring a single element,
|
||||
a range between two iterators and an entire container: for further details, consult
|
||||
for instance the reference for <a href="../reference/ord_indices.html#merge">ordered indices</a> and for
|
||||
<a href="../reference/seq_indices.html#splice">sequenced indices</a>
|
||||
(the rest of indices provide one interface or the other).
|
||||
Please note that sequenced and random access indices do also have an operation called <code>merge</code>,
|
||||
but this follows the specification of <code>std::list::merge</code>, which has a somewhat
|
||||
different behavior (source and destination are required to be ordered by the same criterion). This is
|
||||
a rather confusing naming issue that Boost.MultiIndex simply inherits from the C++ standard.
|
||||
</p>
|
||||
|
||||
<h2><a name="ordered_node_compression">Ordered indices node compression</a></h2>
|
||||
|
||||
<p>
|
||||
@ -821,7 +929,7 @@ Key extraction
|
||||
|
||||
<br>
|
||||
|
||||
<p>Revised July 29th 2021</p>
|
||||
<p>Revised August 16th 2021</p>
|
||||
|
||||
<p>© Copyright 2003-2021 Joaquín M López Muñoz.
|
||||
Distributed under the Boost Software
|
||||
|
76
include/boost/multi_index/detail/any_container_view.hpp
Normal file
76
include/boost/multi_index/detail/any_container_view.hpp
Normal file
@ -0,0 +1,76 @@
|
||||
/* Copyright 2003-2021 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_ANY_CONTAINER_VIEW_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_ANY_CONTAINER_VIEW_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* type-erased, non-owning view over a ConstIterator-container's range */
|
||||
|
||||
template<typename ConstIterator>
|
||||
class any_container_view
|
||||
{
|
||||
public:
|
||||
template<typename Container>
|
||||
any_container_view(const Container& x):px(&x),pt(vtable_for<Container>()){}
|
||||
|
||||
const void* container()const{return px;}
|
||||
ConstIterator begin()const{return pt->begin(px);}
|
||||
ConstIterator end()const{return pt->end(px);}
|
||||
|
||||
private:
|
||||
struct vtable
|
||||
{
|
||||
ConstIterator (*begin)(const void*);
|
||||
ConstIterator (*end)(const void*);
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
static ConstIterator begin_for(const void* px)
|
||||
{
|
||||
return static_cast<const Container*>(px)->begin();
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
static ConstIterator end_for(const void* px)
|
||||
{
|
||||
return static_cast<const Container*>(px)->end();
|
||||
}
|
||||
|
||||
template<typename Container>
|
||||
vtable* vtable_for()
|
||||
{
|
||||
static vtable v=
|
||||
{
|
||||
&begin_for<Container>,
|
||||
&end_for<Container>
|
||||
};
|
||||
|
||||
return &v;
|
||||
}
|
||||
|
||||
const void* px;
|
||||
vtable* pt;
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
74
include/boost/multi_index/detail/index_access_sequence.hpp
Normal file
74
include/boost/multi_index/detail/index_access_sequence.hpp
Normal file
@ -0,0 +1,74 @@
|
||||
/* Copyright 2003-2021 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_INDEX_ACCESS_SEQUENCE_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_INDEX_ACCESS_SEQUENCE_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Successive access to the indices of a multi_index_container. Used as dst in
|
||||
* backbone function extract_(x,dst) to retrieve the destination indices
|
||||
* where iterators referring to x must be transferred to (in merging operations).
|
||||
*/
|
||||
|
||||
template<typename MultiIndexContainer,int N=0>
|
||||
struct index_access_sequence;
|
||||
|
||||
struct index_access_sequence_terminal
|
||||
{
|
||||
index_access_sequence_terminal(void*){}
|
||||
};
|
||||
|
||||
template<typename MultiIndexContainer,int N>
|
||||
struct index_access_sequence_normal
|
||||
{
|
||||
MultiIndexContainer* p;
|
||||
|
||||
index_access_sequence_normal(MultiIndexContainer* p_):p(p_){}
|
||||
|
||||
typename nth_index<MultiIndexContainer,N>::type&
|
||||
get(){return p->template get<N>();}
|
||||
|
||||
index_access_sequence<MultiIndexContainer,N+1>
|
||||
next(){return index_access_sequence<MultiIndexContainer,N+1>(p);}
|
||||
};
|
||||
|
||||
template<typename MultiIndexContainer,int N>
|
||||
struct index_access_sequence_base:
|
||||
mpl::if_c<
|
||||
N<mpl::size<typename MultiIndexContainer::index_type_list>::type::value,
|
||||
index_access_sequence_normal<MultiIndexContainer,N>,
|
||||
index_access_sequence_terminal
|
||||
>
|
||||
{};
|
||||
|
||||
template<typename MultiIndexContainer,int N>
|
||||
struct index_access_sequence:
|
||||
index_access_sequence_base<MultiIndexContainer,N>::type
|
||||
{
|
||||
typedef typename index_access_sequence_base<
|
||||
MultiIndexContainer,N>::type super;
|
||||
|
||||
index_access_sequence(MultiIndexContainer* p):super(p){}
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2003-2021 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)
|
||||
@ -22,6 +22,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/index_access_sequence.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>
|
||||
@ -134,6 +135,15 @@ protected:
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename MultiIndexContainer>
|
||||
final_node_type* insert_(
|
||||
const value_type&,final_node_type*& x,MultiIndexContainer* p)
|
||||
{
|
||||
p->final_extract_for_transfer_(
|
||||
x,index_access_sequence<final_type>(&final()));
|
||||
return x;
|
||||
}
|
||||
|
||||
final_node_type* insert_(
|
||||
const value_type& v,index_node_type*,final_node_type*& x,lvalue_tag)
|
||||
{
|
||||
@ -152,7 +162,8 @@ protected:
|
||||
return x;
|
||||
}
|
||||
|
||||
void extract_(index_node_type*){}
|
||||
template<typename Dst>
|
||||
void extract_(index_node_type*,Dst){}
|
||||
|
||||
void clear_(){}
|
||||
|
||||
@ -203,6 +214,10 @@ protected:
|
||||
final_type& final(){return *static_cast<final_type*>(this);}
|
||||
const final_type& final()const{return *static_cast<const final_type*>(this);}
|
||||
|
||||
template<typename Index>
|
||||
static typename Index::final_type& final(Index& x) /* cross-index access */
|
||||
{return static_cast<typename Index::final_type&>(x);}
|
||||
|
||||
final_node_type* final_header()const{return final().header();}
|
||||
|
||||
bool final_empty_()const{return final().empty_();}
|
||||
@ -222,6 +237,10 @@ protected:
|
||||
std::pair<final_node_type*,bool> final_insert_nh_(final_node_handle_type& nh)
|
||||
{return final().insert_nh_(nh);}
|
||||
|
||||
template<typename Index>
|
||||
std::pair<final_node_type*,bool> final_transfer_(Index& x,final_node_type* n)
|
||||
{return final().transfer_(x,n);}
|
||||
|
||||
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
|
||||
std::pair<final_node_type*,bool> final_emplace_(
|
||||
BOOST_MULTI_INDEX_FUNCTION_PARAM_PACK)
|
||||
@ -260,12 +279,25 @@ protected:
|
||||
return final().extract_(x);
|
||||
}
|
||||
|
||||
template<typename Dst>
|
||||
void final_extract_for_transfer_(final_node_type* x,Dst dst)
|
||||
{
|
||||
final().extract_for_transfer_(x,dst);
|
||||
}
|
||||
|
||||
void final_erase_(final_node_type* x){final().erase_(x);}
|
||||
|
||||
void final_delete_node_(final_node_type* x){final().delete_node_(x);}
|
||||
void final_delete_all_nodes_(){final().delete_all_nodes_();}
|
||||
void final_clear_(){final().clear_();}
|
||||
|
||||
template<typename Index>
|
||||
void final_transfer_range_(
|
||||
Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{final().transfer_range_(x,first,last);}
|
||||
|
||||
void final_swap_(final_type& x){final().swap_(x);}
|
||||
|
||||
bool final_replace_(
|
||||
|
44
include/boost/multi_index/detail/invalidate_iterators.hpp
Normal file
44
include/boost/multi_index/detail/invalidate_iterators.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
/* Copyright 2003-2021 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_INVALIDATE_ITERATORS_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_INVALIDATE_ITERATORS_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* invalidate_iterators mimics the interface of index_access_sequence (see
|
||||
* index_access_sequence.hpp) but returns dummy indices whose iterator type
|
||||
* won't ever match those of the source: the net effect is that safe iterator
|
||||
* transfer resolves to iterator invalidation, so backbone function invocation
|
||||
* extract_(x,invalidate_iterators()) is used in extraction scenarios other
|
||||
* than merging.
|
||||
*/
|
||||
|
||||
struct invalidate_iterators
|
||||
{
|
||||
typedef void iterator;
|
||||
|
||||
invalidate_iterators& get(){return *this;}
|
||||
invalidate_iterators& next(){return *this;}
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2003-2021 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)
|
||||
@ -25,6 +25,12 @@
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <new>
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE)
|
||||
#include <boost/type_traits/is_const.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/utility/enable_if.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
@ -235,6 +241,23 @@ private:
|
||||
BOOST_MOVABLE_BUT_NOT_COPYABLE(insert_return_type)
|
||||
};
|
||||
|
||||
/* utility for SFINAEing merge and related operations */
|
||||
|
||||
#if !defined(BOOST_NO_SFINAE)
|
||||
|
||||
#define BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(Dst,Src,T) \
|
||||
typename enable_if_c< \
|
||||
!is_const< Dst >::value&&!is_const< Src >::value&& \
|
||||
is_same<typename Dst::node_type,typename Src::node_type>::value, \
|
||||
T \
|
||||
>::type
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(Dst,Src,T) T
|
||||
|
||||
#endif
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
@ -59,6 +59,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/invalidate_iterators.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>
|
||||
@ -127,13 +128,6 @@ template<
|
||||
>
|
||||
class ordered_index_impl:
|
||||
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,public safe_mode::safe_container<
|
||||
ordered_index_impl<
|
||||
KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy> >
|
||||
#endif
|
||||
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
@ -145,6 +139,12 @@ class ordered_index_impl:
|
||||
#pragma parse_mfunc_templ off
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
/* cross-index access */
|
||||
|
||||
template <typename,typename,typename> friend class index_base;
|
||||
#endif
|
||||
|
||||
typedef typename SuperMeta::type super;
|
||||
|
||||
protected:
|
||||
@ -171,8 +171,7 @@ public:
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_iterator<
|
||||
bidir_node_iterator<index_node_type>,
|
||||
ordered_index_impl> iterator;
|
||||
bidir_node_iterator<index_node_type> > iterator;
|
||||
#else
|
||||
typedef bidir_node_iterator<index_node_type> iterator;
|
||||
#endif
|
||||
@ -222,8 +221,7 @@ protected:
|
||||
|
||||
protected:
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_container<
|
||||
ordered_index_impl> safe_super;
|
||||
typedef safe_mode::safe_container<iterator> safe_container;
|
||||
#endif
|
||||
|
||||
typedef typename call_traits<
|
||||
@ -231,11 +229,9 @@ protected:
|
||||
typedef typename call_traits<
|
||||
key_type>::param_type key_param_type;
|
||||
|
||||
/* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
|
||||
* expansion.
|
||||
*/
|
||||
/* needed to avoid commas in some macros */
|
||||
|
||||
typedef std::pair<iterator,bool> emplace_return_type;
|
||||
typedef std::pair<iterator,bool> pair_return_type;
|
||||
|
||||
public:
|
||||
|
||||
@ -298,7 +294,7 @@ public:
|
||||
/* modifiers */
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
|
||||
emplace_return_type,emplace,emplace_impl)
|
||||
pair_return_type,emplace,emplace_impl)
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
|
||||
iterator,emplace_hint,emplace_hint_impl,iterator,position)
|
||||
@ -529,6 +525,75 @@ public:
|
||||
this->final_clear_();
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
|
||||
merge(Index& x)
|
||||
{
|
||||
merge(x,x.begin(),x.end());
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
|
||||
merge(BOOST_RV_REF(Index) x){merge(static_cast<Index&>(x));}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
|
||||
ordered_index_impl,Index,pair_return_type)
|
||||
merge(Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i);
|
||||
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
return std::pair<iterator,bool>(
|
||||
make_iterator(static_cast<final_node_type*>(i.get_node())),true);
|
||||
}
|
||||
else{
|
||||
std::pair<final_node_type*,bool> p=this->final_transfer_(
|
||||
x,static_cast<final_node_type*>(i.get_node()));
|
||||
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
|
||||
ordered_index_impl,Index,pair_return_type)
|
||||
merge(BOOST_RV_REF(Index) x,BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
return merge(static_cast<Index&>(x),i);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
|
||||
merge(
|
||||
Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,x);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
BOOST_MULTI_INDEX_ORD_INDEX_CHECK_INVARIANT;
|
||||
if(x.end().get_node()!=this->header()){ /* different containers */
|
||||
this->final_transfer_range_(x,first,last);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(ordered_index_impl,Index,void)
|
||||
merge(
|
||||
BOOST_RV_REF(Index) x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
merge(static_cast<Index&>(x),first,last);
|
||||
}
|
||||
|
||||
/* observers */
|
||||
|
||||
key_from_value key_extractor()const{return key;}
|
||||
@ -659,6 +724,11 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
super(args_list.get_tail(),al),
|
||||
key(tuples::get<0>(args_list.get_head())),
|
||||
comp_(tuples::get<1>(args_list.get_head()))
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
empty_initialize();
|
||||
}
|
||||
@ -667,13 +737,13 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
const ordered_index_impl<
|
||||
KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& x):
|
||||
super(x),
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super(),
|
||||
#endif
|
||||
|
||||
key(x.key),
|
||||
comp_(x.comp_)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
/* Copy ctor just takes the key and compare objects from x. The rest is
|
||||
* done in a subsequent call to copy_().
|
||||
@ -685,13 +755,13 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& x,
|
||||
do_not_copy_elements_tag):
|
||||
super(x,do_not_copy_elements_tag()),
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super(),
|
||||
#endif
|
||||
|
||||
key(x.key),
|
||||
comp_(x.comp_)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
empty_initialize();
|
||||
}
|
||||
@ -703,9 +773,9 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
iterator make_iterator(index_node_type* node)
|
||||
{return iterator(node,this);}
|
||||
{return iterator(node,&safe);}
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
{return const_iterator(node,const_cast<ordered_index_impl*>(this));}
|
||||
{return const_iterator(node,const_cast<safe_container*>(&safe));}
|
||||
#else
|
||||
iterator make_iterator(index_node_type* node){return iterator(node);}
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
@ -809,14 +879,15 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
return res;
|
||||
}
|
||||
|
||||
void extract_(index_node_type* x)
|
||||
template<typename Dst>
|
||||
void extract_(index_node_type* x,Dst dst)
|
||||
{
|
||||
node_impl_type::rebalance_for_extract(
|
||||
x->impl(),header()->parent(),header()->left(),header()->right());
|
||||
super::extract_(x);
|
||||
super::extract_(x,dst.next());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
transfer_iterators(dst.get(),x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -831,7 +902,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
empty_initialize();
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::detach_dereferenceable_iterators();
|
||||
safe.detach_dereferenceable_iterators();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -845,7 +916,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
adl_swap(comp_,x.comp_);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_(x,swap_allocators);
|
||||
@ -856,7 +927,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
KeyFromValue,Compare,SuperMeta,TagList,Category,AugmentPolicy>& x)
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_elements_(x);
|
||||
@ -898,7 +969,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
b=in_place(x->value(),x,Category());
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
extract_(x);
|
||||
extract_(x,invalidate_iterators());
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -908,7 +979,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
BOOST_TRY{
|
||||
link_info inf;
|
||||
if(!link_point(key(x->value()),inf,Category())){
|
||||
super::extract_(x);
|
||||
super::extract_(x,invalidate_iterators());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
@ -918,7 +989,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
node_impl_type::link(x->impl(),inf.side,inf.pos,header()->impl());
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
super::extract_(x);
|
||||
super::extract_(x,invalidate_iterators());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
@ -1272,6 +1343,13 @@ private:
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::detach_equivalent_iterators(it);
|
||||
}
|
||||
|
||||
template<typename Dst>
|
||||
void transfer_iterators(Dst& dst,index_node_type* x)
|
||||
{
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::transfer_equivalent_iterators(dst,it);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
|
||||
@ -1449,6 +1527,10 @@ protected: /* for the benefit of AugmentPolicy::augmented_interface */
|
||||
key_from_value key;
|
||||
key_compare comp_;
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_container safe;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
#pragma parse_mfunc_templ reset
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2003-2018 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2003-2021 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)
|
||||
@ -169,6 +169,25 @@ struct random_access_index_node_impl
|
||||
}
|
||||
}
|
||||
|
||||
static ptr_pointer gather_nulls(
|
||||
ptr_pointer pbegin,ptr_pointer pend,ptr_pointer x)
|
||||
{
|
||||
for(ptr_pointer p=pbegin;p!=x;++p){
|
||||
if(*p){
|
||||
*pbegin=*p;
|
||||
(*pbegin)->up()=pbegin;
|
||||
++pbegin;
|
||||
}
|
||||
}
|
||||
for(ptr_pointer p=pend;p!=x;){
|
||||
if(*--p){
|
||||
*--pend=*p;
|
||||
(*pend)->up()=pend;
|
||||
}
|
||||
}
|
||||
return pbegin;
|
||||
}
|
||||
|
||||
private:
|
||||
ptr_pointer up_;
|
||||
};
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2003-2021 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)
|
||||
@ -15,9 +15,9 @@
|
||||
|
||||
/* Safe mode machinery, in the spirit of Cay Hortmann's "Safe STL"
|
||||
* (http://www.horstmann.com/safestl.html).
|
||||
* In this mode, containers of type Container are derived from
|
||||
* safe_container<Container>, and their corresponding iterators
|
||||
* are wrapped with safe_iterator. These classes provide
|
||||
* In this mode, containers have to redefine their iterators as
|
||||
* safe_iterator<base_iterator> and keep a tracking object member of
|
||||
* type safe_container<safe_iterator<base_iterator> >. These classes provide
|
||||
* an internal record of which iterators are at a given moment associated
|
||||
* to a given container, and properly mark the iterators as invalid
|
||||
* when the container gets destroyed.
|
||||
@ -80,6 +80,11 @@
|
||||
safe_mode::check_is_owner(it,cont), \
|
||||
safe_mode::not_owner);
|
||||
|
||||
#define BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,cont) \
|
||||
BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
|
||||
safe_mode::check_belongs_in_some_index(it,cont), \
|
||||
safe_mode::not_owner);
|
||||
|
||||
#define BOOST_MULTI_INDEX_CHECK_SAME_OWNER(it0,it1) \
|
||||
BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
|
||||
safe_mode::check_same_owner(it0,it1), \
|
||||
@ -113,9 +118,12 @@
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
#include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
|
||||
#include <algorithm>
|
||||
#include <boost/core/addressof.hpp>
|
||||
#include <boost/multi_index/detail/access_specifier.hpp>
|
||||
#include <boost/multi_index/detail/any_container_view.hpp>
|
||||
#include <boost/multi_index/detail/iter_adaptor.hpp>
|
||||
#include <boost/multi_index/safe_mode_errors.hpp>
|
||||
#include <boost/type_traits/is_same.hpp>
|
||||
#include <boost/noncopyable.hpp>
|
||||
|
||||
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
|
||||
@ -125,6 +133,7 @@
|
||||
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
#include <boost/detail/lightweight_mutex.hpp>
|
||||
#include <boost/multi_index/detail/scoped_bilock.hpp>
|
||||
#endif
|
||||
|
||||
namespace boost{
|
||||
@ -162,18 +171,29 @@ inline bool check_decrementable_iterator(const Iterator& it)
|
||||
return (it.valid()&&it!=it.owner()->begin())||it.unchecked();
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
template<typename Iterator,typename Container>
|
||||
inline bool check_is_owner(
|
||||
const Iterator& it,const typename Iterator::container_type& cont)
|
||||
const Iterator& it,const Container& cont)
|
||||
{
|
||||
return (it.valid()&&it.owner()==&cont)||it.unchecked();
|
||||
return (it.valid()&&
|
||||
it.owner()->container()==cont.end().owner()->container())
|
||||
||it.unchecked();
|
||||
}
|
||||
|
||||
template<typename Iterator,typename MultiIndexContainer>
|
||||
inline bool check_belongs_in_some_index(
|
||||
const Iterator& it,const MultiIndexContainer& cont)
|
||||
{
|
||||
return (it.valid()&&it.owner()->end().get_node()==cont.end().get_node())
|
||||
||it.unchecked();
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
inline bool check_same_owner(const Iterator& it0,const Iterator& it1)
|
||||
{
|
||||
return (it0.valid()&&it1.valid()&&it0.owner()==it1.owner())||
|
||||
it0.unchecked()||it1.unchecked();
|
||||
return (it0.valid()&&it1.valid()&&
|
||||
it0.owner()->container()==it1.owner()->container())
|
||||
||it0.unchecked()||it1.unchecked();
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
@ -217,6 +237,28 @@ inline bool check_outside_range(
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Iterator1,typename Iterator2>
|
||||
inline bool check_outside_range(
|
||||
const Iterator1& it,const Iterator2& it0,const Iterator2& it1)
|
||||
{
|
||||
if(it.valid()&&it!=it.owner()->end()&&it0.valid()){
|
||||
Iterator2 last=it0.owner()->end();
|
||||
bool found=false;
|
||||
|
||||
Iterator2 first=it0;
|
||||
for(;first!=last;++first){
|
||||
if(first==it1)break;
|
||||
|
||||
/* crucial that this check goes after previous break */
|
||||
|
||||
if(boost::addressof(*first)==boost::addressof(*it))found=true;
|
||||
}
|
||||
if(first!=it1)return false;
|
||||
return !found;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Iterator,typename Difference>
|
||||
inline bool check_in_bounds(const Iterator& it,Difference n)
|
||||
{
|
||||
@ -233,6 +275,12 @@ inline bool check_different_container(
|
||||
return &cont0!=&cont1;
|
||||
}
|
||||
|
||||
template<typename Container1,typename Container2>
|
||||
inline bool check_different_container(const Container1&,const Container2&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename Container0,typename Container1>
|
||||
inline bool check_equal_allocators(
|
||||
const Container0& cont0,const Container1& cont1)
|
||||
@ -240,42 +288,20 @@ inline bool check_equal_allocators(
|
||||
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.
|
||||
*/
|
||||
/* fwd decls */
|
||||
|
||||
template<typename Iterator>
|
||||
inline void detach_equivalent_iterators(Iterator& it)
|
||||
{
|
||||
if(it.valid()){
|
||||
{
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
boost::detail::lightweight_mutex::scoped_lock lock(it.cont->mutex);
|
||||
#endif
|
||||
template<typename Container> class safe_container;
|
||||
template<typename Iterator> void detach_equivalent_iterators(Iterator&);
|
||||
|
||||
Iterator *prev_,*next_;
|
||||
for(
|
||||
prev_=static_cast<Iterator*>(&it.cont->header);
|
||||
(next_=static_cast<Iterator*>(prev_->next))!=0;){
|
||||
if(next_!=&it&&*next_==it){
|
||||
prev_->next=next_->next;
|
||||
next_->cont=0;
|
||||
}
|
||||
else prev_=next_;
|
||||
}
|
||||
}
|
||||
it.detach();
|
||||
}
|
||||
}
|
||||
namespace safe_mode_detail{
|
||||
|
||||
template<typename Container> class safe_container; /* fwd decl. */
|
||||
/* fwd decls */
|
||||
|
||||
} /* namespace multi_index::safe_mode */
|
||||
|
||||
namespace detail{
|
||||
|
||||
class safe_container_base; /* fwd decl. */
|
||||
class safe_container_base;
|
||||
template<typename Dst,typename Iterator>
|
||||
void transfer_equivalent_iterators(Dst&,Iterator,boost::true_type);
|
||||
template<typename Dst,typename Iterator>
|
||||
inline void transfer_equivalent_iterators(Dst&,Iterator&,boost::false_type);
|
||||
|
||||
class safe_iterator_base
|
||||
{
|
||||
@ -325,12 +351,16 @@ protected:
|
||||
const safe_container_base* owner()const{return cont;}
|
||||
|
||||
BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
friend class safe_container_base;
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template<typename> friend class safe_mode::safe_container;
|
||||
template<typename Iterator> friend
|
||||
void safe_mode::detach_equivalent_iterators(Iterator&);
|
||||
friend class safe_container_base;
|
||||
template<typename>
|
||||
friend class safe_mode::safe_container;
|
||||
template<typename Iterator>
|
||||
friend void safe_mode::detach_equivalent_iterators(Iterator&);
|
||||
template<typename Dst,typename Iterator>
|
||||
friend void safe_mode_detail::transfer_equivalent_iterators(
|
||||
Dst&,Iterator,boost::true_type);
|
||||
#endif
|
||||
|
||||
inline void attach(safe_container_base* cont_);
|
||||
@ -346,11 +376,14 @@ public:
|
||||
safe_container_base(){}
|
||||
|
||||
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
friend class safe_iterator_base;
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
template<typename Iterator> friend
|
||||
void safe_mode::detach_equivalent_iterators(Iterator&);
|
||||
friend class safe_iterator_base;
|
||||
template<typename Iterator>
|
||||
friend void safe_mode::detach_equivalent_iterators(Iterator&);
|
||||
template<typename Dst,typename Iterator>
|
||||
friend void safe_mode_detail::transfer_equivalent_iterators(
|
||||
Dst&,Iterator,boost::true_type);
|
||||
#endif
|
||||
|
||||
~safe_container_base()
|
||||
@ -405,41 +438,36 @@ void safe_iterator_base::detach()
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
namespace safe_mode{
|
||||
} /* namespace multi_index::safe_mode::safe_mode_detail */
|
||||
|
||||
/* In order to enable safe mode on a container:
|
||||
* - The container must derive from safe_container<container_type>,
|
||||
* - The container must keep a member of type safe_container<iterator>,
|
||||
* - iterators must be generated via safe_iterator, which adapts a
|
||||
* preexistent unsafe iterator class.
|
||||
* preexistent unsafe iterator class. safe_iterators are passed the
|
||||
* address of the previous safe_container member at construction time.
|
||||
*/
|
||||
|
||||
template<typename Container>
|
||||
class safe_container;
|
||||
|
||||
template<typename Iterator,typename Container>
|
||||
template<typename Iterator>
|
||||
class safe_iterator:
|
||||
public detail::iter_adaptor<safe_iterator<Iterator,Container>,Iterator>,
|
||||
public detail::safe_iterator_base
|
||||
public detail::iter_adaptor<safe_iterator<Iterator>,Iterator>,
|
||||
public safe_mode_detail::safe_iterator_base
|
||||
{
|
||||
typedef detail::iter_adaptor<safe_iterator,Iterator> super;
|
||||
typedef detail::safe_iterator_base safe_super;
|
||||
typedef safe_mode_detail::safe_iterator_base safe_super;
|
||||
|
||||
public:
|
||||
typedef Container container_type;
|
||||
typedef typename Iterator::reference reference;
|
||||
typedef typename Iterator::difference_type difference_type;
|
||||
|
||||
safe_iterator(){}
|
||||
explicit safe_iterator(safe_container<container_type>* cont_):
|
||||
explicit safe_iterator(safe_container<safe_iterator>* cont_):
|
||||
safe_super(cont_){}
|
||||
template<typename T0>
|
||||
safe_iterator(const T0& t0,safe_container<container_type>* cont_):
|
||||
safe_iterator(const T0& t0,safe_container<safe_iterator>* cont_):
|
||||
super(Iterator(t0)),safe_super(cont_){}
|
||||
template<typename T0,typename T1>
|
||||
safe_iterator(
|
||||
const T0& t0,const T1& t1,safe_container<container_type>* cont_):
|
||||
const T0& t0,const T1& t1,safe_container<safe_iterator>* cont_):
|
||||
super(Iterator(t0,t1)),safe_super(cont_){}
|
||||
safe_iterator(const safe_iterator& x):super(x),safe_super(x){}
|
||||
|
||||
@ -451,12 +479,11 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
const container_type* owner()const
|
||||
const safe_container<safe_iterator>* owner()const
|
||||
{
|
||||
return
|
||||
static_cast<const container_type*>(
|
||||
static_cast<const safe_container<container_type>*>(
|
||||
this->safe_super::owner()));
|
||||
static_cast<const safe_container<safe_iterator>*>(
|
||||
this->safe_super::owner());
|
||||
}
|
||||
|
||||
/* get_node is not to be used by the user */
|
||||
@ -547,21 +574,28 @@ private:
|
||||
#endif
|
||||
};
|
||||
|
||||
template<typename Container>
|
||||
class safe_container:public detail::safe_container_base
|
||||
template<typename Iterator>
|
||||
class safe_container:public safe_mode_detail::safe_container_base
|
||||
{
|
||||
typedef detail::safe_container_base super;
|
||||
typedef safe_mode_detail::safe_container_base super;
|
||||
|
||||
detail::any_container_view<Iterator> view;
|
||||
|
||||
public:
|
||||
template<typename Container>
|
||||
safe_container(const Container& c):view(c){}
|
||||
|
||||
const void* container()const{return view.container();}
|
||||
Iterator begin()const{return view.begin();}
|
||||
Iterator end()const{return view.end();}
|
||||
|
||||
void detach_dereferenceable_iterators()
|
||||
{
|
||||
typedef typename Container::iterator iterator;
|
||||
|
||||
iterator end_=static_cast<Container*>(this)->end();
|
||||
iterator *prev_,*next_;
|
||||
Iterator end_=view.end();
|
||||
Iterator *prev_,*next_;
|
||||
for(
|
||||
prev_=static_cast<iterator*>(&this->header);
|
||||
(next_=static_cast<iterator*>(prev_->next))!=0;){
|
||||
prev_=static_cast<Iterator*>(&this->header);
|
||||
(next_=static_cast<Iterator*>(prev_->next))!=0;){
|
||||
if(*next_!=end_){
|
||||
prev_->next=next_->next;
|
||||
next_->cont=0;
|
||||
@ -570,21 +604,102 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void swap(safe_container<Container>& x)
|
||||
void swap(safe_container<Iterator>& x)
|
||||
{
|
||||
super::swap(x);
|
||||
}
|
||||
};
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
|
||||
template<typename Iterator>
|
||||
inline void detach_equivalent_iterators(Iterator& it)
|
||||
{
|
||||
if(it.valid()){
|
||||
{
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
boost::detail::lightweight_mutex::scoped_lock lock(it.cont->mutex);
|
||||
#endif
|
||||
|
||||
Iterator *prev_,*next_;
|
||||
for(
|
||||
prev_=static_cast<Iterator*>(&it.cont->header);
|
||||
(next_=static_cast<Iterator*>(prev_->next))!=0;){
|
||||
if(next_!=&it&&*next_==it){
|
||||
prev_->next=next_->next;
|
||||
next_->cont=0;
|
||||
}
|
||||
else prev_=next_;
|
||||
}
|
||||
}
|
||||
it.detach();
|
||||
}
|
||||
}
|
||||
|
||||
/* Transfers iterators equivalent to that given to Dst, if that container has
|
||||
* the same iterator type; otherwise, detaches them.
|
||||
*/
|
||||
|
||||
template<typename Dst,typename Iterator>
|
||||
inline void transfer_equivalent_iterators(Dst& dst,Iterator& i)
|
||||
{
|
||||
safe_mode_detail::transfer_equivalent_iterators(
|
||||
dst,i,boost::is_same<Iterator,typename Dst::iterator>());
|
||||
}
|
||||
|
||||
namespace safe_mode_detail{
|
||||
|
||||
template<typename Dst,typename Iterator>
|
||||
inline void transfer_equivalent_iterators(
|
||||
Dst& dst,Iterator it,boost::true_type /* same iterator type */)
|
||||
{
|
||||
if(it.valid()){
|
||||
{
|
||||
safe_container_base* cont_=dst.end().cont;
|
||||
|
||||
#if defined(BOOST_HAS_THREADS)
|
||||
detail::scoped_bilock<boost::detail::lightweight_mutex>
|
||||
scoped_bilock(it.cont->mutex,cont_->mutex);
|
||||
#endif
|
||||
|
||||
Iterator *prev_,*next_;
|
||||
for(
|
||||
prev_=static_cast<Iterator*>(&it.cont->header);
|
||||
(next_=static_cast<Iterator*>(prev_->next))!=0;){
|
||||
if(next_!=&it&&*next_==it){
|
||||
prev_->next=next_->next;
|
||||
next_->cont=cont_;
|
||||
next_->next=cont_->header.next;
|
||||
cont_->header.next=next_;
|
||||
}
|
||||
else prev_=next_;
|
||||
}
|
||||
}
|
||||
/* nothing to do with it, was passed by value and will die now */
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Dst,typename Iterator>
|
||||
inline void transfer_equivalent_iterators(
|
||||
Dst&,Iterator& it,boost::false_type /* same iterator type */)
|
||||
{
|
||||
detach_equivalent_iterators(it);
|
||||
}
|
||||
|
||||
} /* namespace multi_index::safe_mode::safe_mode_detail */
|
||||
|
||||
} /* namespace multi_index::safe_mode */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
#if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
|
||||
namespace serialization{
|
||||
template<typename Iterator,typename Container>
|
||||
template<typename Iterator>
|
||||
struct version<
|
||||
boost::multi_index::safe_mode::safe_iterator<Iterator,Container>
|
||||
boost::multi_index::safe_mode::safe_iterator<Iterator>
|
||||
>
|
||||
{
|
||||
BOOST_STATIC_CONSTANT(
|
||||
|
70
include/boost/multi_index/detail/scoped_bilock.hpp
Normal file
70
include/boost/multi_index/detail/scoped_bilock.hpp
Normal file
@ -0,0 +1,70 @@
|
||||
/* Copyright 2003-2021 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_SCOPED_BILOCK_HPP
|
||||
#define BOOST_MULTI_INDEX_DETAIL_SCOPED_BILOCK_HPP
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/type_traits/aligned_storage.hpp>
|
||||
#include <boost/type_traits/alignment_of.hpp>
|
||||
#include <functional>
|
||||
#include <new>
|
||||
|
||||
namespace boost{
|
||||
|
||||
namespace multi_index{
|
||||
|
||||
namespace detail{
|
||||
|
||||
/* Locks/unlocks two RAII-lockable mutexes taking care that locking is done in
|
||||
* a deadlock-avoiding global order and no double locking happens when the two
|
||||
* mutexes are the same.
|
||||
*/
|
||||
|
||||
template<typename Mutex>
|
||||
class scoped_bilock:private noncopyable
|
||||
{
|
||||
public:
|
||||
scoped_bilock(Mutex& mutex1,Mutex& mutex2):mutex_eq(&mutex1==&mutex2)
|
||||
{
|
||||
bool mutex_lt=std::less<Mutex*>()(&mutex1,&mutex2);
|
||||
|
||||
::new (static_cast<void*>(&lock1)) scoped_lock(mutex_lt?mutex1:mutex2);
|
||||
if(!mutex_eq)
|
||||
::new (static_cast<void*>(&lock2)) scoped_lock(mutex_lt?mutex2:mutex1);
|
||||
}
|
||||
|
||||
~scoped_bilock()
|
||||
{
|
||||
reinterpret_cast<scoped_lock*>(&lock1)->~scoped_lock();
|
||||
if(!mutex_eq)
|
||||
reinterpret_cast<scoped_lock*>(&lock2)->~scoped_lock();
|
||||
}
|
||||
|
||||
private:
|
||||
typedef typename Mutex::scoped_lock scoped_lock;
|
||||
typedef typename aligned_storage<
|
||||
sizeof(scoped_lock),
|
||||
alignment_of<scoped_lock>::value
|
||||
>::type scoped_lock_space;
|
||||
|
||||
bool mutex_eq;
|
||||
scoped_lock_space lock1,lock2;
|
||||
};
|
||||
|
||||
} /* namespace multi_index::detail */
|
||||
|
||||
} /* namespace multi_index */
|
||||
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
@ -34,6 +34,7 @@
|
||||
#include <boost/multi_index/detail/do_not_copy_elements_tag.hpp>
|
||||
#include <boost/multi_index/detail/hash_index_iterator.hpp>
|
||||
#include <boost/multi_index/detail/index_node_base.hpp>
|
||||
#include <boost/multi_index/detail/invalidate_iterators.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>
|
||||
@ -88,12 +89,6 @@ template<
|
||||
>
|
||||
class hashed_index:
|
||||
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,public safe_mode::safe_container<
|
||||
hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category> >
|
||||
#endif
|
||||
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
@ -105,6 +100,12 @@ class hashed_index:
|
||||
#pragma parse_mfunc_templ off
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
/* cross-index access */
|
||||
|
||||
template <typename,typename,typename> friend class index_base;
|
||||
#endif
|
||||
|
||||
typedef typename SuperMeta::type super;
|
||||
|
||||
protected:
|
||||
@ -148,8 +149,7 @@ public:
|
||||
hashed_index_iterator<
|
||||
index_node_type,bucket_array_type,
|
||||
Category,
|
||||
hashed_index_global_iterator_tag>,
|
||||
hashed_index> iterator;
|
||||
hashed_index_global_iterator_tag> > iterator;
|
||||
#else
|
||||
typedef hashed_index_iterator<
|
||||
index_node_type,bucket_array_type,
|
||||
@ -191,19 +191,16 @@ protected:
|
||||
|
||||
private:
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_container<
|
||||
hashed_index> safe_super;
|
||||
typedef safe_mode::safe_container<iterator> safe_container;
|
||||
#endif
|
||||
|
||||
typedef typename call_traits<value_type>::param_type value_param_type;
|
||||
typedef typename call_traits<
|
||||
key_type>::param_type key_param_type;
|
||||
|
||||
/* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
|
||||
* expansion.
|
||||
*/
|
||||
/* needed to avoid commas in some macros */
|
||||
|
||||
typedef std::pair<iterator,bool> emplace_return_type;
|
||||
typedef std::pair<iterator,bool> pair_return_type;
|
||||
|
||||
public:
|
||||
|
||||
@ -273,7 +270,7 @@ public:
|
||||
/* modifiers */
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
|
||||
emplace_return_type,emplace,emplace_impl)
|
||||
pair_return_type,emplace,emplace_impl)
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
|
||||
iterator,emplace_hint,emplace_hint_impl,iterator,position)
|
||||
@ -508,6 +505,73 @@ public:
|
||||
this->final_swap_(x.final());
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
|
||||
merge(Index& x)
|
||||
{
|
||||
merge(x,x.begin(),x.end());
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
|
||||
merge(BOOST_RV_REF(Index) x){merge(static_cast<Index&>(x));}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,pair_return_type)
|
||||
merge(Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(i);
|
||||
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
return std::pair<iterator,bool>(
|
||||
make_iterator(static_cast<final_node_type*>(i.get_node())),true);
|
||||
}
|
||||
else{
|
||||
std::pair<final_node_type*,bool> p=this->final_transfer_(
|
||||
x,static_cast<final_node_type*>(i.get_node()));
|
||||
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,pair_return_type)
|
||||
merge(BOOST_RV_REF(Index) x,BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
return merge(static_cast<Index&>(x),i);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
|
||||
merge(
|
||||
Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(first);
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(last);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(first,x);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
BOOST_MULTI_INDEX_HASHED_INDEX_CHECK_INVARIANT;
|
||||
if(x.end().get_node()!=this->header()){ /* different containers */
|
||||
this->final_transfer_range_(x,first,last);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(hashed_index,Index,void)
|
||||
merge(
|
||||
BOOST_RV_REF(Index) x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
merge(static_cast<Index&>(x),first,last);
|
||||
}
|
||||
|
||||
/* observers */
|
||||
|
||||
key_from_value key_extractor()const{return key;}
|
||||
@ -687,6 +751,11 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
eq_(tuples::get<3>(args_list.get_head())),
|
||||
buckets(al,header()->impl(),tuples::get<0>(args_list.get_head())),
|
||||
mlf(1.0f)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
calculate_max_load();
|
||||
}
|
||||
@ -694,17 +763,17 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
hashed_index(
|
||||
const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x):
|
||||
super(x),
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super(),
|
||||
#endif
|
||||
|
||||
key(x.key),
|
||||
hash_(x.hash_),
|
||||
eq_(x.eq_),
|
||||
buckets(x.get_allocator(),header()->impl(),x.buckets.size()),
|
||||
mlf(x.mlf),
|
||||
max_load(x.max_load)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
/* Copy ctor just takes the internal configuration objects from x. The rest
|
||||
* is done in subsequent call to copy_().
|
||||
@ -715,16 +784,16 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
const hashed_index<KeyFromValue,Hash,Pred,SuperMeta,TagList,Category>& x,
|
||||
do_not_copy_elements_tag):
|
||||
super(x,do_not_copy_elements_tag()),
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super(),
|
||||
#endif
|
||||
|
||||
key(x.key),
|
||||
hash_(x.hash_),
|
||||
eq_(x.eq_),
|
||||
buckets(x.get_allocator(),header()->impl(),0),
|
||||
mlf(1.0f)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
calculate_max_load();
|
||||
}
|
||||
@ -737,12 +806,12 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
iterator make_iterator(index_node_type* node)
|
||||
{
|
||||
return iterator(node,this);
|
||||
return iterator(node,&safe);
|
||||
}
|
||||
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
{
|
||||
return const_iterator(node,const_cast<hashed_index*>(this));
|
||||
return const_iterator(node,const_cast<safe_container*>(&safe));
|
||||
}
|
||||
#else
|
||||
iterator make_iterator(index_node_type* node)
|
||||
@ -894,13 +963,14 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
return res;
|
||||
}
|
||||
|
||||
void extract_(index_node_type* x)
|
||||
template<typename Dst>
|
||||
void extract_(index_node_type* x,Dst dst)
|
||||
{
|
||||
unlink(x);
|
||||
super::extract_(x);
|
||||
super::extract_(x,dst.next());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
transfer_iterators(dst.get(),x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -944,7 +1014,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
buckets.clear(header()->impl());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::detach_dereferenceable_iterators();
|
||||
safe.detach_dereferenceable_iterators();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -961,7 +1031,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
std::swap(max_load,x.max_load);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_(x,swap_allocators);
|
||||
@ -975,7 +1045,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
std::swap(max_load,x.max_load);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_elements_(x);
|
||||
@ -1017,7 +1087,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
b=in_place(x->impl(),key(x->value()),buc);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
extract_(x);
|
||||
extract_(x,invalidate_iterators());
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
@ -1026,7 +1096,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
BOOST_TRY{
|
||||
link_info pos(buckets.at(buc));
|
||||
if(!link_point(x->value(),pos)){
|
||||
super::extract_(x);
|
||||
super::extract_(x,invalidate_iterators());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
@ -1036,7 +1106,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
link(x,pos);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
super::extract_(x);
|
||||
super::extract_(x,invalidate_iterators());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
@ -1576,6 +1646,13 @@ private:
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::detach_equivalent_iterators(it);
|
||||
}
|
||||
|
||||
template<typename Dst>
|
||||
void transfer_iterators(Dst& dst,index_node_type* x)
|
||||
{
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::transfer_equivalent_iterators(dst,it);
|
||||
}
|
||||
#endif
|
||||
|
||||
template<BOOST_MULTI_INDEX_TEMPLATE_PARAM_PACK>
|
||||
@ -1696,7 +1773,11 @@ private:
|
||||
bucket_array_type buckets;
|
||||
float mlf;
|
||||
size_type max_load;
|
||||
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_container safe;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
#pragma parse_mfunc_templ reset
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2003-2021 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)
|
||||
@ -42,6 +42,7 @@
|
||||
#include <boost/multi_index/random_access_index_fwd.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/type_traits/is_copy_constructible.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <functional>
|
||||
#include <stdexcept>
|
||||
@ -80,12 +81,6 @@ namespace detail{
|
||||
template<typename SuperMeta,typename TagList>
|
||||
class random_access_index:
|
||||
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,public safe_mode::safe_container<
|
||||
random_access_index<SuperMeta,TagList> >
|
||||
#endif
|
||||
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
@ -97,6 +92,12 @@ class random_access_index:
|
||||
#pragma parse_mfunc_templ off
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
/* cross-index access */
|
||||
|
||||
template <typename,typename,typename> friend class index_base;
|
||||
#endif
|
||||
|
||||
typedef typename SuperMeta::type super;
|
||||
|
||||
protected:
|
||||
@ -120,8 +121,7 @@ public:
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_iterator<
|
||||
rnd_node_iterator<index_node_type>,
|
||||
random_access_index> iterator;
|
||||
rnd_node_iterator<index_node_type> > iterator;
|
||||
#else
|
||||
typedef rnd_node_iterator<index_node_type> iterator;
|
||||
#endif
|
||||
@ -168,18 +168,15 @@ protected:
|
||||
|
||||
private:
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_container<
|
||||
random_access_index> safe_super;
|
||||
typedef safe_mode::safe_container<iterator> safe_container;
|
||||
#endif
|
||||
|
||||
typedef typename call_traits<
|
||||
value_type>::param_type value_param_type;
|
||||
|
||||
/* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
|
||||
* expansion.
|
||||
*/
|
||||
/* needed to avoid commas in some macros */
|
||||
|
||||
typedef std::pair<iterator,bool> emplace_return_type;
|
||||
typedef std::pair<iterator,bool> pair_return_type;
|
||||
|
||||
public:
|
||||
|
||||
@ -325,7 +322,7 @@ public:
|
||||
/* modifiers */
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
|
||||
emplace_return_type,emplace_front,emplace_front_impl)
|
||||
pair_return_type,emplace_front,emplace_front_impl)
|
||||
|
||||
std::pair<iterator,bool> push_front(const value_type& x)
|
||||
{return insert(begin(),x);}
|
||||
@ -334,7 +331,7 @@ public:
|
||||
void pop_front(){erase(begin());}
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
|
||||
emplace_return_type,emplace_back,emplace_back_impl)
|
||||
pair_return_type,emplace_back,emplace_back_impl)
|
||||
|
||||
std::pair<iterator,bool> push_back(const value_type& x)
|
||||
{return insert(end(),x);}
|
||||
@ -343,7 +340,7 @@ public:
|
||||
void pop_back(){erase(--end());}
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
|
||||
emplace_return_type,emplace,emplace_impl,iterator,position)
|
||||
pair_return_type,emplace,emplace_impl,iterator,position)
|
||||
|
||||
std::pair<iterator,bool> insert(iterator position,const value_type& x)
|
||||
{
|
||||
@ -525,33 +522,36 @@ public:
|
||||
|
||||
/* list operations */
|
||||
|
||||
void splice(iterator position,random_access_index<SuperMeta,TagList>& x)
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(random_access_index,Index,void)
|
||||
splice(iterator position,Index& x)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
||||
BOOST_MULTI_INDEX_CHECK_DIFFERENT_CONTAINER(*this,x);
|
||||
BOOST_MULTI_INDEX_RND_INDEX_CHECK_INVARIANT;
|
||||
iterator first=x.begin(),last=x.end();
|
||||
size_type n=0;
|
||||
BOOST_TRY{
|
||||
while(first!=last){
|
||||
if(push_back(*first).second){
|
||||
first=x.erase(first);
|
||||
++n;
|
||||
}
|
||||
else ++first;
|
||||
}
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(
|
||||
position==end(),safe_mode::inside_range);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
relocate(position,end()-n,end());
|
||||
BOOST_RETHROW;
|
||||
else{
|
||||
external_splice(
|
||||
position,x,x.begin(),x.end(),
|
||||
boost::is_copy_constructible<value_type>());
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
relocate(position,end()-n,end());
|
||||
}
|
||||
|
||||
void splice(
|
||||
iterator position,random_access_index<SuperMeta,TagList>& x,iterator i)
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(random_access_index,Index,void)
|
||||
splice(iterator position,BOOST_RV_REF(Index) x)
|
||||
{
|
||||
splice(position,static_cast<Index&>(x));
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
|
||||
random_access_index,Index,pair_return_type)
|
||||
splice(
|
||||
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
||||
@ -559,28 +559,36 @@ public:
|
||||
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
|
||||
BOOST_MULTI_INDEX_RND_INDEX_CHECK_INVARIANT;
|
||||
if(&x==this)relocate(position,i);
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
index_node_type* pn=position.get_node();
|
||||
index_node_type* in=static_cast<index_node_type*>(i.get_node());
|
||||
if(pn!=in)relocate(pn,in);
|
||||
return std::pair<iterator,bool>(make_iterator(in),true);
|
||||
}
|
||||
else{
|
||||
if(insert(position,*i).second){
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
/* MSVC++ 6.0 optimizer has a hard time with safe mode, and the following
|
||||
* workaround is needed. Left it for all compilers as it does no
|
||||
* harm.
|
||||
*/
|
||||
i.detach();
|
||||
x.erase(x.make_iterator(i.get_node()));
|
||||
#else
|
||||
x.erase(i);
|
||||
#endif
|
||||
|
||||
}
|
||||
std::pair<final_node_type*,bool> p=
|
||||
external_splice(
|
||||
position,x,i,boost::is_copy_constructible<value_type>());
|
||||
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
||||
}
|
||||
}
|
||||
|
||||
void splice(
|
||||
iterator position,random_access_index<SuperMeta,TagList>& x,
|
||||
iterator first,iterator last)
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
|
||||
random_access_index,Index,pair_return_type)
|
||||
splice(
|
||||
iterator position,BOOST_RV_REF(Index) x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
return splice(position,static_cast<Index&>(x),i);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(random_access_index,Index,void)
|
||||
splice(
|
||||
iterator position,Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
||||
@ -590,25 +598,24 @@ public:
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
|
||||
BOOST_MULTI_INDEX_RND_INDEX_CHECK_INVARIANT;
|
||||
if(&x==this)relocate(position,first,last);
|
||||
else{
|
||||
size_type n=0;
|
||||
BOOST_TRY{
|
||||
while(first!=last){
|
||||
if(push_back(*first).second){
|
||||
first=x.erase(first);
|
||||
++n;
|
||||
}
|
||||
else ++first;
|
||||
}
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
relocate(position,end()-n,end());
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
relocate(position,end()-n,end());
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
BOOST_MULTI_INDEX_CHECK_OUTSIDE_RANGE(position,first,last);
|
||||
internal_splice(position,first,last);
|
||||
}
|
||||
else{
|
||||
external_splice(
|
||||
position,x,first,last,boost::is_copy_constructible<value_type>());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(random_access_index,Index,void)
|
||||
splice(
|
||||
iterator position,BOOST_RV_REF(Index) x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
splice(position,static_cast<Index&>(x),first,last);
|
||||
}
|
||||
|
||||
void remove(value_param_type value)
|
||||
@ -745,17 +752,22 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
const ctor_args_list& args_list,const allocator_type& al):
|
||||
super(args_list.get_tail(),al),
|
||||
ptrs(al,header()->impl(),0)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
random_access_index(const random_access_index<SuperMeta,TagList>& x):
|
||||
super(x),
|
||||
ptrs(x.get_allocator(),header()->impl(),x.size())
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super(),
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
ptrs(x.get_allocator(),header()->impl(),x.size())
|
||||
{
|
||||
/* The actual copying takes place in subsequent call to copy_().
|
||||
*/
|
||||
@ -764,12 +776,12 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
random_access_index(
|
||||
const random_access_index<SuperMeta,TagList>& x,do_not_copy_elements_tag):
|
||||
super(x,do_not_copy_elements_tag()),
|
||||
ptrs(x.get_allocator(),header()->impl(),0)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super(),
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
ptrs(x.get_allocator(),header()->impl(),0)
|
||||
{
|
||||
}
|
||||
|
||||
@ -780,9 +792,9 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
iterator make_iterator(index_node_type* node)
|
||||
{return iterator(node,this);}
|
||||
{return iterator(node,&safe);}
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
{return const_iterator(node,const_cast<random_access_index*>(this));}
|
||||
{return const_iterator(node,const_cast<safe_container*>(&safe));}
|
||||
#else
|
||||
iterator make_iterator(index_node_type* node){return iterator(node);}
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
@ -828,13 +840,14 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
return res;
|
||||
}
|
||||
|
||||
void extract_(index_node_type* x)
|
||||
template<typename Dst>
|
||||
void extract_(index_node_type* x,Dst dst)
|
||||
{
|
||||
ptrs.erase(x->impl());
|
||||
super::extract_(x);
|
||||
super::extract_(x,dst.next());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
transfer_iterators(dst.get(),x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -852,7 +865,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
ptrs.clear();
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::detach_dereferenceable_iterators();
|
||||
safe.detach_dereferenceable_iterators();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -863,7 +876,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
ptrs.swap(x.ptrs,swap_allocators);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_(x,swap_allocators);
|
||||
@ -874,7 +887,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
ptrs.swap(x.ptrs);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_elements_(x);
|
||||
@ -1000,6 +1013,13 @@ private:
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::detach_equivalent_iterators(it);
|
||||
}
|
||||
|
||||
template<typename Dst>
|
||||
void transfer_iterators(Dst& dst,index_node_type* x)
|
||||
{
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::transfer_equivalent_iterators(dst,it);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class InputIterator>
|
||||
@ -1085,7 +1105,121 @@ private:
|
||||
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
||||
}
|
||||
|
||||
ptr_array ptrs;
|
||||
template<typename Index>
|
||||
std::pair<final_node_type*,bool> external_splice(
|
||||
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i,
|
||||
boost::true_type /* copy-constructible value */)
|
||||
{
|
||||
if(get_allocator()==x.get_allocator()){
|
||||
return external_splice(position,x,i,boost::false_type());
|
||||
}
|
||||
else{
|
||||
/* backwards compatibility with old, non-transfer-based splice */
|
||||
|
||||
std::pair<iterator,bool> p=insert(position,*i);
|
||||
if(p.second)x.erase(i);
|
||||
return std::pair<final_node_type*,bool>(
|
||||
static_cast<final_node_type*>(p.first.get_node()),p.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
std::pair<final_node_type*,bool> external_splice(
|
||||
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i,
|
||||
boost::false_type /* copy-constructible value */)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
std::pair<final_node_type*,bool> p=this->final_transfer_(
|
||||
x,static_cast<final_node_type*>(i.get_node()));
|
||||
if(p.second&&position.get_node()!=header()){
|
||||
relocate(position.get_node(),p.first);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
void internal_splice(iterator position,Iterator first,Iterator last)
|
||||
{
|
||||
/* null out [first, last) positions in ptrs array */
|
||||
|
||||
for(Iterator it=first;it!=last;++it){
|
||||
*(static_cast<index_node_type*>(it.get_node())->up())=0;
|
||||
}
|
||||
|
||||
node_impl_ptr_pointer pp=node_impl_type::gather_nulls(
|
||||
ptrs.begin(),ptrs.end(),
|
||||
static_cast<index_node_type*>(position.get_node())->up());
|
||||
|
||||
/* relink [first, last) */
|
||||
|
||||
for(Iterator it=first;it!=last;++it,++pp){
|
||||
*pp=static_cast<index_node_type*>(it.get_node());
|
||||
(*pp)->up()=pp;
|
||||
}
|
||||
}
|
||||
|
||||
void internal_splice(iterator position,iterator first,iterator last)
|
||||
{
|
||||
index_node_type* pn=position.get_node();
|
||||
index_node_type* fn=static_cast<index_node_type*>(first.get_node());
|
||||
index_node_type* ln=static_cast<index_node_type*>(last.get_node());
|
||||
if(pn!=ln)relocate(pn,fn,ln);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
void external_splice(
|
||||
iterator position,Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last,
|
||||
boost::true_type /* copy-constructible value */)
|
||||
{
|
||||
if(get_allocator()==x.get_allocator()){
|
||||
external_splice(position,x,first,last,boost::false_type());
|
||||
}
|
||||
else{
|
||||
/* backwards compatibility with old, non-transfer-based splice */
|
||||
|
||||
size_type n=size();
|
||||
BOOST_TRY{
|
||||
while(first!=last){
|
||||
if(push_back(*first).second)first=x.erase(first);
|
||||
else ++first;
|
||||
}
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
relocate(position,begin()+n,end());
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
relocate(position,begin()+n,end());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
void external_splice(
|
||||
iterator position,Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last,
|
||||
boost::false_type /* copy-constructible value */)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
size_type n=size();
|
||||
BOOST_TRY{
|
||||
this->final_transfer_range_(x,first,last);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
relocate(position,begin()+n,end());
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
relocate(position,begin()+n,end());
|
||||
}
|
||||
|
||||
ptr_array ptrs;
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_container safe;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2003-2021 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)
|
||||
@ -39,6 +39,7 @@
|
||||
#include <boost/multi_index/detail/vartempl_support.hpp>
|
||||
#include <boost/multi_index/sequenced_index_fwd.hpp>
|
||||
#include <boost/tuple/tuple.hpp>
|
||||
#include <boost/type_traits/is_copy_constructible.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <functional>
|
||||
#include <utility>
|
||||
@ -70,12 +71,6 @@ namespace detail{
|
||||
template<typename SuperMeta,typename TagList>
|
||||
class sequenced_index:
|
||||
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS SuperMeta::type
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,public safe_mode::safe_container<
|
||||
sequenced_index<SuperMeta,TagList> >
|
||||
#endif
|
||||
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
@ -87,6 +82,12 @@ class sequenced_index:
|
||||
#pragma parse_mfunc_templ off
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
|
||||
/* cross-index access */
|
||||
|
||||
template <typename,typename,typename> friend class index_base;
|
||||
#endif
|
||||
|
||||
typedef typename SuperMeta::type super;
|
||||
|
||||
protected:
|
||||
@ -107,8 +108,7 @@ public:
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_iterator<
|
||||
bidir_node_iterator<index_node_type>,
|
||||
sequenced_index> iterator;
|
||||
bidir_node_iterator<index_node_type> > iterator;
|
||||
#else
|
||||
typedef bidir_node_iterator<index_node_type> iterator;
|
||||
#endif
|
||||
@ -155,17 +155,14 @@ protected:
|
||||
|
||||
private:
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef safe_mode::safe_container<
|
||||
sequenced_index> safe_super;
|
||||
typedef safe_mode::safe_container<iterator> safe_container;
|
||||
#endif
|
||||
|
||||
typedef typename call_traits<value_type>::param_type value_param_type;
|
||||
|
||||
/* Needed to avoid commas in BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL
|
||||
* expansion.
|
||||
*/
|
||||
/* needed to avoid commas in some macros */
|
||||
|
||||
typedef std::pair<iterator,bool> emplace_return_type;
|
||||
typedef std::pair<iterator,bool> pair_return_type;
|
||||
|
||||
public:
|
||||
|
||||
@ -287,7 +284,7 @@ public:
|
||||
/* modifiers */
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
|
||||
emplace_return_type,emplace_front,emplace_front_impl)
|
||||
pair_return_type,emplace_front,emplace_front_impl)
|
||||
|
||||
std::pair<iterator,bool> push_front(const value_type& x)
|
||||
{return insert(begin(),x);}
|
||||
@ -296,7 +293,7 @@ public:
|
||||
void pop_front(){erase(begin());}
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL(
|
||||
emplace_return_type,emplace_back,emplace_back_impl)
|
||||
pair_return_type,emplace_back,emplace_back_impl)
|
||||
|
||||
std::pair<iterator,bool> push_back(const value_type& x)
|
||||
{return insert(end(),x);}
|
||||
@ -305,7 +302,7 @@ public:
|
||||
void pop_back(){erase(--end());}
|
||||
|
||||
BOOST_MULTI_INDEX_OVERLOADS_TO_VARTEMPL_EXTRA_ARG(
|
||||
emplace_return_type,emplace,emplace_impl,iterator,position)
|
||||
pair_return_type,emplace,emplace_impl,iterator,position)
|
||||
|
||||
std::pair<iterator,bool> insert(iterator position,const value_type& x)
|
||||
{
|
||||
@ -476,20 +473,36 @@ public:
|
||||
|
||||
/* list operations */
|
||||
|
||||
void splice(iterator position,sequenced_index<SuperMeta,TagList>& x)
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(sequenced_index,Index,void)
|
||||
splice(iterator position,Index& x)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
||||
BOOST_MULTI_INDEX_CHECK_DIFFERENT_CONTAINER(*this,x);
|
||||
BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT;
|
||||
iterator first=x.begin(),last=x.end();
|
||||
while(first!=last){
|
||||
if(insert(position,*first).second)first=x.erase(first);
|
||||
else ++first;
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(
|
||||
position==end(),safe_mode::inside_range);
|
||||
}
|
||||
else{
|
||||
external_splice(
|
||||
position,x,x.begin(),x.end(),
|
||||
boost::is_copy_constructible<value_type>());
|
||||
}
|
||||
}
|
||||
|
||||
void splice(iterator position,sequenced_index<SuperMeta,TagList>& x,iterator i)
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(sequenced_index,Index,void)
|
||||
splice(iterator position,BOOST_RV_REF(Index) x)
|
||||
{
|
||||
splice(position,static_cast<Index&>(x));
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
|
||||
sequenced_index,Index,pair_return_type)
|
||||
splice(
|
||||
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
||||
@ -497,30 +510,36 @@ public:
|
||||
BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(i);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(i,x);
|
||||
BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT;
|
||||
if(&x==this){
|
||||
if(position!=i)relink(position.get_node(),i.get_node());
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
index_node_type* pn=position.get_node();
|
||||
index_node_type* in=static_cast<index_node_type*>(i.get_node());
|
||||
if(pn!=in)relink(pn,in);
|
||||
return std::pair<iterator,bool>(make_iterator(in),true);
|
||||
}
|
||||
else{
|
||||
if(insert(position,*i).second){
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
/* MSVC++ 6.0 optimizer has a hard time with safe mode, and the following
|
||||
* workaround is needed. Left it for all compilers as it does no
|
||||
* harm.
|
||||
*/
|
||||
i.detach();
|
||||
x.erase(x.make_iterator(i.get_node()));
|
||||
#else
|
||||
x.erase(i);
|
||||
#endif
|
||||
|
||||
}
|
||||
std::pair<final_node_type*,bool> p=
|
||||
external_splice(
|
||||
position,x,i,boost::is_copy_constructible<value_type>());
|
||||
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
||||
}
|
||||
}
|
||||
|
||||
void splice(
|
||||
iterator position,sequenced_index<SuperMeta,TagList>& x,
|
||||
iterator first,iterator last)
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(
|
||||
sequenced_index,Index,pair_return_type)
|
||||
splice(
|
||||
iterator position,BOOST_RV_REF(Index) x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator i)
|
||||
{
|
||||
return splice(position,static_cast<Index&>(x),i);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(sequenced_index,Index,void)
|
||||
splice(
|
||||
iterator position,Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(position);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(position,*this);
|
||||
@ -530,19 +549,26 @@ public:
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(last,x);
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_RANGE(first,last);
|
||||
BOOST_MULTI_INDEX_SEQ_INDEX_CHECK_INVARIANT;
|
||||
if(&x==this){
|
||||
if(x.end().get_node()==this->header()){ /* same container */
|
||||
BOOST_MULTI_INDEX_CHECK_OUTSIDE_RANGE(position,first,last);
|
||||
if(position!=last)relink(
|
||||
position.get_node(),first.get_node(),last.get_node());
|
||||
internal_splice(position,first,last);
|
||||
}
|
||||
else{
|
||||
while(first!=last){
|
||||
if(insert(position,*first).second)first=x.erase(first);
|
||||
else ++first;
|
||||
}
|
||||
external_splice(
|
||||
position,x,first,last,boost::is_copy_constructible<value_type>());
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
BOOST_MULTI_INDEX_ENABLE_IF_MERGEABLE(sequenced_index,Index,void)
|
||||
splice(
|
||||
iterator position,BOOST_RV_REF(Index) x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
splice(position,static_cast<Index&>(x),first,last);
|
||||
}
|
||||
|
||||
void remove(value_param_type value)
|
||||
{
|
||||
sequenced_index_remove(
|
||||
@ -640,6 +666,11 @@ public:
|
||||
BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
sequenced_index(const ctor_args_list& args_list,const allocator_type& al):
|
||||
super(args_list.get_tail(),al)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
empty_initialize();
|
||||
}
|
||||
@ -648,7 +679,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
super(x)
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe_super()
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
@ -660,7 +691,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
super(x,do_not_copy_elements_tag())
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
,safe_super()
|
||||
,safe(*this)
|
||||
#endif
|
||||
|
||||
{
|
||||
@ -674,9 +705,9 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
iterator make_iterator(index_node_type* node)
|
||||
{return iterator(node,this);}
|
||||
{return iterator(node,&safe);}
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
{return const_iterator(node,const_cast<sequenced_index*>(this));}
|
||||
{return const_iterator(node,const_cast<safe_container*>(&safe));}
|
||||
#else
|
||||
iterator make_iterator(index_node_type* node){return iterator(node);}
|
||||
const_iterator make_iterator(index_node_type* node)const
|
||||
@ -720,13 +751,14 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
return res;
|
||||
}
|
||||
|
||||
void extract_(index_node_type* x)
|
||||
template<typename Dst>
|
||||
void extract_(index_node_type* x,Dst dst)
|
||||
{
|
||||
unlink(x);
|
||||
super::extract_(x);
|
||||
super::extract_(x,dst.next());
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
detach_iterators(x);
|
||||
transfer_iterators(dst.get(),x);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -746,7 +778,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
empty_initialize();
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::detach_dereferenceable_iterators();
|
||||
safe.detach_dereferenceable_iterators();
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -755,7 +787,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
sequenced_index<SuperMeta,TagList>& x,BoolConstant swap_allocators)
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_(x,swap_allocators);
|
||||
@ -764,7 +796,7 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
void swap_elements_(sequenced_index<SuperMeta,TagList>& x)
|
||||
{
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_super::swap(x);
|
||||
safe.swap(x.safe);
|
||||
#endif
|
||||
|
||||
super::swap_elements_(x);
|
||||
@ -909,6 +941,13 @@ private:
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::detach_equivalent_iterators(it);
|
||||
}
|
||||
|
||||
template<typename Dst>
|
||||
void transfer_iterators(Dst& dst,index_node_type* x)
|
||||
{
|
||||
iterator it=make_iterator(x);
|
||||
safe_mode::transfer_equivalent_iterators(dst,it);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class InputIterator>
|
||||
@ -978,6 +1017,106 @@ private:
|
||||
return std::pair<iterator,bool>(make_iterator(p.first),p.second);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
std::pair<final_node_type*,bool> external_splice(
|
||||
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i,
|
||||
boost::true_type /* copy-constructible value */)
|
||||
{
|
||||
if(get_allocator()==x.get_allocator()){
|
||||
return external_splice(position,x,i,boost::false_type());
|
||||
}
|
||||
else{
|
||||
/* backwards compatibility with old, non-transfer-based splice */
|
||||
|
||||
std::pair<iterator,bool> p=insert(position,*i);
|
||||
if(p.second)x.erase(i);
|
||||
return std::pair<final_node_type*,bool>(
|
||||
static_cast<final_node_type*>(p.first.get_node()),p.second);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
std::pair<final_node_type*,bool> external_splice(
|
||||
iterator position,Index& x,BOOST_DEDUCED_TYPENAME Index::iterator i,
|
||||
boost::false_type /* copy-constructible value */)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
std::pair<final_node_type*,bool> p=this->final_transfer_(
|
||||
x,static_cast<final_node_type*>(i.get_node()));
|
||||
if(p.second&&position.get_node()!=header()){
|
||||
relink(position.get_node(),p.first);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
template<typename Iterator>
|
||||
void internal_splice(iterator position,Iterator first,Iterator last)
|
||||
{
|
||||
index_node_type* pn=position.get_node();
|
||||
while(first!=last){
|
||||
relink(pn,static_cast<index_node_type*>((first++).get_node()));
|
||||
}
|
||||
}
|
||||
|
||||
void internal_splice(iterator position,iterator first,iterator last)
|
||||
{
|
||||
index_node_type* pn=position.get_node();
|
||||
index_node_type* fn=static_cast<index_node_type*>(first.get_node());
|
||||
index_node_type* ln=static_cast<index_node_type*>(last.get_node());
|
||||
if(pn!=ln)relink(pn,fn,ln);
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
void external_splice(
|
||||
iterator position,Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last,
|
||||
boost::true_type /* copy-constructible value */)
|
||||
{
|
||||
if(get_allocator()==x.get_allocator()){
|
||||
external_splice(position,x,first,last,boost::false_type());
|
||||
}
|
||||
else{
|
||||
/* backwards compatibility with old, non-transfer-based splice */
|
||||
|
||||
while(first!=last){
|
||||
if(insert(position,*first).second)first=x.erase(first);
|
||||
else ++first;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
void external_splice(
|
||||
iterator position,Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last,
|
||||
boost::false_type /* copy-constructible value */)
|
||||
{
|
||||
BOOST_MULTI_INDEX_CHECK_EQUAL_ALLOCATORS(*this,x);
|
||||
if(position==end()){
|
||||
this->final_transfer_range_(x,first,last);
|
||||
}
|
||||
else{
|
||||
iterator first_to_relink=end();
|
||||
--first_to_relink;
|
||||
BOOST_TRY{
|
||||
this->final_transfer_range_(x,first,last);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
++first_to_relink;
|
||||
relink(position.get_node(),first_to_relink.get_node(),header());
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
++first_to_relink;
|
||||
relink(position.get_node(),first_to_relink.get_node(),header());
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
safe_container safe;
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_INVARIANT_CHECKING)&&\
|
||||
BOOST_WORKAROUND(__MWERKS__,<=0x3003)
|
||||
#pragma parse_mfunc_templ reset
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Multiply indexed container.
|
||||
*
|
||||
* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
* Copyright 2003-2021 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)
|
||||
@ -38,6 +38,7 @@
|
||||
#include <boost/multi_index/detail/converter.hpp>
|
||||
#include <boost/multi_index/detail/header_holder.hpp>
|
||||
#include <boost/multi_index/detail/has_tag.hpp>
|
||||
#include <boost/multi_index/detail/invalidate_iterators.hpp>
|
||||
#include <boost/multi_index/detail/no_duplicate_tags.hpp>
|
||||
#include <boost/multi_index/detail/safe_mode.hpp>
|
||||
#include <boost/multi_index/detail/scope_guard.hpp>
|
||||
@ -489,9 +490,7 @@ public:
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(
|
||||
it,static_cast<typename IteratorType::container_type&>(*this));
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,*this);
|
||||
return index_type::make_iterator(
|
||||
static_cast<final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -508,8 +507,7 @@ public:
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(
|
||||
it,static_cast<const typename IteratorType::container_type&>(*this));
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,*this);
|
||||
return index_type::make_iterator(
|
||||
static_cast<final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -541,8 +539,7 @@ public:
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(
|
||||
it,static_cast<typename IteratorType::container_type&>(*this));
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,*this);
|
||||
return index_type::make_iterator(
|
||||
static_cast<final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -559,8 +556,7 @@ public:
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(
|
||||
it,static_cast<const typename IteratorType::container_type&>(*this));
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,*this);
|
||||
return index_type::make_iterator(
|
||||
static_cast<final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -767,6 +763,19 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
std::pair<final_node_type*,bool> transfer_(Index& x,final_node_type* n)
|
||||
{
|
||||
final_node_type* res=super::insert_(n->value(),n,&super::final(x));
|
||||
if(res==n){
|
||||
++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)
|
||||
@ -923,14 +932,21 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
final_node_handle_type extract_(final_node_type* x)
|
||||
{
|
||||
--node_count;
|
||||
super::extract_(x);
|
||||
super::extract_(x,detail::invalidate_iterators());
|
||||
return final_node_handle_type(x,get_allocator());
|
||||
}
|
||||
|
||||
template<typename Dst>
|
||||
void extract_for_transfer_(final_node_type* x,Dst dst)
|
||||
{
|
||||
--node_count;
|
||||
super::extract_(x,dst);
|
||||
}
|
||||
|
||||
void erase_(final_node_type* x)
|
||||
{
|
||||
--node_count;
|
||||
super::extract_(x);
|
||||
super::extract_(x,detail::invalidate_iterators());
|
||||
delete_node_(x);
|
||||
}
|
||||
|
||||
@ -952,6 +968,17 @@ BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
|
||||
node_count=0;
|
||||
}
|
||||
|
||||
template<typename Index>
|
||||
void transfer_range_(
|
||||
Index& x,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator first,
|
||||
BOOST_DEDUCED_TYPENAME Index::iterator last)
|
||||
{
|
||||
while(first!=last){
|
||||
transfer_(x,static_cast<final_node_type*>((first++).get_node()));
|
||||
}
|
||||
}
|
||||
|
||||
void swap_(multi_index_container<Value,IndexSpecifierList,Allocator>& x)
|
||||
{
|
||||
swap_(
|
||||
@ -1332,14 +1359,7 @@ project(
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef detail::converter<
|
||||
multi_index_type,
|
||||
BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,m);
|
||||
return detail::converter<multi_index_type,index_type>::iterator(
|
||||
m,static_cast<typename multi_index_type::final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -1368,14 +1388,7 @@ project(
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef detail::converter<
|
||||
multi_index_type,
|
||||
BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,m);
|
||||
return detail::converter<multi_index_type,index_type>::const_iterator(
|
||||
m,static_cast<typename multi_index_type::final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -1418,14 +1431,7 @@ project(
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef detail::converter<
|
||||
multi_index_type,
|
||||
BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,m);
|
||||
return detail::converter<multi_index_type,index_type>::iterator(
|
||||
m,static_cast<typename multi_index_type::final_node_type*>(it.get_node()));
|
||||
}
|
||||
@ -1455,14 +1461,7 @@ project(
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it);
|
||||
|
||||
#if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
|
||||
typedef detail::converter<
|
||||
multi_index_type,
|
||||
BOOST_DEDUCED_TYPENAME IteratorType::container_type> converter;
|
||||
BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,converter::index(m));
|
||||
#endif
|
||||
|
||||
BOOST_MULTI_INDEX_CHECK_BELONGS_IN_SOME_INDEX(it,m);
|
||||
return detail::converter<multi_index_type,index_type>::const_iterator(
|
||||
m,static_cast<typename multi_index_type::final_node_type*>(it.get_node()));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Boost.MultiIndex test for standard list operations.
|
||||
*
|
||||
* Copyright 2003-2013 Joaquin M Lopez Munoz.
|
||||
* Copyright 2003-2021 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)
|
||||
@ -76,6 +76,7 @@ template<typename Sequence>
|
||||
static void test_list_ops_unique_seq()
|
||||
{
|
||||
typedef typename nth_index<Sequence,1>::type sequenced_index;
|
||||
typedef typename sequenced_index::iterator sequenced_index_iterator;
|
||||
|
||||
Sequence ss,ss2;
|
||||
sequenced_index &si=get<1>(ss),&si2=get<1>(ss2);
|
||||
@ -99,20 +100,32 @@ static void test_list_ops_unique_seq()
|
||||
|
||||
CHECK_EQUAL(si,(3)(5)(1));
|
||||
|
||||
si.splice(si.end(),si2);
|
||||
si.splice(si.end(),si2,project<1>(ss2,ss2.find(2)),si2.end());
|
||||
CHECK_EQUAL(si,(3)(5)(1)(2)(6));
|
||||
CHECK_EQUAL(si2,(3)(4)(0)(8)(5)(1));
|
||||
|
||||
si.splice(project<1>(ss,ss.find(2)),si2);
|
||||
CHECK_EQUAL(si,(3)(5)(1)(4)(0)(8)(2)(6));
|
||||
CHECK_EQUAL(si2,(3)(5)(1));
|
||||
|
||||
si.splice(project<1>(ss,ss.find(4)),si,project<1>(ss,ss.find(8)));
|
||||
CHECK_EQUAL(si,(3)(5)(1)(8)(4)(0)(2)(6));
|
||||
si2.clear();
|
||||
si2.splice(si2.begin(),si,si.begin());
|
||||
|
||||
si.splice(si.end(),si2,si2.begin());
|
||||
si2.clear();
|
||||
std::pair<sequenced_index_iterator,bool> p=
|
||||
si2.splice(si2.begin(),si,si.begin());
|
||||
BOOST_TEST(*(p.first)==3&&p.second);
|
||||
|
||||
p=si.splice(si.end(),si2,si2.begin());
|
||||
BOOST_TEST(*(p.first)==3&&p.second);
|
||||
CHECK_EQUAL(si,(5)(1)(8)(4)(0)(2)(6)(3));
|
||||
BOOST_TEST(si2.empty());
|
||||
|
||||
si2.splice(si2.end(),si,project<1>(ss,ss.find(0)),project<1>(ss,ss.find(6)));
|
||||
si2.splice(si2.end(),si,project<1>(ss,ss.find(2)),project<1>(ss,ss.find(6)));
|
||||
CHECK_EQUAL(si,(5)(1)(8)(4)(0)(6)(3));
|
||||
CHECK_EQUAL(si2,(2));
|
||||
|
||||
si2.splice(si2.begin(),si,project<1>(ss,ss.find(0)),project<1>(ss,ss.find(6)));
|
||||
CHECK_EQUAL(si,(5)(1)(8)(4)(6)(3));
|
||||
CHECK_EQUAL(si2,(0)(2));
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Boost.MultiIndex test for node handling operations.
|
||||
*
|
||||
* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
* Copyright 2003-2021 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)
|
||||
@ -23,8 +23,12 @@
|
||||
#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 <boost/type_traits/is_same.hpp>
|
||||
#include <boost/type_traits/remove_reference.hpp>
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include "count_allocator.hpp"
|
||||
|
||||
using namespace boost::multi_index;
|
||||
@ -136,7 +140,8 @@ 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)
|
||||
(boost::tuples::length<typename boost::remove_reference<Index>::
|
||||
type::ctor_args>::value > 0)
|
||||
>
|
||||
{};
|
||||
|
||||
@ -403,8 +408,410 @@ void test_transfer()
|
||||
BOOST_TEST(src.size()==8);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct enable_if_key_based:boost::enable_if_c<
|
||||
is_key_based<T>::value,
|
||||
void*
|
||||
>{};
|
||||
|
||||
template<typename T>
|
||||
struct enable_if_not_key_based:boost::enable_if_c<
|
||||
!is_key_based<T>::value,
|
||||
void*
|
||||
>{};
|
||||
|
||||
/* Boost.Move C++03 perfect forwarding emulation converts non-const lvalue
|
||||
* refs to const lvalue refs. final_forward undoes that.
|
||||
*/
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES)
|
||||
|
||||
template<typename T>
|
||||
T&& final_forward(typename boost::remove_reference<T>::type& x)
|
||||
{
|
||||
return static_cast<T&&>(x);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template<typename T>
|
||||
T& final_forward(const T& x){return const_cast<T&>(x);}
|
||||
|
||||
#endif
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void merge(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename enable_if_key_based<Dst>::type=0)
|
||||
{
|
||||
dst.merge(final_forward<Src>(src));
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void merge(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename enable_if_not_key_based<Dst>::type=0)
|
||||
{
|
||||
dst.splice(dst.end(),final_forward<Src>(src));
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
std::pair<typename Dst::iterator,bool> merge(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator i,
|
||||
typename enable_if_key_based<Dst>::type=0)
|
||||
{
|
||||
return dst.merge(final_forward<Src>(src),i);
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
std::pair<typename Dst::iterator,bool> merge(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator i,
|
||||
typename enable_if_not_key_based<Dst>::type=0)
|
||||
{
|
||||
return dst.splice(dst.end(),final_forward<Src>(src),i);
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void merge(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator first,
|
||||
typename boost::remove_reference<Src>::type::iterator last,
|
||||
typename enable_if_key_based<Dst>::type=0)
|
||||
{
|
||||
dst.merge(final_forward<Src>(src),first,last);
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void merge(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator first,
|
||||
typename boost::remove_reference<Src>::type::iterator last,
|
||||
typename enable_if_not_key_based<Dst>::type=0)
|
||||
{
|
||||
dst.splice(dst.end(),final_forward<Src>(src),first,last);
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void test_merge_same(Dst& dst,BOOST_FWD_REF(Src) src)
|
||||
{
|
||||
std::size_t n=dst.size();
|
||||
merge(dst,boost::forward<Src>(src));
|
||||
BOOST_TEST(dst.size()==n);
|
||||
BOOST_TEST(src.size()==n);
|
||||
}
|
||||
|
||||
template<typename Iterator,typename Value>
|
||||
bool find_address(Iterator first,Iterator last,const Value* x)
|
||||
{
|
||||
while(first!=last)if(&*first++==x)return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void test_merge_different(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,bool transferred_iters)
|
||||
{
|
||||
typedef typename boost::remove_reference<Src>::
|
||||
type::iterator src_iterator;
|
||||
typedef typename boost::remove_reference<Src>::
|
||||
type::value_type src_value_type;
|
||||
|
||||
std::size_t n=dst.size(),m=src.size();
|
||||
std::vector<
|
||||
std::pair<src_iterator,const src_value_type*>
|
||||
> v;
|
||||
for(src_iterator first=src.begin(),last=src.end();first!=last;++first){
|
||||
v.push_back(std::make_pair(first,&*first));
|
||||
}
|
||||
|
||||
merge(dst,boost::forward<Src>(src));
|
||||
BOOST_TEST(dst.size()>=n && m>=src.size() && dst.size()-n==m-src.size());
|
||||
for(std::size_t i=0;i<v.size();++i){
|
||||
BOOST_TEST(
|
||||
find_address(src.begin(),src.end(),v[i].second)||
|
||||
find_address(dst.begin(),dst.end(),v[i].second));
|
||||
}
|
||||
if(transferred_iters){
|
||||
for(std::size_t i=0;i<v.size();++i){
|
||||
BOOST_TEST(&*(v[i].first)==v[i].second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void test_merge_same(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator i,
|
||||
bool key_based=is_key_based<Dst>::value)
|
||||
{
|
||||
typedef typename Dst::iterator dst_iterator;
|
||||
|
||||
std::size_t n=dst.size();
|
||||
|
||||
std::pair<dst_iterator,bool> p=merge(dst,boost::forward<Src>(src),i);
|
||||
BOOST_TEST(dst.size()==n);
|
||||
BOOST_TEST(src.size()==n);
|
||||
BOOST_TEST(&*(p.first)==&*i && p.second);
|
||||
if(!key_based)BOOST_TEST(boost::next(p.first)==dst.end());
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void test_merge_different(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator i,
|
||||
bool key_based=is_key_based<Dst>::value)
|
||||
{
|
||||
typedef typename Dst::iterator dst_iterator;
|
||||
|
||||
std::size_t n=dst.size(),m=src.size();
|
||||
const typename Dst::value_type* pi=&*i;
|
||||
|
||||
std::pair<dst_iterator,bool> p=merge(dst,boost::forward<Src>(src),i);
|
||||
BOOST_TEST(dst.size()+src.size()==n+m);
|
||||
BOOST_TEST(p.second?
|
||||
&*(p.first)==pi:
|
||||
&*(p.first)!=pi && *(p.first)==*i);
|
||||
if(!key_based)BOOST_TEST(!p.second || boost::next(p.first)==dst.end());
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void test_merge_same(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator first,
|
||||
typename boost::remove_reference<Src>::type::iterator last,
|
||||
bool key_based=is_key_based<Dst>::value)
|
||||
{
|
||||
typedef typename Dst::iterator dst_iterator;
|
||||
typedef typename boost::remove_reference<Src>::
|
||||
type::iterator src_iterator;
|
||||
typedef typename boost::remove_reference<Src>::
|
||||
type::value_type src_value_type;
|
||||
|
||||
std::size_t n=dst.size(),d=std::distance(first,last);
|
||||
std::vector<const src_value_type*> v;
|
||||
for(src_iterator it=first;it!=last;++it)v.push_back(&*it);
|
||||
|
||||
merge(dst,boost::forward<Src>(src),first,last);
|
||||
BOOST_TEST(dst.size()==n);
|
||||
BOOST_TEST(src.size()==n);
|
||||
if(!key_based){
|
||||
dst_iterator it=boost::next(dst.begin(),dst.size()-d);
|
||||
for(std::size_t i=0;i<d;++i){
|
||||
BOOST_TEST(&*it++==v[i]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
src_iterator it=first;
|
||||
for(std::size_t i=0;i<d;++i){
|
||||
BOOST_TEST(&*it++==v[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Dst,typename Src>
|
||||
void test_merge_different(
|
||||
Dst& dst,BOOST_FWD_REF(Src) src,
|
||||
typename boost::remove_reference<Src>::type::iterator first,
|
||||
typename boost::remove_reference<Src>::type::iterator last,
|
||||
bool key_based=is_key_based<Dst>::value)
|
||||
{
|
||||
typedef typename Dst::iterator dst_iterator;
|
||||
typedef typename boost::remove_reference<Src>::
|
||||
type::iterator src_iterator;
|
||||
typedef typename boost::remove_reference<Src>::
|
||||
type::value_type src_value_type;
|
||||
|
||||
std::size_t n=dst.size(),
|
||||
m=src.size();
|
||||
std::vector<const src_value_type*> v;
|
||||
for(src_iterator it=first;it!=last;++it)v.push_back(&*it);
|
||||
|
||||
merge(dst,boost::forward<Src>(src),first,last);
|
||||
BOOST_TEST(dst.size()>=n && m>=src.size() && dst.size()-n==m-src.size());
|
||||
if(!key_based){
|
||||
for(dst_iterator it=boost::next(dst.begin(),n);it!=dst.end();++it){
|
||||
BOOST_TEST(std::find(v.begin(),v.end(),&*it)!=v.end());
|
||||
}
|
||||
}
|
||||
for(std::size_t i=0;i<v.size();++i){
|
||||
BOOST_TEST(
|
||||
find_address(src.begin(),src.end(),v[i])||
|
||||
find_address(dst.begin(),dst.end(),v[i]));
|
||||
}
|
||||
}
|
||||
|
||||
template<int N,int M,typename Dst>
|
||||
void test_merge_same(Dst& dst)
|
||||
{
|
||||
const Dst dst1=dst;
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
test_merge_same(
|
||||
dst2.template get<N>(),dst2.template get<M>());
|
||||
test_merge_same(
|
||||
dst2.template get<N>(),boost::move(dst2.template get<M>()));
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
test_merge_same(
|
||||
dst2.template get<N>(),dst2.template get<M>(),
|
||||
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
|
||||
test_merge_same(
|
||||
dst2.template get<N>(),boost::move(dst2.template get<M>()),
|
||||
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
test_merge_same(
|
||||
dst2.template get<N>(),dst2.template get<M>(),
|
||||
dst2.template get<M>().begin(),
|
||||
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
|
||||
test_merge_same(
|
||||
dst2.template get<N>(),boost::move(dst2.template get<M>()),
|
||||
dst2.template get<M>().begin(),
|
||||
boost::next(dst2.template get<M>().begin(),dst2.size()/2));
|
||||
}
|
||||
}
|
||||
|
||||
template<int N,int M,typename Dst,typename Src>
|
||||
void test_merge_different(Dst& dst,Src& src)
|
||||
{
|
||||
const Dst dst1=dst;
|
||||
const Src src1=src;
|
||||
const bool transferred_iters=
|
||||
boost::is_same<
|
||||
typename boost::multi_index::nth_index<Dst,M>::type::iterator,
|
||||
typename boost::multi_index::nth_index<Src,M>::type::iterator>::value;
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
Src src2=src1;
|
||||
test_merge_different(
|
||||
dst2.template get<N>(),src2.template get<M>(),transferred_iters);
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
Src src2=src1;
|
||||
test_merge_different(
|
||||
dst2.template get<N>(),boost::move(src2.template get<M>()),
|
||||
transferred_iters);
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
Src src2=src1;
|
||||
test_merge_different(
|
||||
dst2.template get<N>(),src2.template get<M>(),
|
||||
boost::next(src2.template get<M>().begin(),src2.size()/2));
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
Src src2=src1;
|
||||
test_merge_different(
|
||||
dst2.template get<N>(),boost::move(src2.template get<M>()),
|
||||
boost::next(src2.template get<M>().begin(),src2.size()/2));
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
Src src2=src1;
|
||||
test_merge_different(
|
||||
dst2.template get<N>(),src2.template get<M>(),
|
||||
src2.template get<M>().begin(),
|
||||
boost::next(src2.template get<M>().begin(),src2.size()/2));
|
||||
}
|
||||
{
|
||||
Dst dst2=dst1;
|
||||
Src src2=src1;
|
||||
test_merge_different(
|
||||
dst2.template get<N>(),boost::move(src2.template get<M>()),
|
||||
src2.template get<M>().begin(),
|
||||
boost::next(src2.template get<M>().begin(),src2.size()/2));
|
||||
}
|
||||
}
|
||||
|
||||
template<int N,int M,typename Dst,typename Src>
|
||||
void test_merge(Dst& dst,Src& src)
|
||||
{
|
||||
test_merge_different<N,M>(dst,src);
|
||||
}
|
||||
|
||||
template<int N,int M,typename Dst>
|
||||
void test_merge(Dst& dst,Dst& src)
|
||||
{
|
||||
if(&dst==&src)test_merge_same<N,M>(dst);
|
||||
else test_merge_different<N,M>(dst,src);
|
||||
}
|
||||
|
||||
struct another_int_hash
|
||||
{
|
||||
std::size_t operator()(int x)const
|
||||
{
|
||||
return boost::hash<int>()(x)*2;
|
||||
}
|
||||
};
|
||||
|
||||
void test_merge()
|
||||
{
|
||||
typedef multi_index_container<
|
||||
int,
|
||||
indexed_by<
|
||||
ordered_non_unique<identity<int> >,
|
||||
hashed_non_unique<identity<int> >,
|
||||
random_access<>,
|
||||
sequenced<>,
|
||||
ranked_non_unique<identity<int> >
|
||||
>
|
||||
> container1;
|
||||
|
||||
typedef multi_index_container<
|
||||
int,
|
||||
indexed_by<
|
||||
ordered_unique<
|
||||
identity<int>,
|
||||
std::greater<int>
|
||||
>,
|
||||
hashed_unique<
|
||||
identity<int>,
|
||||
another_int_hash
|
||||
>,
|
||||
random_access<>,
|
||||
sequenced<>,
|
||||
ranked_unique<
|
||||
identity<int>,
|
||||
std::greater<int>
|
||||
>
|
||||
>
|
||||
> container2;
|
||||
|
||||
container1 c1;
|
||||
container2 c2;
|
||||
for(int i=0;i<10;++i){
|
||||
c1.insert(i);
|
||||
c2.insert(2*i);
|
||||
}
|
||||
|
||||
test_merge<0,1>(c1,c1);
|
||||
test_merge<1,2>(c1,c1);
|
||||
test_merge<2,3>(c1,c1);
|
||||
test_merge<3,4>(c1,c1);
|
||||
test_merge<4,0>(c1,c1);
|
||||
test_merge<0,3>(c2,c2);
|
||||
test_merge<1,4>(c2,c2);
|
||||
test_merge<4,2>(c2,c2);
|
||||
|
||||
test_merge<0,1>(c1,c2);
|
||||
test_merge<1,2>(c1,c2);
|
||||
test_merge<2,3>(c1,c2);
|
||||
test_merge<3,4>(c1,c2);
|
||||
test_merge<4,0>(c1,c2);
|
||||
test_merge<0,3>(c2,c1);
|
||||
test_merge<1,4>(c2,c1);
|
||||
test_merge<4,2>(c2,c1);
|
||||
}
|
||||
|
||||
void test_node_handling()
|
||||
{
|
||||
test_node_handle();
|
||||
test_transfer();
|
||||
test_merge();
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
/* Boost.MultiIndex test for safe_mode.
|
||||
*
|
||||
* Copyright 2003-2020 Joaquin M Lopez Munoz.
|
||||
* Copyright 2003-2021 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)
|
||||
@ -326,7 +326,7 @@ static void local_test_safe_mode_with_rearrange()
|
||||
|
||||
TRY_SAFE_MODE
|
||||
i.splice(i.begin(),i);
|
||||
CATCH_SAFE_MODE(safe_mode::same_container)
|
||||
CATCH_SAFE_MODE(safe_mode::inside_range)
|
||||
|
||||
TRY_SAFE_MODE
|
||||
iterator it;
|
||||
|
Loading…
x
Reference in New Issue
Block a user