mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-09 23:23:59 +00:00
added insert_and_visit and similar operations to concurrent containers (#283)
This commit is contained in:
parent
57546ed7e3
commit
834580b539
@ -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^]).
|
||||
|
@ -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(), 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_or_visit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type insert_or_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(), f1, 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(), 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(), f1, 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(), 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_or_visit(std::initializer_list<value_type> il, F1 f1, F2 f2);
|
||||
template<class F1, class F2>
|
||||
size_type insert_or_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(), f1, 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(), 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(), f1, 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);
|
||||
|
@ -517,6 +517,80 @@ namespace boost {
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), 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>
|
||||
void insert_and_visit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_visit(ilist.begin(), ilist.end(), f1, 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>
|
||||
void insert_and_cvisit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, f2);
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
@ -538,6 +612,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 +711,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);
|
||||
|
@ -517,6 +517,101 @@ namespace boost {
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), 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>
|
||||
void 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)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_visit(ilist.begin(), ilist.end(), f1, 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>
|
||||
void 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)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, f2);
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
@ -538,6 +633,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);
|
||||
|
@ -585,6 +585,124 @@ 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>
|
||||
void insert_and_visit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F2)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_visit(ilist.begin(), ilist.end(), f1, 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>
|
||||
void insert_and_cvisit(
|
||||
InputIterator first, InputIterator last, F1 f1, F2 f2)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F1)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F2)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, 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 +724,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 +823,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);
|
||||
|
@ -585,6 +585,145 @@ 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>
|
||||
void 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)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_visit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_visit(ilist.begin(), ilist.end(), f1, 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>
|
||||
void 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)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_and_cvisit(*first, f1, f2);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F1, class F2>
|
||||
void 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)
|
||||
this->insert_and_cvisit(ilist.begin(), ilist.end(), f1, 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 +745,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)
|
||||
@ -58,6 +58,24 @@
|
||||
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 {
|
||||
|
@ -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));
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
@ -561,6 +791,58 @@ 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) {
|
||||
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;
|
||||
});
|
||||
});
|
||||
|
||||
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 +850,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) {
|
||||
@ -578,7 +867,7 @@ namespace {
|
||||
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) {
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
@ -600,6 +889,58 @@ 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) {
|
||||
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;
|
||||
});
|
||||
});
|
||||
|
||||
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;
|
||||
|
||||
template <class X, class GF, class F>
|
||||
void insert(X*, GF gen_factory, F inserter, test::random_generator rg)
|
||||
{
|
||||
@ -721,6 +1062,62 @@ 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>) {
|
||||
x.insert_and_visit(init_list,
|
||||
[&num_inserts](arg_type& v) {
|
||||
(void)v;
|
||||
++num_inserts;
|
||||
},
|
||||
[&num_invokes](arg_type& v) {
|
||||
(void)v;
|
||||
++num_invokes;
|
||||
});
|
||||
|
||||
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;
|
||||
});
|
||||
});
|
||||
|
||||
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 +1132,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 +1225,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 +1241,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()
|
||||
|
Loading…
x
Reference in New Issue
Block a user