diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png index daaa7c8c..bf71c537 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png index efcc0431..a38c3fa1 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png index 3d6c7556..0794eb5f 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png index e4c76174..8da3eb16 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png index d66378f2..b760e7f8 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png index 87ce888b..68d6a996 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png index 1ce567a1..88564686 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png index 6864dc3f..6c0c1012 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png index a208b831..e587b266 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png index ca5179af..d8dca6d1 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png index 83fb7f70..bf38d42b 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png index b7b75652..da28fbc7 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png index 46df08d4..0edf67be 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png index 3d063557..58229fef 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png index 9ce8c189..63656943 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png index 865dd5d7..2aac2583 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png index ae1ab8d6..f21ed9c3 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png index b67d971d..2d10fb99 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png index a9b8b439..7bd41d66 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png index 556ddfd5..333a1e03 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png index d0c9965e..284de298 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png index 21825f61..09b34a89 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png index 38e6a2f0..a7df48c5 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png index 429396dd..40dc15a4 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png index 2e0839d0..5c0ebdf5 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png index 2f794f9d..b658b8d2 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png index d37dca1e..0a9885f1 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png index 1fa3c428..5c1debb8 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png index d3672e9a..72bd9dfc 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png index ccfaf51e..39c007c3 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png index edad91c4..a407d7c9 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png index f9e4598e..d6ddebed 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png index eb01649a..100bf11e 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png index ff18d099..2cb29575 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png index 06c305de..43677cf4 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png index c8619317..e83b0da1 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png index bc4e2032..28d41c72 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png index ba4eb83b..2e6d780c 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png index 11881e3a..767e5d8c 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png index d3571eb3..a4fe1f91 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png index 0d371ce2..b2f5ce93 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png index d4e6bd65..0745afbd 100644 Binary files a/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png and b/doc/diagrams/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/unordered/benchmarks.adoc b/doc/unordered/benchmarks.adoc index 46c70e91..4ba673e0 100644 --- a/doc/unordered/benchmarks.adoc +++ b/doc/unordered/benchmarks.adoc @@ -447,6 +447,10 @@ operations follow a https://en.wikipedia.org/wiki/Zipf%27s_law#Formal_definition with different _skew_ parameters: the higher the skew, the more concentrated are the keys in the lower values of the covered range. +`boost::concurrent_flat_map` is exercised using both regular and xref:#concurrent_bulk_visitation[bulk visitation]: +in the latter case, lookup keys are buffered in a local array and then processed at +once each time the buffer reaches xref:#concurrent_flat_map_constants[`bulk_visit_size`]. + === GCC 12, x64 diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index f99979c0..2de1ba66 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -13,6 +13,7 @@ with serial and parallel variants. * Added efficient move construction of `boost::unordered_flat_(map|set)` from `boost::concurrent_flat_(map|set)` and vice versa. +* Added bulk visitation to concurrent containers for increased lookup performance. * Added debug-mode mechanisms for detecting illegal reentrancies into a concurrent container from user code. * Added Boost.Serialization support to all containers and their (non-local) iterator types. diff --git a/doc/unordered/concurrent.adoc b/doc/unordered/concurrent.adoc index 1bb441b4..266ca95e 100644 --- a/doc/unordered/concurrent.adoc +++ b/doc/unordered/concurrent.adoc @@ -194,6 +194,55 @@ may be inserted, modified or erased by other threads during visitation. It is advisable not to assume too much about the exact global state of a concurrent container at any point in your program. +== Bulk visitation + +Suppose you have an `std::array` of keys you want to look up for in a concurrent map: + +[source,c++] +---- +std::array keys; +... +for(const auto& key: keys) { + m.visit(key, [](auto& x) { ++x.second; }); +} +---- + +_Bulk visitation_ allows us to pass all the keys in one operation: + +[source,c++] +---- +m.visit(keys.begin(), keys.end(), [](auto& x) { ++x.second; }); +---- + +This functionality is not provided for mere syntactic convenience, though: by processing all the +keys at once, some internal optimizations can be applied that increase +performance over the regular, one-at-a-time case (consult the +xref:#benchmarks_boostconcurrent_flat_map[benchmarks]). In fact, it may be beneficial +to buffer incoming keys so that they can be bulk visited in chunks: + +[source,c++] +---- +static constexpr auto bulk_visit_size = boost::concurrent_flat_map::bulk_visit_size; +std::array buffer; +std::size_t i=0; +while(...) { // processing loop + ... + buffer[i++] = k; + if(i == bulk_visit_size) { + map.visit(buffer.begin(), buffer.end(), [](auto& x) { ++x.second; }); + i = 0; + } + ... +} +// flush remaining keys +map.visit(buffer.begin(), buffer.begin() + i, [](auto& x) { ++x.second; }); +---- + +There's a latency/throughput tradeoff here: it will take longer for incoming keys to +be processed (since they are buffered), but the number of processed keys per second +is higher. `bulk_visit_size` is the recommended chunk size —smaller buffers +may yield worse performance. + == Blocking Operations ``boost::concurrent_flat_set``s and ``boost::concurrent_flat_map``s can be copied, assigned, cleared and merged just like any diff --git a/doc/unordered/concurrent_flat_map.adoc b/doc/unordered/concurrent_flat_map.adoc index 8dd00479..c58adf2a 100644 --- a/doc/unordered/concurrent_flat_map.adoc +++ b/doc/unordered/concurrent_flat_map.adoc @@ -50,6 +50,9 @@ namespace boost { using size_type = std::size_t; using difference_type = std::ptrdiff_t; + // constants + static constexpr size_type xref:#concurrent_flat_map_constants[bulk_visit_size] = _implementation-defined_; + // construct/copy/destroy xref:#concurrent_flat_map_default_constructor[concurrent_flat_map](); explicit xref:#concurrent_flat_map_bucket_count_constructor[concurrent_flat_map](size_type n, @@ -106,6 +109,13 @@ namespace boost { template size_t xref:#concurrent_flat_map_cvisit[visit](const K& k, F f) const; template size_t xref:#concurrent_flat_map_cvisit[cvisit](const K& k, F f) const; + template + size_t xref:concurrent_flat_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f); + template + size_t xref:concurrent_flat_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const; + template + size_t xref:concurrent_flat_map_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const; + template size_t xref:#concurrent_flat_map_cvisit_all[visit_all](F f); template size_t xref:#concurrent_flat_map_cvisit_all[visit_all](F f) const; template size_t xref:#concurrent_flat_map_cvisit_all[cvisit_all](F f) const; @@ -386,6 +396,13 @@ a function visiting elements of `m`) are detected and signalled through `BOOST_A When run-time speed is a concern, the feature can be disabled by globally defining this macro. +=== Constants + +```cpp +static constexpr size_type bulk_visit_size; +``` + +Chunk size internally used in xref:concurrent_flat_map_bulk_visit[bulk visit] operations. === Constructors @@ -722,6 +739,42 @@ Notes:;; The `template` overloads only participate in overload --- +==== Bulk visit + +```c++ +template + size_t visit(FwdIterator first, FwdIterator last, F f); +template + size_t visit(FwdIterator first, FwdIterator last, F f) const; +template + size_t cvisit(FwdIterator first, FwdIterator last, F f) const; +``` + +For each element `k` in the range [`first`, `last`), +if there is an element `x` in the container with key equivalent to `k`, +invokes `f` with a reference to `x`. +Such reference is const iff `*this` is const. + +Although functionally equivalent to individually invoking +xref:concurrent_flat_map_cvisit[`[c\]visit`] for each key, bulk visitation +performs generally faster due to internal streamlining optimizations. +It is advisable that `std::distance(first,last)` be at least +xref:#concurrent_flat_map_constants[`bulk_visit_size`] to enjoy +a performance gain: beyond this size, performance is not expected +to increase further. + +[horizontal] +Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^] +({cpp}11 to {cpp}17), +or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later). +For `K` = `std::iterator_traits::value_type`, either `K` is `key_type` or +else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. +In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. +This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +Returns:;; The number of elements visited. + +--- + ==== [c]visit_all ```c++ diff --git a/doc/unordered/concurrent_flat_set.adoc b/doc/unordered/concurrent_flat_set.adoc index c7c67aaa..b9436708 100644 --- a/doc/unordered/concurrent_flat_set.adoc +++ b/doc/unordered/concurrent_flat_set.adoc @@ -45,6 +45,9 @@ namespace boost { using size_type = std::size_t; using difference_type = std::ptrdiff_t; + // constants + static constexpr size_type xref:#concurrent_flat_set_constants[bulk_visit_size] = _implementation-defined_; + // construct/copy/destroy xref:#concurrent_flat_set_default_constructor[concurrent_flat_set](); explicit xref:#concurrent_flat_set_bucket_count_constructor[concurrent_flat_set](size_type n, @@ -98,6 +101,11 @@ namespace boost { template size_t xref:#concurrent_flat_set_cvisit[visit](const K& k, F f) const; template size_t xref:#concurrent_flat_set_cvisit[cvisit](const K& k, F f) const; + template + size_t xref:concurrent_flat_set_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const; + template + size_t xref:concurrent_flat_set_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const; + template size_t xref:#concurrent_flat_set_cvisit_all[visit_all](F f) const; template size_t xref:#concurrent_flat_set_cvisit_all[cvisit_all](F f) const; template @@ -340,6 +348,13 @@ a function visiting elements of `m`) are detected and signalled through `BOOST_A When run-time speed is a concern, the feature can be disabled by globally defining this macro. +=== Constants + +```cpp +static constexpr size_type bulk_visit_size; +``` + +Chunk size internally used in xref:concurrent_flat_set_bulk_visit[bulk visit] operations. === Constructors @@ -672,6 +687,39 @@ Notes:;; The `template` overloads only participate in overload --- +==== Bulk visit + +```c++ +template + size_t visit(FwdIterator first, FwdIterator last, F f) const; +template + size_t cvisit(FwdIterator first, FwdIterator last, F f) const; +``` + +For each element `k` in the range [`first`, `last`), +if there is an element `x` in the container with key equivalent to `k`, +invokes `f` with a const reference to `x`. + +Although functionally equivalent to individually invoking +xref:concurrent_flat_set_cvisit[`[c\]visit`] for each key, bulk visitation +performs generally faster due to internal streamlining optimizations. +It is advisable that `std::distance(first,last)` be at least +xref:#concurrent_flat_set_constants[`bulk_visit_size`] to enjoy +a performance gain: beyond this size, performance is not expected +to increase further. + +[horizontal] +Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^] +({cpp}11 to {cpp}17), +or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later). +For `K` = `std::iterator_traits::value_type`, either `K` is `key_type` or +else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. +In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. +This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +Returns:;; The number of elements visited. + +--- + ==== [c]visit_all ```c++ diff --git a/include/boost/unordered/concurrent_flat_map.hpp b/include/boost/unordered/concurrent_flat_map.hpp index 8fb5ec2e..07b6ea7b 100644 --- a/include/boost/unordered/concurrent_flat_map.hpp +++ b/include/boost/unordered/concurrent_flat_map.hpp @@ -1,6 +1,7 @@ /* Fast open-addressing concurrent hashmap. * * Copyright 2023 Christian Mazakas. + * Copyright 2023 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) @@ -72,6 +73,7 @@ namespace boost { using pointer = typename boost::allocator_pointer::type; using const_pointer = typename boost::allocator_const_pointer::type; + static constexpr size_type bulk_visit_size = table_type::bulk_visit_size; concurrent_flat_map() : concurrent_flat_map(detail::foa::default_bucket_count) @@ -270,6 +272,33 @@ namespace boost { return table_.visit(std::forward(k), f); } + template + BOOST_FORCEINLINE + size_t visit(FwdIterator first, FwdIterator last, F f) + { + BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator) + BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) + return table_.visit(first, last, f); + } + + template + BOOST_FORCEINLINE + size_t visit(FwdIterator first, FwdIterator last, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator) + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(first, last, f); + } + + template + BOOST_FORCEINLINE + size_t cvisit(FwdIterator first, FwdIterator last, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator) + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(first, last, f); + } + template size_type visit_all(F f) { BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) diff --git a/include/boost/unordered/concurrent_flat_set.hpp b/include/boost/unordered/concurrent_flat_set.hpp index fea086be..c55a9681 100644 --- a/include/boost/unordered/concurrent_flat_set.hpp +++ b/include/boost/unordered/concurrent_flat_set.hpp @@ -38,7 +38,10 @@ namespace boost { using type_policy = detail::foa::flat_set_types; - detail::foa::concurrent_table table_; + using table_type = + detail::foa::concurrent_table; + + table_type table_; template bool friend operator==(concurrent_flat_set const& lhs, @@ -67,6 +70,7 @@ namespace boost { using pointer = typename boost::allocator_pointer::type; using const_pointer = typename boost::allocator_const_pointer::type; + static constexpr size_type bulk_visit_size = table_type::bulk_visit_size; concurrent_flat_set() : concurrent_flat_set(detail::foa::default_bucket_count) @@ -251,6 +255,24 @@ namespace boost { return table_.visit(std::forward(k), f); } + template + BOOST_FORCEINLINE + size_t visit(FwdIterator first, FwdIterator last, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator) + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(first, last, f); + } + + template + BOOST_FORCEINLINE + size_t cvisit(FwdIterator first, FwdIterator last, F f) const + { + BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator) + BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) + return table_.visit(first, last, f); + } + template size_type visit_all(F f) const { BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) diff --git a/include/boost/unordered/detail/concurrent_static_asserts.hpp b/include/boost/unordered/detail/concurrent_static_asserts.hpp index 93717534..48784ac8 100644 --- a/include/boost/unordered/detail/concurrent_static_asserts.hpp +++ b/include/boost/unordered/detail/concurrent_static_asserts.hpp @@ -10,10 +10,12 @@ #ifndef BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP #define BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP +#include #include #include #include +#include #include #define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \ @@ -72,4 +74,32 @@ namespace boost { } // namespace boost +#if defined(BOOST_NO_CXX20_HDR_CONCEPTS) +#define BOOST_UNORDERED_STATIC_ASSERT_FWD_ITERATOR(Iterator) \ + static_assert( \ + std::is_base_of< \ + std::forward_iterator_tag, \ + typename std::iterator_traits::iterator_category>::value, \ + "The provided iterator must be at least forward"); +#else +#define BOOST_UNORDERED_STATIC_ASSERT_FWD_ITERATOR(Iterator) \ + static_assert(std::forward_iterator, \ + "The provided iterator must be at least forward"); + +#endif + +#define BOOST_UNORDERED_STATIC_ASSERT_KEY_COMPATIBLE_ITERATOR(Iterator) \ + static_assert( \ + std::is_same< \ + typename std::iterator_traits::value_type, \ + key_type>::value || \ + detail::are_transparent< \ + typename std::iterator_traits::value_type, \ + hasher, key_equal>::value, \ + "The provided iterator must dereference to a compatible key value"); + +#define BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(Iterator) \ + BOOST_UNORDERED_STATIC_ASSERT_FWD_ITERATOR(Iterator) \ + BOOST_UNORDERED_STATIC_ASSERT_KEY_COMPATIBLE_ITERATOR(Iterator) + #endif // BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP diff --git a/include/boost/unordered/detail/foa/concurrent_table.hpp b/include/boost/unordered/detail/foa/concurrent_table.hpp index 54341396..40a66c73 100644 --- a/include/boost/unordered/detail/foa/concurrent_table.hpp +++ b/include/boost/unordered/detail/foa/concurrent_table.hpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -465,6 +466,7 @@ public: using key_equal=typename super::key_equal; using allocator_type=typename super::allocator_type; using size_type=typename super::size_type; + static constexpr std::size_t bulk_visit_size=16; private: template @@ -564,6 +566,27 @@ public: return visit(x,std::forward(f)); } + template + BOOST_FORCEINLINE + std::size_t visit(FwdIterator first,FwdIterator last,F&& f) + { + return bulk_visit_impl(group_exclusive{},first,last,std::forward(f)); + } + + template + BOOST_FORCEINLINE + std::size_t visit(FwdIterator first,FwdIterator last,F&& f)const + { + return bulk_visit_impl(group_shared{},first,last,std::forward(f)); + } + + template + BOOST_FORCEINLINE + std::size_t cvisit(FwdIterator first,FwdIterator last,F&& f)const + { + return visit(first,last,std::forward(f)); + } + template std::size_t visit_all(F&& f) { return visit_all_impl(group_exclusive{},std::forward(f)); @@ -1051,6 +1074,26 @@ private: access_mode,x,this->position_for(hash),hash,std::forward(f)); } + template + BOOST_FORCEINLINE + std::size_t bulk_visit_impl( + GroupAccessMode access_mode,FwdIterator first,FwdIterator last,F&& f)const + { + auto lck=shared_access(); + std::size_t res=0; + auto n=static_cast(std::distance(first,last)); + while(n){ + auto m=n<2*bulk_visit_size?n:bulk_visit_size; + res+=unprotected_bulk_visit(access_mode,first,m,std::forward(f)); + n-=m; + std::advance( + first, + static_cast< + typename std::iterator_traits::difference_type>(m)); + } + return res; + } + template std::size_t visit_all_impl(GroupAccessMode access_mode,F&& f)const { @@ -1149,6 +1192,76 @@ private: return 0; } + template + BOOST_FORCEINLINE std::size_t unprotected_bulk_visit( + GroupAccessMode access_mode,FwdIterator first,std::size_t m,F&& f)const + { + BOOST_ASSERT(m<2*bulk_visit_size); + + std::size_t res=0, + hashes[2*bulk_visit_size-1], + positions[2*bulk_visit_size-1]; + int masks[2*bulk_visit_size-1]; + auto it=first; + + for(auto i=m;i--;++it){ + auto hash=hashes[i]=this->hash_for(*it); + auto pos=positions[i]=this->position_for(hash); + BOOST_UNORDERED_PREFETCH(this->arrays.groups()+pos); + } + + for(auto i=m;i--;){ + auto hash=hashes[i]; + auto pos=positions[i]; + auto mask=masks[i]=(this->arrays.groups()+pos)->match(hash); + if(mask){ + BOOST_UNORDERED_PREFETCH(this->arrays.group_accesses()+pos); + BOOST_UNORDERED_PREFETCH_ELEMENTS(this->arrays.elements()+pos*N,N); + } + } + + it=first; + for(auto i=m;i--;++it){ + auto pos=positions[i]; + prober pb(pos); + auto pg=this->arrays.groups()+pos; + auto mask=masks[i]; + element_type *p; + if(!mask)goto post_mask; + p=this->arrays.elements()+pos*N; + for(;;){ + { + auto lck=access(access_mode,pos); + do{ + auto n=unchecked_countr_zero(mask); + if(BOOST_LIKELY( + pg->is_occupied(n)&& + bool(this->pred()(*it,this->key_from(p[n]))))){ + f(cast_for(access_mode,type_policy::value_from(p[n]))); + ++res; + goto next_key; + } + mask&=mask-1; + }while(mask); + } + post_mask: + do{ + if(BOOST_LIKELY(pg->is_not_overflowed(hashes[i]))|| + BOOST_UNLIKELY(!pb.next(this->arrays.groups_size_mask))){ + goto next_key; + } + pos=pb.get(); + pg=this->arrays.groups()+pos; + mask=pg->match(hashes[i]); + }while(!mask); + p=this->arrays.elements()+pos*N; + BOOST_UNORDERED_PREFETCH_ELEMENTS(p,N); + } + next_key:; + } + return res; + } + #if defined(BOOST_MSVC) #pragma warning(pop) /* C4800 */ #endif diff --git a/include/boost/unordered/detail/foa/core.hpp b/include/boost/unordered/detail/foa/core.hpp index ddc71917..0ffbfc03 100644 --- a/include/boost/unordered/detail/foa/core.hpp +++ b/include/boost/unordered/detail/foa/core.hpp @@ -92,7 +92,7 @@ #elif defined(BOOST_UNORDERED_SSE2) #define BOOST_UNORDERED_PREFETCH(p) _mm_prefetch((const char*)(p),_MM_HINT_T0) #else -#define BOOST_UNORDERED_PREFETCH(p) ((void)0) +#define BOOST_UNORDERED_PREFETCH(p) ((void)(p)) #endif /* We have experimentally confirmed that ARM architectures get a higher diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 003b6d0c..5ead9944 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -20,7 +20,7 @@ function(foa_tests) endfunction() function(cfoa_tests) - boost_test(PREFIX boost_unordered_cfoa LINK_LIBRARIES Boost::compat Threads::Threads ${ARGN}) + boost_test(PREFIX boost_unordered_cfoa LINK_LIBRARIES Boost::compat Boost::iterator Threads::Threads ${ARGN}) endfunction() # FCA tests diff --git a/test/cfoa/visit_tests.cpp b/test/cfoa/visit_tests.cpp index d604bffa..61452ef7 100644 --- a/test/cfoa/visit_tests.cpp +++ b/test/cfoa/visit_tests.cpp @@ -3,13 +3,29 @@ // 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) +#include +#include + +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40900) +// warning triggered in transform_iterator.hpp transitive includes +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wconversion" +#pragma GCC diagnostic ignored "-Wsign-conversion" +#endif + #include "helpers.hpp" #include #include #include +#include +#if BOOST_WORKAROUND(BOOST_GCC_VERSION, < 40900) +#pragma GCC diagnostic pop +#endif + +#include #include #include #include @@ -825,6 +841,129 @@ namespace { check_raii_counts(); } + struct regular_key_extractor + { + template + auto operator()(const T& x) const -> decltype(get_key(x)) + { + return get_key(x); + } + } regular_key_extract; + + struct transp_key_extractor + { + template + auto operator()(const T& x) const -> decltype((get_key(x).x_)) + { + return get_key(x).x_; + } + } transp_key_extract; + + template + void bulk_visit( + X*, KeyExtractor key_extract, GF gen_factory, test::random_generator rg) + { + using key_type = typename X::key_type; + using value_type = typename X::value_type; + + // concurrent_flat_set visit is always const access + using arg_type = typename std::conditional< + std::is_same::value, + value_type const, + value_type + >::type; + + auto gen = gen_factory.template get(); + auto values = make_random_values(16384 * 16, [&] { return gen(rg); }); + + using values_type = decltype(values); + using span_value_type = typename values_type::value_type; + + raii::reset_counts(); + + { + X x; + for (auto const& v: values) { + if (get_key(v).x_ % 3 != 0) x.insert(v); + } + X const& cx = x; + + std::uint64_t old_default_constructor = raii::default_constructor; + std::uint64_t old_copy_constructor = raii::copy_constructor; + std::uint64_t old_move_constructor = raii::move_constructor; + std::uint64_t old_copy_assignment = raii::copy_assignment; + std::uint64_t old_move_assignment = raii::move_assignment; + + std::atomic num_visits{0}; + + thread_runner(values, [&x, &cx, &num_visits, key_extract] + (boost::span s) { + auto it = boost::make_transform_iterator(s.begin(), key_extract); + + std::size_t n = s.size(), m = 0, q = 0; + + auto found = [&it, &m](value_type const& v) { + return std::find( + it, it + (std::ptrdiff_t)m, get_key(v)) != it + (std::ptrdiff_t)m; + }; + + while (n) { + if (m > n) m = n; + + switch (q % 3) { + case 0: + x.visit( + it, it + (std::ptrdiff_t)m, + [&num_visits, &found](arg_type& v) { + if ( found(v) ) ++num_visits; + }); + break; + case 1: + cx.visit( + it, it + (std::ptrdiff_t)m, + [&num_visits, &found](value_type const& v) { + if ( found(v) ) ++num_visits; + }); + break; + case 2: + cx.cvisit( + it, it + (std::ptrdiff_t)m, + [&num_visits, &found](value_type const& v) { + if ( found(v) ) ++num_visits; + }); + break; + default: + break; + } + it += (std::ptrdiff_t)m; + n -= m; + ++m; + if (m > 5*X::bulk_visit_size){ + m = 0; + ++ q; + } + } + }); + + BOOST_TEST_EQ(num_visits, x.size()); + + BOOST_TEST_EQ(old_default_constructor, raii::default_constructor); + BOOST_TEST_EQ(old_copy_constructor, raii::copy_constructor); + BOOST_TEST_EQ(old_move_constructor, raii::move_constructor); + BOOST_TEST_EQ(old_copy_assignment, raii::copy_assignment); + BOOST_TEST_EQ(old_move_assignment, raii::move_assignment); + } + + BOOST_TEST_GE(raii::default_constructor, 0u); + BOOST_TEST_GE(raii::copy_constructor, 0u); + BOOST_TEST_GE(raii::move_constructor, 0u); + BOOST_TEST_GT(raii::destructor, 0u); + + BOOST_TEST_EQ(raii::default_constructor + raii::copy_constructor + + raii::move_constructor, + raii::destructor); + } + boost::unordered::concurrent_flat_map* map; boost::unordered::concurrent_flat_map* transp_map; @@ -869,6 +1008,22 @@ UNORDERED_TEST( ((sequential)) ) +UNORDERED_TEST( + bulk_visit, + ((map)(set)) + ((regular_key_extract)) + ((value_type_generator_factory)) + ((sequential)) +) + +UNORDERED_TEST( + bulk_visit, + ((transp_map)(transp_set)) + ((transp_key_extract)) + ((value_type_generator_factory)) + ((sequential)) +) + // clang-format on RUN_TESTS()