From bf4a5efd2d8cab5f593f58bc9fde2872ce9b332e Mon Sep 17 00:00:00 2001 From: joaquintides Date: Sun, 23 Jul 2023 12:23:08 +0200 Subject: [PATCH] documented concurrent/unordered interop --- doc/unordered/changes.adoc | 2 ++ doc/unordered/concurrent.adoc | 26 ++++++++++++++++++++++++++ doc/unordered/concurrent_flat_map.adoc | 16 ++++++++++++++++ doc/unordered/unordered_flat_map.adoc | 17 +++++++++++++++++ 4 files changed, 61 insertions(+) diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index 757a7000..1d760650 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -10,6 +10,8 @@ * Added `[c]visit_while` operations to `boost::concurrent_map`, with serial and parallel variants. +* Added efficient move construction of `boost::unordered_flat_map` from +`boost::concurrent_flat_map` and vice versa. == Release 1.83.0 - Major update diff --git a/doc/unordered/concurrent.adoc b/doc/unordered/concurrent.adoc index 7ed1be44..d418cec4 100644 --- a/doc/unordered/concurrent.adoc +++ b/doc/unordered/concurrent.adoc @@ -201,3 +201,29 @@ and the user need not take any special precaution, but overall performance may b Another blocking operation is _rehashing_, which happens explicitly via `rehash`/`reserve` or during insertion when the table's load hits `max_load()`. As with non-concurrent containers, reserving space in advance of bulk insertions will generally speed up the process. + +== Interoperability with non-concurrent containers + +As their internal data structure is basically the same, `boost::unordered_flat_map` can +be efficiently move-constructed from `boost::concurrent_flat_map` and vice versa. +This interoperability comes handy in multistage scenarios where parts of the data processing happen +in parallel whereas other steps are non-concurrent (or non-modifying). In the following example, +we want to construct a histogram from a huge input vector of words: +the population phase can be done in parallel with `boost::concurrent_flat_map` and results +then transferred to the final container. + +[source,c++] +---- +std::vector words = ...; + +// Insert words in parallel +boost::concurrent_flat_map m0; +std::for_each( + std::execution::par, words.begin(), words.end(), + [&](const auto& word) { + m0.try_emplace_or_visit(word, 1, [](auto& x) { ++x.second; }); + }); + +// Transfer to a regular unordered_flat_map +boost::unordered_flat_map m=std::move(m0); +---- diff --git a/doc/unordered/concurrent_flat_map.adoc b/doc/unordered/concurrent_flat_map.adoc index 8038f210..bca4f5bb 100644 --- a/doc/unordered/concurrent_flat_map.adoc +++ b/doc/unordered/concurrent_flat_map.adoc @@ -69,6 +69,7 @@ namespace boost { explicit xref:#concurrent_flat_map_allocator_constructor[concurrent_flat_map](const Allocator& a); xref:#concurrent_flat_map_copy_constructor_with_allocator[concurrent_flat_map](const concurrent_flat_map& other, const Allocator& a); xref:#concurrent_flat_map_move_constructor_with_allocator[concurrent_flat_map](concurrent_flat_map&& other, const Allocator& a); + xref:#concurrent_flat_map_move_constructor_from_unordered_flat_map[concurrent_flat_map](unordered_flat_map&& other); xref:#concurrent_flat_map_initializer_list_constructor[concurrent_flat_map](std::initializer_list il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -501,6 +502,21 @@ Concurrency:;; Blocking on `other`. --- +==== Move Constructor from unordered_flat_map + +```c++ +concurrent_flat_map(unordered_flat_map&& other); +``` + +Move construction from a xref:#unordered_flat_map[`unordered_flat_map`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. + +[horizontal] +Complexity:;; O(`bucket_count()`) + +--- + ==== Initializer List Constructor [source,c++,subs="+quotes"] ---- diff --git a/doc/unordered/unordered_flat_map.adoc b/doc/unordered/unordered_flat_map.adoc index a112e192..543db307 100644 --- a/doc/unordered/unordered_flat_map.adoc +++ b/doc/unordered/unordered_flat_map.adoc @@ -77,6 +77,7 @@ namespace boost { explicit xref:#unordered_flat_map_allocator_constructor[unordered_flat_map](const Allocator& a); xref:#unordered_flat_map_copy_constructor_with_allocator[unordered_flat_map](const unordered_flat_map& other, const Allocator& a); xref:#unordered_flat_map_move_constructor_with_allocator[unordered_flat_map](unordered_flat_map&& other, const Allocator& a); + xref:#unordered_flat_map_move_constructor_from_concurrent_flat_map[unordered_flat_map](concurrent_flat_map&& other); xref:#unordered_flat_map_initializer_list_constructor[unordered_flat_map](std::initializer_list il, size_type n = _implementation-defined_ const hasher& hf = hasher(), @@ -472,6 +473,22 @@ from `other`, and the allocator is copy-constructed from `a`. --- +==== Move Constructor from concurrent_flat_map + +```c++ +unordered_flat_map(concurrent_flat_map&& other); +``` + +Move construction from a xref:#concurrent_flat_map[`concurrent_flat_map`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. + +[horizontal] +Complexity:;; Constant time. +Concurrency:;; Blocking on `other`. + +--- + ==== Initializer List Constructor [source,c++,subs="+quotes"] ----