Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b41c054c66 | |||
| fbc981eac9 | |||
| 5d2b27d1d9 | |||
| a36937d9b5 | |||
| e214ecdbd0 | |||
| 94ab2f0776 | |||
| 1bdb3717d3 | |||
| cfdfae0a65 | |||
| 489b50bc0f | |||
| 3fe7871745 | |||
| 1e043993ac | |||
| 834580b539 |
@@ -279,14 +279,14 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 23.04 GCC 13 32/64 (11,14)",
|
||||
"cppalliance/droneubuntu2304:1",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
"g++-13 g++-13-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 23.04 GCC 13 32/64 (17,20,2b)",
|
||||
"cppalliance/droneubuntu2304:1",
|
||||
"cppalliance/droneubuntu2404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '17,20,2b', ADDRMD: '32,64' },
|
||||
"g++-13 g++-13-multilib",
|
||||
),
|
||||
|
||||
@@ -57,20 +57,23 @@ jobs:
|
||||
- { compiler: gcc-9, cxxstd: '11,14,17', os: 'ubuntu-22.04', install: 'g++-9' }
|
||||
- { compiler: gcc-10, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-10' }
|
||||
- { compiler: gcc-11, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-11' }
|
||||
- { name: "gcc-12 w/ sanitizers (11)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '11', os: 'ubuntu-22.04', ccache_key: "san1" }
|
||||
- { name: "gcc-12 w/ sanitizers (14)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '14', os: 'ubuntu-22.04', ccache_key: "san1" }
|
||||
- { name: "gcc-12 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '17', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "gcc-12 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '20', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "gcc-12 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '2b', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { compiler: gcc-12, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-12' }
|
||||
- { compiler: gcc-13, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-13' }
|
||||
- { compiler: gcc-14, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-14' }
|
||||
- { name: "gcc-14 w/ sanitizers (11)", sanitize: yes,
|
||||
compiler: gcc-14, cxxstd: '11', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" }
|
||||
- { name: "gcc-14 w/ sanitizers (14)", sanitize: yes,
|
||||
compiler: gcc-14, cxxstd: '14', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" }
|
||||
- { name: "gcc-14 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: gcc-14, cxxstd: '17', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
|
||||
- { name: "gcc-14 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: gcc-14, cxxstd: '20', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
|
||||
- { name: "gcc-14 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: gcc-14, cxxstd: '2b', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
|
||||
- { name: Collect coverage, coverage: yes,
|
||||
compiler: gcc-12, cxxstd: '20', os: 'ubuntu-22.04', install: 'g++-12-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
compiler: gcc-14, cxxstd: '20', os: 'ubuntu-24.04', install: 'g++-14 g++-14-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
|
||||
- { name: "cfoa tsan (gcc-12)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-22.04', compiler: gcc-12,
|
||||
- { name: "cfoa tsan (gcc-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-24.04', install: 'g++-14', compiler: gcc-14,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan" }
|
||||
|
||||
# Linux, clang, libc++
|
||||
@@ -88,23 +91,30 @@ jobs:
|
||||
compiler: clang-12, cxxstd: '2b', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
- { compiler: 'clang-13', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
- { compiler: 'clang-13', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
- { compiler: 'clang-14', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
- { compiler: 'clang-14', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
- { compiler: 'clang-15', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
- { compiler: 'clang-15', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
- { compiler: 'clang-16', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-16 libc++-16-dev libc++abi-16-dev' }
|
||||
- { compiler: 'clang-16', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-16 libc++-16-dev libc++abi-16-dev' }
|
||||
- { compiler: 'clang-17', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
|
||||
- { compiler: 'clang-17', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
|
||||
- { compiler: 'clang-18', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
|
||||
- { compiler: 'clang-18', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
|
||||
|
||||
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
|
||||
- { name: "clang-14 w/ sanitizers (11,14)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '11,14', os: 'ubuntu-22.04', ccache_key: "san1" }
|
||||
- { name: "clang-14 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '17', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "clang-14 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '20', container: 'ubuntu:22.04', os: 'ubuntu-latest', ccache_key: "san2" }
|
||||
- { name: "clang-14 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '2b', container: 'ubuntu:22.04', os: 'ubuntu-latest', ccache_key: "san2" }
|
||||
- { name: "clang-18 w/ sanitizers (11,14)", sanitize: yes,
|
||||
compiler: clang-18, cxxstd: '11,14', os: 'ubuntu-24.04', ccache_key: "san1" }
|
||||
- { name: "clang-18 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: clang-18, cxxstd: '17', os: 'ubuntu-24.04', ccache_key: "san2" }
|
||||
- { name: "clang-18 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: clang-18, cxxstd: '20', container: 'ubuntu:24.04', os: 'ubuntu-latest', ccache_key: "san2" }
|
||||
- { name: "clang-18 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: clang-18, cxxstd: '2b', container: 'ubuntu:24.04', os: 'ubuntu-latest', ccache_key: "san2" }
|
||||
|
||||
- { name: "cfoa tsan (clang-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-22.04', compiler: clang-14,
|
||||
- { name: "cfoa tsan (clang-18)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-24.04', compiler: clang-18,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
|
||||
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev', ccache_key: "tsan" }
|
||||
|
||||
- { compiler: 'clang-15', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
- { compiler: 'clang-15', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev', ccache_key: "tsan" }
|
||||
|
||||
# OSX, clang
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: 'macos-12', sanitize: yes, ccache_key: "san1" }
|
||||
@@ -239,7 +249,12 @@ jobs:
|
||||
|
||||
- name: Run tests
|
||||
if: '!matrix.coverity'
|
||||
run: B2_TARGETS=${{matrix.targets}} ci/build.sh
|
||||
run: |
|
||||
if [[ ${B2_TSAN} == "yes" ]] && [[ $(uname) == "Linux" ]]; then
|
||||
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
|
||||
sudo sysctl vm.mmap_rnd_bits=28
|
||||
fi
|
||||
B2_TARGETS=${{matrix.targets}} ci/build.sh
|
||||
|
||||
- name: Upload coverage
|
||||
if: matrix.coverage
|
||||
@@ -326,8 +341,8 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { sys: MINGW32, compiler: gcc, cxxstd: '11,17,20' }
|
||||
- { sys: MINGW64, compiler: gcc, cxxstd: '11,17,20' }
|
||||
- { sys: MINGW32, compiler: gcc, cxxstd: '11,17,20', variant: 'release' }
|
||||
- { sys: MINGW64, compiler: gcc, cxxstd: '11,17,20', variant: 'debug,release' }
|
||||
|
||||
needs: [runner-selection]
|
||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['windows-latest'] }}
|
||||
@@ -361,9 +376,12 @@ jobs:
|
||||
B2_CXXSTD: ${{matrix.cxxstd}}
|
||||
B2_SANITIZE: ${{matrix.sanitize}}
|
||||
B2_STDLIB: ${{matrix.stdlib}}
|
||||
B2_VARIANT: ${{matrix.variant}}
|
||||
run: ci/github/install.sh
|
||||
|
||||
- name: Run tests
|
||||
env:
|
||||
B2_VARIANT: ${{matrix.variant}}
|
||||
run: ci/build.sh
|
||||
|
||||
# Run also the CMake tests to avoid having to setup another matrix for CMake on MSYS
|
||||
|
||||
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 29 KiB After Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 30 KiB |
@@ -459,13 +459,14 @@ h|unsuccessful lookup
|
||||
|
||||
|===
|
||||
|
||||
== boost::concurrent_flat_map
|
||||
== boost::concurrent_(flat|node)_map
|
||||
|
||||
All benchmarks were created using:
|
||||
|
||||
* `https://spec.oneapi.io/versions/latest/elements/oneTBB/source/containers/concurrent_hash_map_cls.html[oneapi::tbb::concurrent_hash_map^]<int, int>`
|
||||
* `https://github.com/greg7mdp/gtl/blob/main/docs/phmap.md[gtl::parallel_flat_hash_map^]<int, int>` with 64 submaps
|
||||
* `boost::concurrent_flat_map<int, int>`
|
||||
* `boost::concurrent_node_map<int, int>`
|
||||
|
||||
The source code can be https://github.com/boostorg/boost_unordered_benchmarks/tree/boost_concurrent_flat_map[found here^].
|
||||
|
||||
@@ -475,7 +476,7 @@ 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]:
|
||||
`boost::concurrent_flat_map` and `boost::concurrent_node_map` are 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`].
|
||||
|
||||
|
||||
@@ -9,6 +9,9 @@
|
||||
== Release 1.87.0 - Major update
|
||||
|
||||
* Added concurrent, node-based containers `boost::concurrent_node_map` and `boost::concurrent_node_set`.
|
||||
* Added `insert_and_visit(x, f1, f2)` and similar operations to concurrent containers, which
|
||||
allow for visitation of an element right after insertion (by contrast, `insert_or_visit(x, f)` only
|
||||
visits the element if insertion did _not_ take place).
|
||||
* Made visitation exclusive-locked within certain
|
||||
`boost::concurrent_flat_set` operations to allow for safe mutable modification of elements
|
||||
({github-pr-url}/265[PR#265^]).
|
||||
@@ -16,6 +19,7 @@
|
||||
* Added GDB pretty-printers for all containers and iterators. For a container with an allocator that uses fancy pointers, these only work if the proper pretty-printer is written for the fancy pointer type itself.
|
||||
* Fixed `std::initializer_list` assignment issues for open-addressing containers
|
||||
({github-pr-url}/277[PR#277^]).
|
||||
* Allowed non-copyable callables to be passed to the `std::initializer_list` overloads of `insert_{and|or}_[c]visit` for concurrent containers, by internally passing a `std::reference_wrapper` of the callable to the iterator-pair overloads.
|
||||
|
||||
|
||||
== Release 1.86.0
|
||||
|
||||
@@ -132,6 +132,23 @@ will grant visitation functions const/non-const access to the element depending
|
||||
by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result
|
||||
in higher parallelization. For concurrent sets, on the other hand,
|
||||
visitation is always const access.
|
||||
|
||||
Although expected to be used much less frequently, concurrent containers
|
||||
also provide insertion operations where an element can be visited right after
|
||||
element creation (in addition to the usual visitation when an equivalent
|
||||
element already exists):
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
m.insert_and_cvisit(x,
|
||||
[](const auto& y) {
|
||||
std::cout<< "(" << y.first << ", " << y.second <<") inserted\n";
|
||||
},
|
||||
[](const auto& y) {
|
||||
std::cout<< "(" << y.first << ", " << y.second << ") already exists\n";
|
||||
});
|
||||
----
|
||||
|
||||
Consult the references of
|
||||
xref:#concurrent_node_set[`boost::concurrent_node_set`],
|
||||
xref:#concurrent_flat_map[`boost::concurrent_node_map`],
|
||||
|
||||
@@ -169,6 +169,27 @@ namespace boost {
|
||||
template<class F> size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f);
|
||||
template<class F> size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f);
|
||||
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_visit](const init_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_cvisit](const init_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_visit](init_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_cvisit](init_type&& obj, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
|
||||
template<class... Args> bool xref:#concurrent_flat_map_try_emplace[try_emplace](const key_type& k, Args&&... args);
|
||||
template<class... Args> bool xref:#concurrent_flat_map_try_emplace[try_emplace](key_type&& k, Args&&... args);
|
||||
template<class K, class... Args> bool xref:#concurrent_flat_map_try_emplace[try_emplace](K&& k, Args&&... args);
|
||||
@@ -186,6 +207,19 @@ namespace boost {
|
||||
template<class K, class... Args, class F>
|
||||
bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_cvisit](K&& k, Args&&... args, F&& f);
|
||||
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_visit](const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_cvisit](const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_visit](key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_cvisit](key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_visit](K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_cvisit](K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
|
||||
template<class M> bool xref:#concurrent_flat_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj);
|
||||
template<class M> bool xref:#concurrent_flat_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj);
|
||||
template<class K, class M> bool xref:#concurrent_flat_map_insert_or_assign[insert_or_assign](K&& k, M&& obj);
|
||||
@@ -394,8 +428,9 @@ user-provided visitation function on the element passed do not introduce data ra
|
||||
|
||||
* Read access to the element.
|
||||
* Non-mutable modification of the element.
|
||||
* Mutable modification of the element (if the container operation executing the visitation function is not const
|
||||
and its name does not contain `cvisit`.)
|
||||
* Mutable modification of the element:
|
||||
** Within a container function accepting two visitation functions, always for the first function.
|
||||
** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function.
|
||||
|
||||
Any `boost::concurrent_flat_map operation` that inserts or modifies an element `e`
|
||||
synchronizes with the internal invocation of a visitation function on `e`.
|
||||
@@ -1113,7 +1148,113 @@ template<class F> size_type insert_or_cvisit(std::initializer_list<value_type> i
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or[c\]visit](il.begin(), il.end(), f);
|
||||
this->xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== emplace_and_[c]visit
|
||||
```c++
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_and_visit(Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_and_cvisit(Args&&... args, F1&& f1, F2&& f2);
|
||||
```
|
||||
|
||||
Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff `emplace_and_cvisit` is used.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is constructible from `args`.
|
||||
Returns:;; `true` if an insert took place.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued. +
|
||||
+
|
||||
The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack.
|
||||
|
||||
---
|
||||
|
||||
==== Copy insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_visit(const init_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(const init_type& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued. +
|
||||
+
|
||||
In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `const value_type&` argument participate in overload resolution
|
||||
only if `std::remove_cv<std::remove_reference<decltype(obj)>::type>::type` is `value_type`.
|
||||
|
||||
---
|
||||
|
||||
==== Move insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_visit(init_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued. +
|
||||
+
|
||||
In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `value_type&&` argument participate in overload resolution
|
||||
only if `std::remove_reference<decltype(obj)>::type` is `value_type`.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Iterator Range and Visit
|
||||
```c++
|
||||
template<class InputIterator, class F1, class F2>
|
||||
size_type insert_or_visit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator, class F1, class F2>
|
||||
size_type insert_or_cvisit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
while(first != last) this->xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2);
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Initializer List and Visit
|
||||
```c++
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_visit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_cvisit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
@@ -1207,6 +1348,55 @@ The `template<class K, class\... Args, class F>` overloads only participate in o
|
||||
|
||||
---
|
||||
|
||||
==== try_emplace_and_[c]visit
|
||||
```c++
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_visit(const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_cvisit(const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_visit(key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_cvisit(key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool try_emplace_and_visit(K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool try_emplace_and_cvisit(K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; No `value_type` is constructed
|
||||
if there is an element with an equivalent key; otherwise, the construction is of the form: +
|
||||
+
|
||||
--
|
||||
```c++
|
||||
// first four overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
|
||||
// last two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
Invalidates pointers and references to elements if a rehashing is issued.
|
||||
|
||||
The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack.
|
||||
|
||||
The `template<class K, class\... Args, class F1, class F2>` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. 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.
|
||||
|
||||
--
|
||||
|
||||
---
|
||||
|
||||
==== insert_or_assign
|
||||
```c++
|
||||
template<class M> bool insert_or_assign(const key_type& k, M&& obj);
|
||||
|
||||
@@ -160,6 +160,25 @@ namespace boost {
|
||||
template<class F> size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list<value_type> il, F f);
|
||||
template<class F> size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list<value_type> il, F f);
|
||||
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_set_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_set_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_set_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_flat_set_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class K, class F1, class F2> bool xref:#concurrent_flat_set_transparent_insert_and_cvisit[insert_and_visit](K&& k, F1 f1, F2 f2);
|
||||
template<class K, class F1, class F2> bool xref:#concurrent_flat_set_transparent_insert_and_cvisit[insert_and_cvisit](K&& k, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
|
||||
size_type xref:#concurrent_flat_set_erase[erase](const key_type& k);
|
||||
template<class K> size_type xref:#concurrent_flat_set_erase[erase](const K& k);
|
||||
|
||||
@@ -355,8 +374,9 @@ user-provided visitation function on the element passed do not introduce data ra
|
||||
|
||||
* Read access to the element.
|
||||
* Non-mutable modification of the element.
|
||||
* Mutable modification of the element (if the container operation executing the visitation function is not const
|
||||
and its name does not contain `cvisit`.)
|
||||
* Mutable modification of the element:
|
||||
** Within a container function accepting two visitation functions, always for the first function.
|
||||
** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function.
|
||||
|
||||
Any `boost::concurrent_flat_set operation` that inserts or modifies an element `e`
|
||||
synchronizes with the internal invocation of a visitation function on `e`.
|
||||
@@ -1086,7 +1106,123 @@ template<class F> size_type insert_or_cvisit(std::initializer_list<value_type> i
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or[c\]visit](il.begin(), il.end(), f);
|
||||
this->xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== emplace_and_[c]visit
|
||||
```c++
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_and_visit(Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_and_cvisit(Args&&... args, F1&& f1, F2&& f2);
|
||||
```
|
||||
|
||||
Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is constructible from `args`.
|
||||
Returns:;; `true` if an insert took place.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued. +
|
||||
+
|
||||
The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack.
|
||||
|
||||
---
|
||||
|
||||
==== Copy insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(const value_type& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued.
|
||||
|
||||
---
|
||||
|
||||
==== Move insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent insert_and_[c]visit
|
||||
```c++
|
||||
template<class K, class F1, class F2> bool insert_and_visit(K&& k, F1 f1, F2 f2);
|
||||
template<class K, class F1, class F2> bool insert_and_cvisit(K&& k, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `std::forward<K>(k)` in the container if and only if there is no element in the container with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`.
|
||||
Returns:;; `true` if an insert took place.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Invalidates pointers and references to elements if a rehashing is issued. +
|
||||
+
|
||||
These overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. 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.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Iterator Range and Visit
|
||||
```c++
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type insert_and_visit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type insert_and_cvisit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
while(first != last) this->xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2);
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Initializer List and Visit
|
||||
```c++
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_visit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_cvisit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
|
||||
@@ -175,6 +175,31 @@ namespace boost {
|
||||
template<class F> insert_return_type xref:#concurrent_node_map_insert_node_or_visit[insert_or_visit](node_type&& nh, F f);
|
||||
template<class F> insert_return_type xref:#concurrent_node_map_insert_node_or_visit[insert_or_cvisit](node_type&& nh, F f);
|
||||
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_visit](const init_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_cvisit](const init_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_visit](init_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_cvisit](init_type&& obj, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
insert_return_type xref:#concurrent_node_map_insert_node_and_visit[insert_and_visit](node_type&& nh, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
insert_return_type xref:#concurrent_node_map_insert_node_and_visit[insert_and_cvisit](node_type&& nh, F1 f1, F2 f2);
|
||||
|
||||
template<class... Args> bool xref:#concurrent_node_map_try_emplace[try_emplace](const key_type& k, Args&&... args);
|
||||
template<class... Args> bool xref:#concurrent_node_map_try_emplace[try_emplace](key_type&& k, Args&&... args);
|
||||
template<class K, class... Args> bool xref:#concurrent_node_map_try_emplace[try_emplace](K&& k, Args&&... args);
|
||||
@@ -192,6 +217,20 @@ namespace boost {
|
||||
template<class K, class... Args, class F>
|
||||
bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_cvisit](K&& k, Args&&... args, F&& f);
|
||||
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_visit](const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_cvisit](const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_visit](key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_cvisit](key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_visit](K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_cvisit](K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
|
||||
|
||||
template<class M> bool xref:#concurrent_node_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj);
|
||||
template<class M> bool xref:#concurrent_node_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj);
|
||||
template<class K, class M> bool xref:#concurrent_node_map_insert_or_assign[insert_or_assign](K&& k, M&& obj);
|
||||
@@ -406,8 +445,9 @@ user-provided visitation function on the element passed do not introduce data ra
|
||||
|
||||
* Read access to the element.
|
||||
* Non-mutable modification of the element.
|
||||
* Mutable modification of the element (if the container operation executing the visitation function is not const
|
||||
and its name does not contain `cvisit`.)
|
||||
* Mutable modification of the element:
|
||||
** Within a container function accepting two visitation functions, always for the first function.
|
||||
** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function.
|
||||
|
||||
Any `boost::concurrent_node_map operation` that inserts or modifies an element `e`
|
||||
synchronizes with the internal invocation of a visitation function on `e`.
|
||||
@@ -1167,7 +1207,7 @@ template<class F> size_type insert_or_cvisit(std::initializer_list<value_type> i
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or[c\]visit](il.begin(), il.end(), f);
|
||||
this->xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
@@ -1196,6 +1236,130 @@ Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` a
|
||||
|
||||
---
|
||||
|
||||
==== emplace_and_[c]visit
|
||||
```c++
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_and_visit(Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_and_cvisit(Args&&... args, F1&& f1, F2&& f2);
|
||||
```
|
||||
|
||||
Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff `emplace_and_cvisit` is used.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is constructible from `args`.
|
||||
Returns:;; `true` if an insert took place.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack.
|
||||
|
||||
---
|
||||
|
||||
==== Copy insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_visit(const init_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(const init_type& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `const value_type&` argument participate in overload resolution
|
||||
only if `std::remove_cv<std::remove_reference<decltype(obj)>::type>::type` is `value_type`.
|
||||
|
||||
---
|
||||
|
||||
==== Move insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_visit(init_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `value_type&&` argument participate in overload resolution
|
||||
only if `std::remove_reference<decltype(obj)>::type` is `value_type`.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Iterator Range and Visit
|
||||
```c++
|
||||
template<class InputIterator, class F1, class F2>
|
||||
size_type insert_or_visit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator, class F1, class F2>
|
||||
size_type insert_or_cvisit(InputIterator first, InputIterator last, F1 f2, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
while(first != last) this->xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2);
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Initializer List and Visit
|
||||
```c++
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_visit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_cvisit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Node and Visit
|
||||
```c++
|
||||
template<class F1, class F2>
|
||||
insert_return_type insert_and_visit(node_type&& nh, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
insert_return_type insert_and_cvisit(node_type&& nh, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
If `nh` is empty, does nothing.
|
||||
Otherwise, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.key()`,
|
||||
and then invokes `f1` with a non-const reference to the newly inserted element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff `insert_or_cvisit` is used.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: +
|
||||
* If `nh` is empty, `inserted` is `false` and `node` is empty.
|
||||
* Otherwise if the insertion took place, `inserted` is true and `node` is empty.
|
||||
* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` or call to `f1` or `f2`, the function has no effect.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal.
|
||||
|
||||
---
|
||||
|
||||
==== try_emplace
|
||||
```c++
|
||||
template<class... Args> bool try_emplace(const key_type& k, Args&&... args);
|
||||
@@ -1278,6 +1442,53 @@ The `template<class K, class\... Args, class F>` overloads only participate in o
|
||||
|
||||
---
|
||||
|
||||
==== try_emplace_and_[c]visit
|
||||
```c++
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_visit(const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_cvisit(const key_type& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_visit(key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool try_emplace_and_cvisit(key_type&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool try_emplace_and_visit(K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class K, class... Args, class F1, class F2>
|
||||
bool try_emplace_and_cvisit(K&& k, Args&&... args, F1&& f1, F2&& f2);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it,
|
||||
and then invokes `f1` with a non-const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; No `value_type` is constructed
|
||||
if there is an element with an equivalent key; otherwise, the construction is of the form: +
|
||||
+
|
||||
--
|
||||
```c++
|
||||
// first four overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
|
||||
// last two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
The interface is exposition only, as C++ does not allow to declare parameter `f1` and `f2` after a variadic parameter pack.
|
||||
|
||||
The `template<class K, class\... Args, class F1, class F2>` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. 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.
|
||||
|
||||
--
|
||||
|
||||
---
|
||||
|
||||
==== insert_or_assign
|
||||
```c++
|
||||
template<class M> bool insert_or_assign(const key_type& k, M&& obj);
|
||||
|
||||
@@ -166,6 +166,29 @@ namespace boost {
|
||||
template<class F> insert_return_type xref:#concurrent_node_set_insert_node_or_visit[insert_or_visit](node_type&& nh, F f);
|
||||
template<class F> insert_return_type xref:#concurrent_node_set_insert_node_or_visit[insert_or_cvisit](node_type&& nh, F f);
|
||||
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_set_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_set_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_set_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool xref:#concurrent_node_set_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2);
|
||||
template<class K, class F1, class F2> bool xref:#concurrent_node_set_transparent_insert_and_cvisit[insert_and_visit](K&& k, F1 f1, F2 f2);
|
||||
template<class K, class F1, class F2> bool xref:#concurrent_node_set_transparent_insert_and_cvisit[insert_and_cvisit](K&& k, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
insert_return_type xref:#concurrent_node_set_insert_node_and_visit[insert_and_visit](node_type&& nh, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
insert_return_type xref:#concurrent_node_set_insert_node_and_visit[insert_and_cvisit](node_type&& nh, F1 f1, F2 f2);
|
||||
|
||||
size_type xref:#concurrent_node_set_erase[erase](const key_type& k);
|
||||
template<class K> size_type xref:#concurrent_node_set_erase[erase](const K& k);
|
||||
|
||||
@@ -368,8 +391,9 @@ user-provided visitation function on the element passed do not introduce data ra
|
||||
|
||||
* Read access to the element.
|
||||
* Non-mutable modification of the element.
|
||||
* Mutable modification of the element (if the container operation executing the visitation function is not const
|
||||
and its name does not contain `cvisit`.)
|
||||
* Mutable modification of the element:
|
||||
** Within a container function accepting two visitation functions, always for the first function.
|
||||
** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function.
|
||||
|
||||
Any `boost::concurrent_node_set operation` that inserts or modifies an element `e`
|
||||
synchronizes with the internal invocation of a visitation function on `e`.
|
||||
@@ -1140,7 +1164,7 @@ template<class F> size_type insert_or_cvisit(std::initializer_list<value_type> i
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or[c\]visit](il.begin(), il.end(), f);
|
||||
this->xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
@@ -1169,6 +1193,140 @@ Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` a
|
||||
|
||||
---
|
||||
|
||||
==== emplace_and_[c]visit
|
||||
```c++
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_or_visit(Args&&... args, F1&& f1, F2&& f2);
|
||||
template<class... Args, class F1, class F2>
|
||||
bool emplace_or_cvisit(Args&&... args, F1&& f1, F2&& f2);
|
||||
```
|
||||
|
||||
Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is constructible from `args`.
|
||||
Returns:;; `true` if an insert took place.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack.
|
||||
|
||||
---
|
||||
|
||||
==== Copy insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(const value_type& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(const value_type& obj, F1 f2, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
|
||||
---
|
||||
|
||||
==== Move insert_and_[c]visit
|
||||
```c++
|
||||
template<class F1, class F2> bool insert_and_visit(value_type&& obj, F1 f1, F2 f2);
|
||||
template<class F1, class F2> bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts `obj` in the table if and only if there is no element in the table with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
Returns:;; `true` if an insert took place. +
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent insert_and_[c]visit
|
||||
```c++
|
||||
template<class K, class F1, class F2> bool insert_and_visit(K&& k, F1 f1, F2 f2);
|
||||
template<class K, class F1, class F2> bool insert_and_cvisit(K&& k, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `std::forward<K>(k)` in the container if and only if there is no element in the container with an equivalent key,
|
||||
and then invokes `f1` with a const reference to the newly created element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`.
|
||||
Returns:;; `true` if an insert took place.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; These overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. 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.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Iterator Range and Visit
|
||||
```c++
|
||||
template<class InputIterator,class F1, class F2>
|
||||
size_type insert_and_visit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
template<class InputIterator,class F1, class f2>
|
||||
size_type insert_and_cvisit(InputIterator first, InputIterator last, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
while(first != last) this->xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2);
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Initializer List and Visit
|
||||
```c++
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_visit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type insert_and_cvisit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
Equivalent to
|
||||
[listing,subs="+macros,+quotes"]
|
||||
-----
|
||||
this->xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2));
|
||||
-----
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements inserted.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Node and Visit
|
||||
```c++
|
||||
template<class F1, class F2>
|
||||
insert_return_type insert_and_visit(node_type&& nh, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
insert_return_type insert_and_cvisit(node_type&& nh, F1 f1, F2 f2);
|
||||
```
|
||||
|
||||
If `nh` is empty, does nothing.
|
||||
Otherwise, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.value()`,
|
||||
and then invokes `f1` with a const reference to the newly inserted element.
|
||||
Otherwise, invokes `f2` with a const reference to the equivalent element.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: +
|
||||
* If `nh` is empty, `inserted` is `false` and `node` is empty.
|
||||
* Otherwise if the insertion took place, `inserted` is true and `node` is empty.
|
||||
* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` or call to `f1` or `f2`, the function has no effect.
|
||||
Concurrency:;; Blocking on rehashing of `*this`.
|
||||
Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal.
|
||||
|
||||
---
|
||||
|
||||
==== erase
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
|
||||
@@ -190,6 +190,7 @@ namespace boost {
|
||||
}
|
||||
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
concurrent_flat_map(
|
||||
unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
@@ -419,16 +420,18 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator begin, InputIterator end)
|
||||
size_type insert(InputIterator begin, InputIterator end)
|
||||
{
|
||||
for (auto pos = begin; pos != end; ++pos) {
|
||||
size_type count_elements = 0;
|
||||
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
|
||||
table_.emplace(*pos);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
size_type insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
return this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
template <class M>
|
||||
@@ -471,19 +474,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_visit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class Ty, class F>
|
||||
@@ -502,19 +507,101 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_cvisit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class Ty, class F1, class F2>
|
||||
BOOST_FORCEINLINE auto insert_and_visit(Ty&& value, F1 f1, F2 f2)
|
||||
-> decltype(table_.insert_and_visit(std::forward<Ty>(value), f1, f2))
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(std::forward<Ty>(value), f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(init_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
return this->insert_and_visit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class Ty, class F1, class F2>
|
||||
BOOST_FORCEINLINE auto insert_and_cvisit(Ty&& value, F1 f1, F2 f2)
|
||||
-> decltype(table_.insert_and_cvisit(std::forward<Ty>(value), f1, f2))
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(std::forward<Ty>(value), f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return this->insert_and_cvisit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
@@ -538,6 +625,30 @@ namespace boost {
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_visit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_cvisit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_cvisit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace(key_type const& k, Args&&... args)
|
||||
{
|
||||
@@ -613,6 +724,78 @@ namespace boost {
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(
|
||||
key_type const& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_visit(
|
||||
k, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(
|
||||
key_type const& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_cvisit(
|
||||
k, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(
|
||||
key_type&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_visit(
|
||||
std::move(k), std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(
|
||||
key_type&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_cvisit(
|
||||
std::move(k), std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K, class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(
|
||||
K&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_visit(std::forward<K>(k),
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K, class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(
|
||||
K&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_cvisit(std::forward<K>(k),
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||
{
|
||||
return table_.erase(k);
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace boost {
|
||||
}
|
||||
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
concurrent_flat_set(
|
||||
unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
@@ -425,16 +426,18 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator begin, InputIterator end)
|
||||
size_type insert(InputIterator begin, InputIterator end)
|
||||
{
|
||||
for (auto pos = begin; pos != end; ++pos) {
|
||||
size_type count_elements = 0;
|
||||
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
|
||||
table_.emplace(*pos);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
size_type insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
return this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@@ -462,19 +465,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_visit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@@ -502,19 +507,122 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_cvisit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(
|
||||
value_type const& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(obj, f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(value_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class K, class F1, class F2>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert_and_visit(K&& k, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.try_emplace_and_visit(std::forward<K>(k), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_visit(std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return this->insert_and_visit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(
|
||||
value_type const& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(obj, f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class K, class F1, class F2>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert_and_cvisit(K&& k, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.try_emplace_and_cvisit(std::forward<K>(k), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return this->insert_and_cvisit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
@@ -538,6 +646,30 @@ namespace boost {
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_visit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_cvisit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_cvisit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||
{
|
||||
return table_.erase(k);
|
||||
|
||||
@@ -197,6 +197,7 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
concurrent_node_map(
|
||||
unordered_node_map<Key, T, Hash, Pred, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
@@ -426,16 +427,18 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator begin, InputIterator end)
|
||||
size_type insert(InputIterator begin, InputIterator end)
|
||||
{
|
||||
for (auto pos = begin; pos != end; ++pos) {
|
||||
size_type count_elements = 0;
|
||||
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
|
||||
table_.emplace(*pos);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
size_type insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
return this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
insert_return_type insert(node_type&& nh)
|
||||
@@ -497,19 +500,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_visit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@@ -549,19 +554,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_cvisit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@@ -585,6 +592,130 @@ namespace boost {
|
||||
}
|
||||
}
|
||||
|
||||
template <class Ty, class F1, class F2>
|
||||
BOOST_FORCEINLINE auto insert_and_visit(Ty&& value, F1 f1, F2 f2)
|
||||
-> decltype(table_.insert_and_visit(std::forward<Ty>(value), f1, f2))
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(std::forward<Ty>(value), f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(init_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
return this->insert_and_visit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
insert_return_type insert_and_visit(node_type&& nh, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
using access = detail::foa::node_handle_access;
|
||||
|
||||
if (nh.empty()) {
|
||||
return {false, node_type{}};
|
||||
}
|
||||
|
||||
// Caveat: get_allocator() incurs synchronization (not cheap)
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
if (table_.insert_and_visit(std::move(access::element(nh)), f1, f2)) {
|
||||
access::reset(nh);
|
||||
return {true, node_type{}};
|
||||
} else {
|
||||
return {false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
template <class Ty, class F1, class F2>
|
||||
BOOST_FORCEINLINE auto insert_and_cvisit(Ty&& value, F1 f1, F2 f2)
|
||||
-> decltype(table_.insert_and_cvisit(std::forward<Ty>(value), f1, f2))
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(std::forward<Ty>(value), f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return this->insert_and_cvisit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
insert_return_type insert_and_cvisit(node_type&& nh, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
using access = detail::foa::node_handle_access;
|
||||
|
||||
if (nh.empty()) {
|
||||
return {false, node_type{}};
|
||||
}
|
||||
|
||||
// Caveat: get_allocator() incurs synchronization (not cheap)
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
if (table_.insert_and_cvisit(std::move(access::element(nh)), f1, f2)) {
|
||||
access::reset(nh);
|
||||
return {true, node_type{}};
|
||||
} else {
|
||||
return {false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
@@ -606,6 +737,30 @@ namespace boost {
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_visit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_cvisit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_cvisit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace(key_type const& k, Args&&... args)
|
||||
{
|
||||
@@ -681,6 +836,78 @@ namespace boost {
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(
|
||||
key_type const& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_visit(
|
||||
k, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(
|
||||
key_type const& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_cvisit(
|
||||
k, std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(
|
||||
key_type&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_visit(
|
||||
std::move(k), std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(
|
||||
key_type&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_cvisit(
|
||||
std::move(k), std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K, class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(
|
||||
K&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_visit(std::forward<K>(k),
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K, class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(
|
||||
K&& k, Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.try_emplace_and_cvisit(std::forward<K>(k),
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||
{
|
||||
return table_.erase(k);
|
||||
|
||||
@@ -194,6 +194,7 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
concurrent_node_set(
|
||||
unordered_node_set<Key, Hash, Pred, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
@@ -432,16 +433,18 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator begin, InputIterator end)
|
||||
size_type insert(InputIterator begin, InputIterator end)
|
||||
{
|
||||
for (auto pos = begin; pos != end; ++pos) {
|
||||
size_type count_elements = 0;
|
||||
for (auto pos = begin; pos != end; ++pos, ++count_elements) {
|
||||
table_.emplace(*pos);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
size_type insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
return this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
insert_return_type insert(node_type&& nh)
|
||||
@@ -488,19 +491,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_visit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_visit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@@ -549,19 +554,21 @@ namespace boost {
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
size_type insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_or_cvisit(*first, f);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
size_type insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
return this->insert_or_cvisit(ilist.begin(), ilist.end(), std::ref(f));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
@@ -585,6 +592,152 @@ namespace boost {
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(
|
||||
value_type const& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(obj, f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(value_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_visit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class K, class F1, class F2>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert_and_visit(K&& k, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.try_emplace_and_visit(std::forward<K>(k), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_visit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return this->insert_and_visit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
insert_return_type insert_and_visit(node_type&& nh, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
using access = detail::foa::node_handle_access;
|
||||
|
||||
if (nh.empty()) {
|
||||
return {false, node_type{}};
|
||||
}
|
||||
|
||||
// Caveat: get_allocator() incurs synchronization (not cheap)
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
if (table_.insert_and_visit(std::move(access::element(nh)), f1, f2)) {
|
||||
access::reset(nh);
|
||||
return {true, node_type{}};
|
||||
} else {
|
||||
return {false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(
|
||||
value_type const& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(obj, f1, f2);
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.insert_and_cvisit(std::move(obj), f1, f2);
|
||||
}
|
||||
|
||||
template <class K, class F1, class F2>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert_and_cvisit(K&& k, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return table_.try_emplace_and_cvisit(std::forward<K>(k), f1, f2);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
size_type count_elements = 0;
|
||||
for (; first != last; ++first, ++count_elements) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
return count_elements;
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
size_type insert_and_cvisit(
|
||||
std::initializer_list<value_type> ilist, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
return this->insert_and_cvisit(
|
||||
ilist.begin(), ilist.end(), std::ref(f1), std::ref(f2));
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
insert_return_type insert_and_cvisit(node_type&& nh, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
using access = detail::foa::node_handle_access;
|
||||
|
||||
if (nh.empty()) {
|
||||
return {false, node_type{}};
|
||||
}
|
||||
|
||||
// Caveat: get_allocator() incurs synchronization (not cheap)
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
if (table_.insert_and_cvisit(std::move(access::element(nh)), f1, f2)) {
|
||||
access::reset(nh);
|
||||
return {true, node_type{}};
|
||||
} else {
|
||||
return {false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
@@ -606,6 +759,30 @@ namespace boost {
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_visit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg1, class Arg2, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_cvisit(
|
||||
Arg1&& arg1, Arg2&& arg2, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE(
|
||||
Arg1, Arg2, Args...)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg2, Args...)
|
||||
return table_.emplace_and_cvisit(
|
||||
std::forward<Arg1>(arg1), std::forward<Arg2>(arg2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||
{
|
||||
return table_.erase(k);
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Copyright 2023 Christian Mazakas.
|
||||
* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Copyright 2023-2024 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)
|
||||
@@ -13,10 +13,7 @@
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \
|
||||
static_assert(boost::unordered::detail::is_invocable<F, value_type&>::value, \
|
||||
@@ -58,16 +55,41 @@
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \
|
||||
BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args))
|
||||
|
||||
#define BOOST_UNORDERED_DETAIL_PENULTIMATE_ARG(Arg1, Arg2, Args) \
|
||||
mp11::mp_at_c<mp11::mp_list< \
|
||||
Arg1 BOOST_UNORDERED_DETAIL_COMMA Arg2 BOOST_UNORDERED_DETAIL_COMMA Args \
|
||||
>, \
|
||||
mp11::mp_size<mp11::mp_list< \
|
||||
Arg1 BOOST_UNORDERED_DETAIL_COMMA Arg2 BOOST_UNORDERED_DETAIL_COMMA Args \
|
||||
>>::value - 2>
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_INVOCABLE( \
|
||||
Arg1, Arg2, Args) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE( \
|
||||
BOOST_UNORDERED_DETAIL_PENULTIMATE_ARG(Arg1, Arg2, Args))
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_PENULTIMATE_ARG_CONST_INVOCABLE( \
|
||||
Arg1, Arg2, Args) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \
|
||||
BOOST_UNORDERED_DETAIL_PENULTIMATE_ARG(Arg1, Arg2, Args))
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <class F, class... Args>
|
||||
struct is_invocable
|
||||
: std::is_constructible<std::function<void(Args...)>,
|
||||
std::reference_wrapper<typename std::remove_reference<F>::type> >
|
||||
template <class...> struct is_invocable_helper : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class F, class... Args>
|
||||
struct is_invocable_helper<
|
||||
void_t<decltype(std::declval<F>()(std::declval<Args>()...))>, F,
|
||||
Args...> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class F, class... Args>
|
||||
using is_invocable = is_invocable_helper<void, F, Args...>;
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace unordered
|
||||
|
||||
@@ -215,7 +215,7 @@ struct atomic_integral
|
||||
|
||||
/* Group-level concurrency protection. It provides a rw mutex plus an
|
||||
* atomic insertion counter for optimistic insertion (see
|
||||
* unprotected_norehash_emplace_or_visit).
|
||||
* unprotected_norehash_emplace_and_visit).
|
||||
*/
|
||||
|
||||
struct group_access
|
||||
@@ -755,6 +755,22 @@ public:
|
||||
try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Key,typename... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_visit(Key&& x,Args&&... args)
|
||||
{
|
||||
return emplace_and_visit_flast(
|
||||
group_exclusive{},
|
||||
try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Key,typename... Args>
|
||||
BOOST_FORCEINLINE bool try_emplace_and_cvisit(Key&& x,Args&&... args)
|
||||
{
|
||||
return emplace_and_visit_flast(
|
||||
group_shared{},
|
||||
try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE bool emplace_or_visit(Args&&... args)
|
||||
{
|
||||
@@ -769,86 +785,121 @@ public:
|
||||
group_shared{},std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_visit(const init_type& x,F&& f)
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit(Args&&... args)
|
||||
{
|
||||
return emplace_or_visit_impl(group_exclusive{},std::forward<F>(f),x);
|
||||
return construct_and_emplace_and_visit_flast(
|
||||
group_exclusive{},std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_cvisit(const init_type& x,F&& f)
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_cvisit(Args&&... args)
|
||||
{
|
||||
return emplace_or_visit_impl(group_shared{},std::forward<F>(f),x);
|
||||
return construct_and_emplace_and_visit_flast(
|
||||
group_shared{},std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_visit(init_type&& x,F&& f)
|
||||
template<typename Value,typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_visit(Value&& x,F&& f)
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_exclusive{},std::forward<F>(f),std::move(x));
|
||||
return insert_and_visit(
|
||||
std::forward<Value>(x),[](const value_type&){},std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_cvisit(init_type&& x,F&& f)
|
||||
template<typename Value,typename F>
|
||||
BOOST_FORCEINLINE bool insert_or_cvisit(Value&& x,F&& f)
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_shared{},std::forward<F>(f),std::move(x));
|
||||
return insert_and_cvisit(
|
||||
std::forward<Value>(x),[](const value_type&){},std::forward<F>(f));
|
||||
}
|
||||
|
||||
template<typename F1,typename F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(const init_type& x,F1&& f1,F2&& f2)
|
||||
{
|
||||
return emplace_and_visit_impl(
|
||||
group_exclusive{},std::forward<F1>(f1),std::forward<F2>(f2),x);
|
||||
}
|
||||
|
||||
template<typename F1,typename F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(const init_type& x,F1&& f1,F2&& f2)
|
||||
{
|
||||
return emplace_and_visit_impl(
|
||||
group_shared{},std::forward<F1>(f1),std::forward<F2>(f2),x);
|
||||
}
|
||||
|
||||
template<typename F1,typename F2>
|
||||
BOOST_FORCEINLINE bool insert_and_visit(init_type&& x,F1&& f1,F2&& f2)
|
||||
{
|
||||
return emplace_and_visit_impl(
|
||||
group_exclusive{},std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
std::move(x));
|
||||
}
|
||||
|
||||
template<typename F1,typename F2>
|
||||
BOOST_FORCEINLINE bool insert_and_cvisit(init_type&& x,F1&& f1,F2&& f2)
|
||||
{
|
||||
return emplace_and_visit_impl(
|
||||
group_shared{},std::forward<F1>(f1),std::forward<F2>(f2),std::move(x));
|
||||
}
|
||||
|
||||
/* SFINAE tilts call ambiguities in favor of init_type */
|
||||
|
||||
template<typename Value,typename F>
|
||||
BOOST_FORCEINLINE auto insert_or_visit(const Value& x,F&& f)
|
||||
template<typename Value,typename F1,typename F2>
|
||||
BOOST_FORCEINLINE auto insert_and_visit(const Value& x,F1&& f1,F2&& f2)
|
||||
->enable_if_is_value_type<Value,bool>
|
||||
{
|
||||
return emplace_or_visit_impl(group_exclusive{},std::forward<F>(f),x);
|
||||
return emplace_and_visit_impl(
|
||||
group_exclusive{},std::forward<F1>(f1),std::forward<F2>(f2),x);
|
||||
}
|
||||
|
||||
template<typename Value,typename F>
|
||||
BOOST_FORCEINLINE auto insert_or_cvisit(const Value& x,F&& f)
|
||||
template<typename Value,typename F1,typename F2>
|
||||
BOOST_FORCEINLINE auto insert_and_cvisit(const Value& x,F1&& f1,F2&& f2)
|
||||
->enable_if_is_value_type<Value,bool>
|
||||
{
|
||||
return emplace_or_visit_impl(group_shared{},std::forward<F>(f),x);
|
||||
return emplace_and_visit_impl(
|
||||
group_shared{},std::forward<F1>(f1),std::forward<F2>(f2),x);
|
||||
}
|
||||
|
||||
template<typename Value,typename F>
|
||||
BOOST_FORCEINLINE auto insert_or_visit(Value&& x,F&& f)
|
||||
template<typename Value,typename F1,typename F2>
|
||||
BOOST_FORCEINLINE auto insert_and_visit(Value&& x,F1&& f1,F2&& f2)
|
||||
->enable_if_is_value_type<Value,bool>
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_exclusive{},std::forward<F>(f),std::move(x));
|
||||
return emplace_and_visit_impl(
|
||||
group_exclusive{},std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
std::move(x));
|
||||
}
|
||||
|
||||
template<typename Value,typename F>
|
||||
BOOST_FORCEINLINE auto insert_or_cvisit(Value&& x,F&& f)
|
||||
template<typename Value,typename F1,typename F2>
|
||||
BOOST_FORCEINLINE auto insert_and_cvisit(Value&& x,F1&& f1,F2&& f2)
|
||||
->enable_if_is_value_type<Value,bool>
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_shared{},std::forward<F>(f),std::move(x));
|
||||
return emplace_and_visit_impl(
|
||||
group_shared{},std::forward<F1>(f1),std::forward<F2>(f2),std::move(x));
|
||||
}
|
||||
|
||||
template<typename F,typename T=element_type>
|
||||
template<typename F1,typename F2,typename T=element_type>
|
||||
BOOST_FORCEINLINE
|
||||
typename std::enable_if<
|
||||
!std::is_same<T,value_type>::value,
|
||||
bool
|
||||
>::type
|
||||
insert_or_visit(element_type&& x, F&& f)
|
||||
insert_and_visit(element_type&& x,F1&& f1,F2&& f2)
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_exclusive{},std::forward<F>(f),std::move(x));
|
||||
return emplace_and_visit_impl(
|
||||
group_exclusive{},std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
std::move(x));
|
||||
}
|
||||
|
||||
template<typename F,typename T=element_type>
|
||||
template<typename F1,typename F2,typename T=element_type>
|
||||
BOOST_FORCEINLINE
|
||||
typename std::enable_if<
|
||||
!std::is_same<T,value_type>::value,
|
||||
bool
|
||||
>::type
|
||||
insert_or_cvisit(element_type&& x, F&& f)
|
||||
insert_and_cvisit(element_type&& x,F1&& f1,F2&& f2)
|
||||
{
|
||||
return emplace_or_visit_impl(
|
||||
group_shared{},std::forward<F>(f),std::move(x));
|
||||
return emplace_and_visit_impl(
|
||||
group_shared{},std::forward<F1>(f1),std::forward<F2>(f2),std::move(x));
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
@@ -1408,23 +1459,59 @@ private:
|
||||
);
|
||||
}
|
||||
|
||||
struct call_construct_and_emplace_and_visit
|
||||
{
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE bool operator()(
|
||||
concurrent_table* this_,Args&&... args)const
|
||||
{
|
||||
return this_->construct_and_emplace_and_visit(
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename GroupAccessMode,typename... Args>
|
||||
BOOST_FORCEINLINE bool construct_and_emplace_and_visit_flast(
|
||||
GroupAccessMode access_mode,Args&&... args)
|
||||
{
|
||||
return mp11::tuple_apply(
|
||||
call_construct_and_emplace_and_visit{},
|
||||
std::tuple_cat(
|
||||
std::make_tuple(this,access_mode),
|
||||
tuple_rotate_right<2>(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename GroupAccessMode,typename F,typename... Args>
|
||||
BOOST_FORCEINLINE bool construct_and_emplace_or_visit(
|
||||
GroupAccessMode access_mode,F&& f,Args&&... args)
|
||||
{
|
||||
return construct_and_emplace_and_visit(
|
||||
access_mode,[](const value_type&){},std::forward<F>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename GroupAccessMode,typename F1,typename F2,typename... Args>
|
||||
BOOST_FORCEINLINE bool construct_and_emplace_and_visit(
|
||||
GroupAccessMode access_mode,F1&& f1,F2&& f2,Args&&... args)
|
||||
{
|
||||
auto lck=shared_access();
|
||||
|
||||
alloc_cted_insert_type<type_policy,Allocator,Args...> x(
|
||||
this->al(),std::forward<Args>(args)...);
|
||||
int res=unprotected_norehash_emplace_or_visit(
|
||||
access_mode,std::forward<F>(f),type_policy::move(x.value()));
|
||||
int res=unprotected_norehash_emplace_and_visit(
|
||||
access_mode,std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
type_policy::move(x.value()));
|
||||
if(BOOST_LIKELY(res>=0))return res!=0;
|
||||
|
||||
lck.unlock();
|
||||
|
||||
rehash_if_full();
|
||||
return noinline_emplace_or_visit(
|
||||
access_mode,std::forward<F>(f),type_policy::move(x.value()));
|
||||
return noinline_emplace_and_visit(
|
||||
access_mode,std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
type_policy::move(x.value()));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
@@ -1442,6 +1529,15 @@ private:
|
||||
access_mode,std::forward<F>(f),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename GroupAccessMode,typename F1,typename F2,typename... Args>
|
||||
BOOST_NOINLINE bool noinline_emplace_and_visit(
|
||||
GroupAccessMode access_mode,F1&& f1,F2&& f2,Args&&... args)
|
||||
{
|
||||
return emplace_and_visit_impl(
|
||||
access_mode,std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
struct call_emplace_or_visit_impl
|
||||
{
|
||||
template<typename... Args>
|
||||
@@ -1465,15 +1561,49 @@ private:
|
||||
);
|
||||
}
|
||||
|
||||
struct call_emplace_and_visit_impl
|
||||
{
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE bool operator()(
|
||||
concurrent_table* this_,Args&&... args)const
|
||||
{
|
||||
return this_->emplace_and_visit_impl(std::forward<Args>(args)...);
|
||||
}
|
||||
};
|
||||
|
||||
template<typename GroupAccessMode,typename... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit_flast(
|
||||
GroupAccessMode access_mode,Args&&... args)
|
||||
{
|
||||
return mp11::tuple_apply(
|
||||
call_emplace_and_visit_impl{},
|
||||
std::tuple_cat(
|
||||
std::make_tuple(this,access_mode),
|
||||
tuple_rotate_right<2>(
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
template<typename GroupAccessMode,typename F,typename... Args>
|
||||
BOOST_FORCEINLINE bool emplace_or_visit_impl(
|
||||
GroupAccessMode access_mode,F&& f,Args&&... args)
|
||||
{
|
||||
return emplace_and_visit_impl(
|
||||
access_mode,[](const value_type&){},std::forward<F>(f),
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename GroupAccessMode,typename F1,typename F2,typename... Args>
|
||||
BOOST_FORCEINLINE bool emplace_and_visit_impl(
|
||||
GroupAccessMode access_mode,F1&& f1,F2&& f2,Args&&... args)
|
||||
{
|
||||
for(;;){
|
||||
{
|
||||
auto lck=shared_access();
|
||||
int res=unprotected_norehash_emplace_or_visit(
|
||||
access_mode,std::forward<F>(f),std::forward<Args>(args)...);
|
||||
int res=unprotected_norehash_emplace_and_visit(
|
||||
access_mode,std::forward<F1>(f1),std::forward<F2>(f2),
|
||||
std::forward<Args>(args)...);
|
||||
if(BOOST_LIKELY(res>=0))return res!=0;
|
||||
}
|
||||
rehash_if_full();
|
||||
@@ -1498,6 +1628,16 @@ private:
|
||||
return true;
|
||||
}
|
||||
|
||||
template<typename GroupAccessMode,typename F,typename... Args>
|
||||
BOOST_FORCEINLINE int
|
||||
unprotected_norehash_emplace_or_visit(
|
||||
GroupAccessMode access_mode,F&& f,Args&&... args)
|
||||
{
|
||||
return unprotected_norehash_emplace_and_visit(
|
||||
access_mode,[&](const value_type&){},
|
||||
std::forward<F>(f),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
struct reserve_size
|
||||
{
|
||||
reserve_size(concurrent_table& x_):x(x_)
|
||||
@@ -1539,10 +1679,10 @@ private:
|
||||
bool commit_=false;
|
||||
};
|
||||
|
||||
template<typename GroupAccessMode,typename F,typename... Args>
|
||||
template<typename GroupAccessMode,typename F1,typename F2,typename... Args>
|
||||
BOOST_FORCEINLINE int
|
||||
unprotected_norehash_emplace_or_visit(
|
||||
GroupAccessMode access_mode,F&& f,Args&&... args)
|
||||
unprotected_norehash_emplace_and_visit(
|
||||
GroupAccessMode access_mode,F1&& f1,F2&& f2,Args&&... args)
|
||||
{
|
||||
const auto &k=this->key_from(std::forward<Args>(args)...);
|
||||
auto hash=this->hash_for(k);
|
||||
@@ -1552,7 +1692,7 @@ private:
|
||||
startover:
|
||||
boost::uint32_t counter=insert_counter(pos0);
|
||||
if(unprotected_visit(
|
||||
access_mode,k,pos0,hash,std::forward<F>(f)))return 0;
|
||||
access_mode,k,pos0,hash,std::forward<F2>(f2)))return 0;
|
||||
|
||||
reserve_size rsize(*this);
|
||||
if(BOOST_LIKELY(rsize.succeeded())){
|
||||
@@ -1572,6 +1712,7 @@ private:
|
||||
this->construct_element(p,std::forward<Args>(args)...);
|
||||
rslot.commit();
|
||||
rsize.commit();
|
||||
f1(cast_for(group_exclusive{},type_policy::value_from(*p)));
|
||||
BOOST_UNORDERED_ADD_STATS(this->cstats.insertion,(pb.length()));
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
/* Copyright 2023-2024 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)
|
||||
@@ -19,27 +19,28 @@ namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
template<typename Tuple>
|
||||
template<std::size_t Offset,typename Tuple>
|
||||
using tuple_rotate_right_return_type=mp11::mp_rotate_right_c<
|
||||
typename std::remove_cv<typename std::remove_reference<Tuple>::type>::type,
|
||||
1
|
||||
Offset
|
||||
>;
|
||||
|
||||
template<std::size_t... Is,typename Tuple>
|
||||
tuple_rotate_right_return_type<Tuple>
|
||||
template<std::size_t Offset,std::size_t... Is,typename Tuple>
|
||||
tuple_rotate_right_return_type<Offset,Tuple>
|
||||
tuple_rotate_right_aux(mp11::index_sequence<Is...>,Tuple&& x)
|
||||
{
|
||||
return tuple_rotate_right_return_type<Tuple>{
|
||||
std::get<(Is+sizeof...(Is)-1)%sizeof...(Is)>(std::forward<Tuple>(x))...};
|
||||
return tuple_rotate_right_return_type<Offset,Tuple>{
|
||||
std::get<(Is+sizeof...(Is)-Offset)%sizeof...(Is)>(
|
||||
std::forward<Tuple>(x))...};
|
||||
}
|
||||
|
||||
template<typename Tuple>
|
||||
tuple_rotate_right_return_type<Tuple> tuple_rotate_right(Tuple&& x)
|
||||
template<std::size_t Offset=1,typename Tuple>
|
||||
tuple_rotate_right_return_type<Offset,Tuple> tuple_rotate_right(Tuple&& x)
|
||||
{
|
||||
using RawTuple=typename std::remove_cv<
|
||||
typename std::remove_reference<Tuple>::type>::type;
|
||||
|
||||
return tuple_rotate_right_aux(
|
||||
return tuple_rotate_right_aux<Offset>(
|
||||
mp11::make_index_sequence<std::tuple_size<RawTuple>::value>{},
|
||||
std::forward<Tuple>(x));
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <boost/unordered/detail/serialize_tracked_address.hpp>
|
||||
#include <boost/unordered/detail/static_assert.hpp>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
#include <boost/unordered/unordered_printers.hpp>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/core/allocator_traits.hpp>
|
||||
|
||||
@@ -182,6 +182,7 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
unordered_flat_map(
|
||||
concurrent_flat_map<Key, T, Hash, KeyEqual, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
|
||||
@@ -178,6 +178,7 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
unordered_flat_set(
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
|
||||
@@ -189,6 +189,7 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
unordered_node_map(
|
||||
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
|
||||
@@ -187,6 +187,7 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <bool avoid_explicit_instantiation = true>
|
||||
unordered_node_set(
|
||||
concurrent_node_set<Key, Hash, KeyEqual, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
|
||||
@@ -163,6 +163,10 @@ compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTIM
|
||||
compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_SET : insert_node_type_fail_set ;
|
||||
compile-fail unordered/insert_node_type_fail.cpp : <define>UNORDERED_TEST_MULTISET : insert_node_type_fail_multiset ;
|
||||
|
||||
compile unordered/explicit_instantiation_tests.cpp : : fca_explicit_instantiation_tests ;
|
||||
compile unordered/explicit_instantiation_tests.cpp : <define>BOOST_UNORDERED_FOA_TESTS : foa_explicit_instantiation_tests ;
|
||||
compile cfoa/explicit_instantiation_tests.cpp : : cfoa_explicit_instantiation_tests ;
|
||||
|
||||
local FCA_EXCEPTION_TESTS =
|
||||
constructor_exception_tests
|
||||
copy_exception_tests
|
||||
|
||||
@@ -53,6 +53,34 @@ namespace {
|
||||
return x.emplace_or_cvisit(v.first.x_, v.second.x_, f);
|
||||
}
|
||||
|
||||
template <typename Container, typename Value, typename F1, typename F2>
|
||||
bool member_emplace_and_visit(Container& x, Value& v, F1 f1, F2 f2)
|
||||
{
|
||||
return x.emplace_and_visit(v.x_, f1, f2);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Container, typename Key, typename Value, typename F1, typename F2>
|
||||
bool member_emplace_and_visit(
|
||||
Container& x, std::pair<Key, Value>& v, F1 f1, F2 f2)
|
||||
{
|
||||
return x.emplace_and_visit(v.first.x_, v.second.x_, f1, f2);
|
||||
}
|
||||
|
||||
template <typename Container, typename Value, typename F1, typename F2>
|
||||
bool member_emplace_and_cvisit(Container& x, Value& v, F1 f1, F2 f2)
|
||||
{
|
||||
return x.emplace_and_cvisit(v.x_, f1, f2);
|
||||
}
|
||||
|
||||
template <
|
||||
typename Container, typename Key, typename Value, typename F1, typename F2>
|
||||
bool member_emplace_and_cvisit(
|
||||
Container& x, std::pair<Key, Value>& v, F1 f1, F2 f2)
|
||||
{
|
||||
return x.emplace_and_cvisit(v.first.x_, v.second.x_, f1, f2);
|
||||
}
|
||||
|
||||
struct lvalue_emplacer_type
|
||||
{
|
||||
template <class T, class X> void call_impl(std::vector<T>& values, X& x)
|
||||
@@ -133,6 +161,55 @@ namespace {
|
||||
}
|
||||
} lvalue_emplace_or_cvisit;
|
||||
|
||||
struct lvalue_emplace_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = member_emplace_and_cvisit(
|
||||
x, r,
|
||||
[&num_inserts_internal](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(
|
||||
raii::default_constructor, value_type_cardinality * values.size());
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(raii::move_constructor, value_type_cardinality * x.size());
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||
}
|
||||
} lvalue_emplace_and_cvisit;
|
||||
|
||||
struct lvalue_emplace_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -176,6 +253,55 @@ namespace {
|
||||
}
|
||||
} lvalue_emplace_or_visit;
|
||||
|
||||
struct lvalue_emplace_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = member_emplace_and_visit(
|
||||
x, r,
|
||||
[&num_inserts_internal](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(
|
||||
raii::default_constructor, value_type_cardinality * values.size());
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(raii::move_constructor, value_type_cardinality * x.size());
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||
}
|
||||
} lvalue_emplace_and_visit;
|
||||
|
||||
struct copy_emplacer_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -312,6 +438,13 @@ UNORDERED_TEST(
|
||||
(lvalue_emplace_or_cvisit)(lvalue_emplace_or_visit)(copy_emplacer)(move_emplacer))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
emplace,
|
||||
((map)(node_map)(set)(node_set))
|
||||
((value_type_generator_factory)(init_type_generator_factory))
|
||||
((lvalue_emplace_and_cvisit)(lvalue_emplace_and_visit))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
// clang-format on
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
// Copyright 2024 Braden Ganetsky
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||
#include <boost/unordered/concurrent_node_map.hpp>
|
||||
#include <boost/unordered/concurrent_node_set.hpp>
|
||||
|
||||
template class boost::concurrent_flat_map<int, int>;
|
||||
template class boost::concurrent_flat_set<int>;
|
||||
template class boost::concurrent_node_map<int, int>;
|
||||
template class boost::concurrent_node_set<int>;
|
||||
|
||||
int main() { return 0; }
|
||||
@@ -86,7 +86,7 @@ namespace {
|
||||
while (!nh.empty()) {
|
||||
auto& o = out[br2++ % out.size()];
|
||||
typename X::insert_return_type r;
|
||||
switch (br3++ % 3) {
|
||||
switch (br3++ % 5) {
|
||||
case 0:
|
||||
r = o.insert(std::move(nh));
|
||||
break;
|
||||
@@ -97,13 +97,37 @@ namespace {
|
||||
(void)v2;
|
||||
});
|
||||
break;
|
||||
case 2: default:
|
||||
case 2:
|
||||
r = o.insert_or_cvisit(
|
||||
std::move(nh), [&](arg_visit_type const& v2) {
|
||||
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||
(void)v2;
|
||||
});
|
||||
break;
|
||||
case 3:
|
||||
r = o.insert_and_visit(
|
||||
std::move(nh),
|
||||
[&](arg_visit_type& v2) {
|
||||
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||
(void)v2;
|
||||
},
|
||||
[&](arg_visit_type& v2) {
|
||||
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||
(void)v2;
|
||||
});
|
||||
break;
|
||||
case 4: default:
|
||||
r = o.insert_and_cvisit(
|
||||
std::move(nh),
|
||||
[&](arg_visit_type& v2) {
|
||||
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||
(void)v2;
|
||||
},
|
||||
[&](arg_visit_type const& v2) {
|
||||
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||
(void)v2;
|
||||
});
|
||||
break;
|
||||
}
|
||||
BOOST_ASSERT(r.inserted || !r.node.empty());
|
||||
nh = std::move(r.node);
|
||||
@@ -144,6 +168,20 @@ namespace {
|
||||
BOOST_TEST(!r.inserted);
|
||||
BOOST_TEST(r.node.empty());
|
||||
}
|
||||
{
|
||||
node_type nh;
|
||||
auto r = x.insert_and_visit(
|
||||
std::move(nh), [](value_type const&) {}, [](value_type const&) {});
|
||||
BOOST_TEST(!r.inserted);
|
||||
BOOST_TEST(r.node.empty());
|
||||
}
|
||||
{
|
||||
node_type nh;
|
||||
auto r = x.insert_and_cvisit(
|
||||
std::move(nh), [](value_type const&) {}, [](value_type const&) {});
|
||||
BOOST_TEST(!r.inserted);
|
||||
BOOST_TEST(r.node.empty());
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
@@ -156,7 +194,7 @@ UNORDERED_TEST(
|
||||
|
||||
UNORDERED_TEST(
|
||||
insert_empty_node_tests,
|
||||
((test_node_map)(test_node_set)))
|
||||
((test_node_map)(test_node_set)))
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -149,7 +149,7 @@ namespace {
|
||||
}
|
||||
|
||||
thread_runner(values2, [&x](boost::span<raii_convertible> s) {
|
||||
x.insert(s.begin(), s.end());
|
||||
BOOST_TEST_EQ(x.insert(s.begin(), s.end()), s.size());
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(
|
||||
@@ -376,6 +376,62 @@ namespace {
|
||||
}
|
||||
} lvalue_insert_or_cvisit;
|
||||
|
||||
struct lvalue_insert_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.insert_and_cvisit(
|
||||
r,
|
||||
[&num_inserts_internal](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||
BOOST_TEST_EQ(
|
||||
raii::copy_constructor, value_type_cardinality * x.size());
|
||||
|
||||
if (is_container_node_based<X>::value) {
|
||||
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||
}
|
||||
else{
|
||||
// don't check move construction count here because of rehashing
|
||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
}
|
||||
} lvalue_insert_and_cvisit;
|
||||
|
||||
struct lvalue_insert_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -424,6 +480,61 @@ namespace {
|
||||
}
|
||||
} lvalue_insert_or_visit;
|
||||
|
||||
struct lvalue_insert_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b =
|
||||
x.insert_and_visit(r,
|
||||
[&num_inserts_internal](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||
BOOST_TEST_EQ(raii::copy_constructor, value_type_cardinality * x.size());
|
||||
|
||||
if (is_container_node_based<X>::value) {
|
||||
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||
}
|
||||
else{
|
||||
// don't check move construction count here because of rehashing
|
||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
}
|
||||
} lvalue_insert_and_visit;
|
||||
|
||||
struct rvalue_insert_or_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -470,6 +581,66 @@ namespace {
|
||||
}
|
||||
} rvalue_insert_or_cvisit;
|
||||
|
||||
struct rvalue_insert_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.insert_and_cvisit(
|
||||
std::move(r),
|
||||
[&num_inserts_internal](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||
|
||||
if (std::is_same<T, typename X::value_type>::value) {
|
||||
if (std::is_same<typename X::key_type,
|
||||
typename X::value_type>::value) {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
else {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
} else {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(
|
||||
raii::move_constructor, value_type_cardinality * x.size());
|
||||
}
|
||||
}
|
||||
} rvalue_insert_and_cvisit;
|
||||
|
||||
struct rvalue_insert_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -522,6 +693,65 @@ namespace {
|
||||
}
|
||||
} rvalue_insert_or_visit;
|
||||
|
||||
struct rvalue_insert_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.insert_and_visit(
|
||||
std::move(r),
|
||||
[&num_inserts_internal](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||
if (std::is_same<T, typename X::value_type>::value) {
|
||||
if (std::is_same<typename X::key_type,
|
||||
typename X::value_type>::value) {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
else {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
} else {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(
|
||||
raii::move_constructor, value_type_cardinality * x.size());
|
||||
}
|
||||
}
|
||||
} rvalue_insert_and_visit;
|
||||
|
||||
struct iterator_range_insert_or_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -538,11 +768,12 @@ namespace {
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(
|
||||
values2, [&x, &num_invokes](boost::span<raii_convertible> s) {
|
||||
x.insert_or_cvisit(s.begin(), s.end(),
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
BOOST_TEST_EQ(x.insert_or_cvisit(s.begin(), s.end(),
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
s.size());
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
@@ -561,6 +792,60 @@ namespace {
|
||||
}
|
||||
} iterator_range_insert_or_cvisit;
|
||||
|
||||
struct iterator_range_insert_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::vector<raii_convertible> values2;
|
||||
values2.reserve(values.size());
|
||||
for (auto const& v : values) {
|
||||
values2.push_back(raii_convertible(v));
|
||||
}
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values2,
|
||||
[&x, &num_inserts, &num_invokes](boost::span<raii_convertible> s) {
|
||||
BOOST_TEST_EQ(x.insert_and_cvisit(
|
||||
s.begin(), s.end(),
|
||||
[&num_inserts](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
s.size());
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(
|
||||
raii::default_constructor, value_type_cardinality * values2.size());
|
||||
#if (BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 50300) && \
|
||||
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50500)) || \
|
||||
(BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 40900) && \
|
||||
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50000))
|
||||
// skip test
|
||||
#else
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
#endif
|
||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||
}
|
||||
} iterator_range_insert_and_cvisit;
|
||||
|
||||
struct iterator_range_insert_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -568,6 +853,13 @@ namespace {
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::vector<raii_convertible> values2;
|
||||
values2.reserve(values.size());
|
||||
for (auto const& v : values) {
|
||||
@@ -577,11 +869,12 @@ namespace {
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(
|
||||
values2, [&x, &num_invokes](boost::span<raii_convertible> s) {
|
||||
x.insert_or_visit(s.begin(), s.end(),
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
BOOST_TEST_EQ(x.insert_or_visit(s.begin(), s.end(),
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
s.size());
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
@@ -600,6 +893,68 @@ namespace {
|
||||
}
|
||||
} iterator_range_insert_or_visit;
|
||||
|
||||
struct iterator_range_insert_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
static constexpr auto value_type_cardinality =
|
||||
value_cardinality<typename X::value_type>::value;
|
||||
|
||||
// concurrent_flat_set visit is always const access
|
||||
using arg_type = typename std::conditional<
|
||||
std::is_same<typename X::key_type, typename X::value_type>::value,
|
||||
typename X::value_type const,
|
||||
typename X::value_type
|
||||
>::type;
|
||||
|
||||
std::vector<raii_convertible> values2;
|
||||
values2.reserve(values.size());
|
||||
for (auto const& v : values) {
|
||||
values2.push_back(raii_convertible(v));
|
||||
}
|
||||
|
||||
std::atomic<std::uint64_t> num_inserts{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values2,
|
||||
[&x, &num_inserts, &num_invokes](boost::span<raii_convertible> s) {
|
||||
BOOST_TEST_EQ(x.insert_and_visit(
|
||||
s.begin(), s.end(),
|
||||
[&num_inserts](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
s.size());
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(
|
||||
raii::default_constructor, value_type_cardinality * values2.size());
|
||||
#if (BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 50300) && \
|
||||
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50500)) || \
|
||||
(BOOST_WORKAROUND(BOOST_GCC_VERSION, >= 40900) && \
|
||||
BOOST_WORKAROUND(BOOST_GCC_VERSION, < 50000))
|
||||
// skip test
|
||||
#else
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
#endif
|
||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||
}
|
||||
} iterator_range_insert_and_visit;
|
||||
|
||||
struct non_copyable_function
|
||||
{
|
||||
non_copyable_function() = default;
|
||||
non_copyable_function(const non_copyable_function&) = delete;
|
||||
non_copyable_function(non_copyable_function&&) = default;
|
||||
template <class... Args> void operator()(Args&&...) const {}
|
||||
};
|
||||
|
||||
template <class X, class GF, class F>
|
||||
void insert(X*, GF gen_factory, F inserter, test::random_generator rg)
|
||||
{
|
||||
@@ -655,8 +1010,9 @@ namespace {
|
||||
{
|
||||
X x;
|
||||
|
||||
thread_runner(
|
||||
dummy, [&x, &init_list](boost::span<raii>) { x.insert(init_list); });
|
||||
thread_runner(dummy, [&x, &init_list](boost::span<raii>) {
|
||||
BOOST_TEST_EQ(x.insert(init_list), init_list.size());
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(x.size(), reference_cont.size());
|
||||
|
||||
@@ -686,16 +1042,22 @@ namespace {
|
||||
X x;
|
||||
|
||||
thread_runner(dummy, [&x, &init_list, &num_invokes](boost::span<raii>) {
|
||||
x.insert_or_visit(init_list, [&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
BOOST_TEST_EQ(x.insert_or_visit(init_list,
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
init_list.size());
|
||||
|
||||
x.insert_or_cvisit(
|
||||
init_list, [&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
BOOST_TEST_EQ(x.insert_or_cvisit(init_list,
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
init_list.size());
|
||||
|
||||
x.insert_or_visit(init_list, non_copyable_function{});
|
||||
x.insert_or_cvisit(init_list, non_copyable_function{});
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_invokes, (init_list.size() - x.size()) +
|
||||
@@ -721,6 +1083,70 @@ namespace {
|
||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
|
||||
X x;
|
||||
|
||||
thread_runner(dummy,
|
||||
[&x, &init_list, &num_inserts, &num_invokes](boost::span<raii>) {
|
||||
BOOST_TEST_EQ(x.insert_and_visit(
|
||||
init_list,
|
||||
[&num_inserts](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts;
|
||||
},
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
init_list.size());
|
||||
|
||||
BOOST_TEST_EQ(x.insert_and_cvisit(
|
||||
init_list,
|
||||
[&num_inserts](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
}),
|
||||
init_list.size());
|
||||
|
||||
x.insert_and_visit(
|
||||
init_list, non_copyable_function{}, non_copyable_function{});
|
||||
x.insert_and_cvisit(
|
||||
init_list, non_copyable_function{}, non_copyable_function{});
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, (init_list.size() - x.size()) +
|
||||
(num_threads - 1) * init_list.size() +
|
||||
num_threads * init_list.size());
|
||||
BOOST_TEST_EQ(x.size(), reference_cont.size());
|
||||
|
||||
BOOST_TEST_EQ(x.size(), x.visit_all([&](value_type const& v) {
|
||||
BOOST_TEST(reference_cont.contains(get_key(v)));
|
||||
BOOST_TEST_EQ(v, *reference_cont.find(get_key(v)));
|
||||
}));
|
||||
}
|
||||
|
||||
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_TEST_EQ(raii::copy_assignment, 0u);
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -735,6 +1161,9 @@ namespace {
|
||||
|
||||
x.insert_or_visit({2, 3}, [](value_type&) {});
|
||||
x.insert_or_cvisit({3, 4}, [](value_type const&) {});
|
||||
|
||||
x.insert_and_visit({4, 5}, [](value_type&) {}, [](value_type&) {});
|
||||
x.insert_and_cvisit({5, 6}, [](value_type&) {}, [](value_type const&) {});
|
||||
}
|
||||
|
||||
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
||||
@@ -825,7 +1254,8 @@ using test::sequential;
|
||||
// clang-format off
|
||||
UNORDERED_TEST(
|
||||
insert_initializer_list,
|
||||
((map_and_init_list)(node_map_and_init_list)(set_and_init_list)))
|
||||
((map_and_init_list)(node_map_and_init_list)
|
||||
(set_and_init_list)(node_set_and_init_list)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
insert,
|
||||
@@ -840,6 +1270,16 @@ UNORDERED_TEST(
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
insert,
|
||||
((map)(fancy_map)(node_map)(fancy_node_map)
|
||||
(set)(fancy_set)(node_set)(fancy_node_set))
|
||||
((value_type_generator_factory)(init_type_generator_factory))
|
||||
((lvalue_insert_and_cvisit)(lvalue_insert_and_visit)
|
||||
(rvalue_insert_and_cvisit)(rvalue_insert_and_visit)
|
||||
(iterator_range_insert_and_cvisit)(iterator_range_insert_and_visit))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
insert,
|
||||
((map)(node_map))
|
||||
((init_type_generator_factory))
|
||||
|
||||
@@ -177,6 +177,53 @@ namespace {
|
||||
}
|
||||
} lvalue_try_emplace_or_cvisit;
|
||||
|
||||
struct lvalue_try_emplace_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.try_emplace_and_cvisit(
|
||||
r.first, r.second.x_,
|
||||
[&num_inserts_internal](typename X::value_type& v)
|
||||
{
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||
|
||||
if (is_container_node_based<X>::value) {
|
||||
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||
}
|
||||
else{
|
||||
// don't check move construction count here because of rehashing
|
||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||
}
|
||||
} lvalue_try_emplace_and_cvisit;
|
||||
|
||||
struct lvalue_try_emplace_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -217,6 +264,53 @@ namespace {
|
||||
}
|
||||
} lvalue_try_emplace_or_visit;
|
||||
|
||||
struct lvalue_try_emplace_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.try_emplace_and_visit(
|
||||
r.first, r.second.x_,
|
||||
[&num_inserts_internal](typename X::value_type& v)
|
||||
{
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||
|
||||
if (is_container_node_based<X>::value) {
|
||||
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||
}
|
||||
else{
|
||||
// don't check move construction count here because of rehashing
|
||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||
}
|
||||
} lvalue_try_emplace_and_visit;
|
||||
|
||||
struct rvalue_try_emplace_or_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -258,6 +352,54 @@ namespace {
|
||||
}
|
||||
} rvalue_try_emplace_or_cvisit;
|
||||
|
||||
struct rvalue_try_emplace_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.try_emplace_and_cvisit(
|
||||
std::move(r.first), r.second.x_,
|
||||
[&num_inserts_internal](typename X::value_type& v)
|
||||
{
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||
|
||||
if (std::is_same<T, typename X::value_type>::value) {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||
if (is_container_node_based<X>::value) {
|
||||
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||
}
|
||||
else{
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
} else {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
}
|
||||
} rvalue_try_emplace_and_cvisit;
|
||||
|
||||
struct rvalue_try_emplace_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -298,6 +440,53 @@ namespace {
|
||||
}
|
||||
} rvalue_try_emplace_or_visit;
|
||||
|
||||
struct rvalue_try_emplace_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.try_emplace_and_visit(
|
||||
std::move(r.first), r.second.x_,
|
||||
[&num_inserts_internal](typename X::value_type& v)
|
||||
{
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||
if (std::is_same<T, typename X::value_type>::value) {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||
if (is_container_node_based<X>::value) {
|
||||
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||
}
|
||||
else{
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
} else {
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||
}
|
||||
}
|
||||
} rvalue_try_emplace_and_visit;
|
||||
|
||||
struct transp_try_emplace_or_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -326,6 +515,41 @@ namespace {
|
||||
}
|
||||
} transp_try_emplace_or_cvisit;
|
||||
|
||||
struct transp_try_emplace_and_cvisit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.try_emplace_and_cvisit(
|
||||
r.first.x_, r.second.x_,
|
||||
[&num_inserts_internal](typename X::value_type& v)
|
||||
{
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type const& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
BOOST_TEST_EQ(raii::default_constructor, 2 * x.size());
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
}
|
||||
} transp_try_emplace_and_cvisit;
|
||||
|
||||
struct transp_try_emplace_or_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
@@ -355,6 +579,42 @@ namespace {
|
||||
}
|
||||
} transp_try_emplace_or_visit;
|
||||
|
||||
struct transp_try_emplace_and_visit_type
|
||||
{
|
||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||
{
|
||||
std::atomic<std::uint64_t> num_inserts{0}, num_inserts_internal{0};
|
||||
std::atomic<std::uint64_t> num_invokes{0};
|
||||
thread_runner(values,
|
||||
[&x, &num_inserts, &num_inserts_internal, &num_invokes](boost::span<T> s) {
|
||||
for (auto& r : s) {
|
||||
bool b = x.try_emplace_and_visit(
|
||||
r.first.x_, r.second.x_,
|
||||
[&num_inserts_internal](typename X::value_type& v)
|
||||
{
|
||||
(void)v;
|
||||
++num_inserts_internal;
|
||||
},
|
||||
[&num_invokes](typename X::value_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
if (b) {
|
||||
++num_inserts;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
BOOST_TEST_EQ(num_inserts, num_inserts_internal);
|
||||
BOOST_TEST_EQ(num_inserts, x.size());
|
||||
BOOST_TEST_EQ(num_invokes, values.size() - x.size());
|
||||
|
||||
BOOST_TEST_EQ(raii::default_constructor, 2 * x.size());
|
||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||
}
|
||||
} transp_try_emplace_and_visit;
|
||||
|
||||
template <class X, class G, class F>
|
||||
void try_emplace(X*, G gen, F try_emplacer, test::random_generator rg)
|
||||
{
|
||||
@@ -417,6 +677,14 @@ UNORDERED_TEST(
|
||||
(rvalue_try_emplace_or_cvisit)(rvalue_try_emplace_or_visit))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
try_emplace,
|
||||
((map)(node_map))
|
||||
((value_type_generator)(init_type_generator))
|
||||
((lvalue_try_emplace_and_cvisit)(lvalue_try_emplace_and_visit)
|
||||
(rvalue_try_emplace_and_cvisit)(rvalue_try_emplace_and_visit))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
try_emplace,
|
||||
((transp_map)(transp_node_map))
|
||||
@@ -424,6 +692,13 @@ UNORDERED_TEST(
|
||||
((transp_try_emplace)(norehash_transp_try_emplace)
|
||||
(transp_try_emplace_or_cvisit)(transp_try_emplace_or_visit))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
try_emplace,
|
||||
((transp_map)(transp_node_map))
|
||||
((init_type_generator))
|
||||
((transp_try_emplace_and_cvisit)(transp_try_emplace_and_visit))
|
||||
((default_generator)(sequential)(limited_range)))
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
// Copyright 2024 Braden Ganetsky
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_node_set.hpp>
|
||||
|
||||
template class boost::unordered_flat_map<int, int>;
|
||||
template class boost::unordered_flat_set<int>;
|
||||
template class boost::unordered_node_map<int, int>;
|
||||
template class boost::unordered_node_set<int>;
|
||||
|
||||
#else
|
||||
|
||||
#include <boost/unordered/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_set.hpp>
|
||||
|
||||
template class boost::unordered_map<int, int>;
|
||||
template class boost::unordered_multimap<int, int>;
|
||||
template class boost::unordered_multiset<int>;
|
||||
template class boost::unordered_set<int>;
|
||||
|
||||
#endif // BOOST_UNORDERED_FOA_TESTS
|
||||
|
||||
int main() { return 0; }
|
||||