diff --git a/doc/reference/hash_indices.html b/doc/reference/hash_indices.html index c3aeb83..1e1c838 100644 --- a/doc/reference/hash_indices.html +++ b/doc/reference/hash_indices.html @@ -308,6 +308,16 @@ requirements. void clear()noexcept; void swap(index class name& x); + template<typename Index> void merge(Index&& x); + template<typename Index> + std::pair<iterator,bool> merge( + Index&& x,typename std::remove_reference_t<Index>::const_iterator i); + template<typename Index> + void merge( + Index&& x, + typename std::remove_reference_t<Index>::const_iterator first, + typename std::remove_reference_t<Index>::const_iterator last); + // observers: key_from_value key_extractor()const; @@ -474,7 +484,9 @@ local_iterator
const_local_iterator
-These types are forward iterators. +These types are forward iterators. They depend only on node_type 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).

Constructors, copy and assignment

@@ -925,6 +937,89 @@ with mod' and back defined in such a way that key is the internal KeyFromValue object of the index. +template<typename Index> void merge(Index&& x); + +
+Requires: x is a non-const reference to an index of a +node-compatible +multi_index_container. get_allocator()==x.get_allocator().
+Effects: +
+merge(x,x.begin(),x.end());
+
+
+ + +template<typename Index> std::pair<iterator,bool> merge(
+  Index&& x,typename std::remove_reference_t<Index>::const_iterator i); +
+ +
+Requires: x is a non-const reference to an index of a +node-compatible +multi_index_container. get_allocator()==x.get_allocator(). +i is a valid dereferenceable iterator of x.
+Effects: Does nothing if the source and destination containers are the same; +otherwise, transfers the node of the element referred to by i into the +multi_index_container to which the destination index belongs if + +Note that no element is copied or destroyed in the process.
+Postconditions: If transfer succeeds, for any index in the source container +having the same iterator/const_iterator types as the corresponding +index in the destination container, iterators referring to *i +remain valid and behave as iterators of the destination index.
+Returns: The return value is a pair p. p.second +is true if and only if transfer took place or the source and destination +containers are the same. If p.second is true, +p.first points to *i; otherwise, p.first +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.
+Complexity: If the source and destination containers are the same, +constant; otherwise, O(I(n)+D(x.size())).
+Exception safety: If the source and destination containers are the same, +nothrow; otherwise strong. +
+ + +template<typename Index> void merge(
+  Index&& x,
+  typename std::remove_reference_t<Index>::const_iterator first,
+  typename std::remove_reference_t<Index>::const_iterator last); +
+ +
+Requires: x is a non-const reference to an index of a +node-compatible +multi_index_container. get_allocator()==x.get_allocator(). +[first,last) is a valid range of x.
+Effects: Does nothing if the source and destination containers are the same; +otherwise, for each node in [first,last), in this order, +the node is transferred to the multi_index_container to which the +destination index belongs if + +Note that no element is copied or destroyed in the process.
+Postconditions: For any index in the source container having the same +iterator/const_iterator 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.
+Complexity: If the source and destination containers are the same, +constant; otherwise, O(m*(I(n+m)+D(x.size()))), where +m is the number of elements in [first, +last).
+Exception safety: If the source and destination containers are the same, +nothrow; otherwise basic. +
+

Observers

Apart from standard hash_function and key_eq, @@ -1275,7 +1370,7 @@ Sequenced indices
-

Revised July 29th 2021

+

Revised August 16th 2021

© Copyright 2003-2021 Joaquín M López Muñoz. Distributed under the Boost Software diff --git a/doc/reference/ord_indices.html b/doc/reference/ord_indices.html index 34600f2..af5b491 100644 --- a/doc/reference/ord_indices.html +++ b/doc/reference/ord_indices.html @@ -42,6 +42,7 @@ Ranked indices

@@ -282,7 +283,7 @@ determining whether a hashed index is preferred over an ordered one.

-Hashed indices replicate the interface as std::unordered_set and +Hashed indices replicate the interface of std::unordered_set and std::unordered_multiset, with only minor differences where required by the general constraints of multi_index_containers, 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:

+

Node handling operations

+ +

+Using direct node manipulation, elements can be passed between +multi_index_containers without actually copying them: +

+ +
+// move an employee to the retiree archive
+void move_to_retirement(int ssnumber,employee_set& es,employee_set& archive)
+{
+  // assume employee_set has an index on SS number(not shown before)
+  // extract the employee with given SS number to a node handle
+  employee_set_by_ssn::node_type node=es.get<ssn>().extract(ssnumber);
+
+  if(!node.empty()){ // employee found
+    // re-insert into archive (note the use of std::move)
+    archive.insert(std::move(node));
+  }
+}
+
+ +

+In the example, the internal node is transferred as-is from es to archive, +which is more efficient than erasing from the source and recreating in destination. +node_type is a move-only class used to pass nodes around, and its interface follows +that of the homonym type +for C++ associative containers (set containers version). Boost.MultiIndex provides node extraction +and insertion operations for all index types, including sequenced ones (by contrast, +std::list does not have such features): +

+ +
+multi_index_container<
+  int,
+  indexed_by<
+    sequenced<>,
+    ordered_unique<identity<int> >
+  >
+> src;
+
+multi_index_container<
+  int,
+  indexed_by<
+    sequenced<>,
+    ordered_non_unique<identity<int>, std::greater<int> >
+  >
+> dst;
+
+...
+
+// transfer even numbers from src to dst
+for(auto first=src.begin(),last=src.end();first!=last;){
+  if(*first%2==0) dst.insert(dst.end(),src.extract(first++));
+  else            ++first;
+}
+
+ +

+Note that src and dst are of different types, +yet transfer is possible. Two multi_index_containers are +node-compatible (that is, they use the same node_type) 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. +

+ +

+Alternatively, direct node transfer between two containers can be done without +keeping intervening node_types thanks to merge (key-based +indices) and splice (non key-based indices). +

+ +
+// move older employees to retirement
+void move_to_retirement_by_age(
+  int max_age,employee_set& es,employee_set& archive)
+{
+  // assume employee_set has an index on age (not shown before)
+  employee_set_by_age& ea=es.get<age>();
+
+  // archive employees with age>max_age
+  archive.merge(ea,ea.upper_bound(max_age),ea.end());
+}
+
+...
+
+// transfer even numbers from src to dst
+for(auto first=src.begin(),last=src.end();first!=last;){
+  if(*first%2==0) dst.splice(dst.end(),src,first++);
+  else            ++first;
+}
+
+ +

+There are overloads of merge/splice for transferring a single element, +a range between two iterators and an entire container: for further details, consult +for instance the reference for ordered indices and for +sequenced indices +(the rest of indices provide one interface or the other). +Please note that sequenced and random access indices do also have an operation called merge, +but this follows the specification of std::list::merge, 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. +

+

Ordered indices node compression

@@ -821,7 +929,7 @@ Key extraction
-

Revised July 29th 2021

+

Revised August 16th 2021

© Copyright 2003-2021 Joaquín M López Muñoz. Distributed under the Boost Software