mirror of
https://github.com/boostorg/unordered.git
synced 2025-05-09 23:23:59 +00:00
Feature/concurrent node containers (#271)
* added concurrent node containers * removed spurious typename * added missing includes * avoided unused param warning * worked around Clang bug * s/{}/() to work around GCC4.8 problems with aggregate initialization * used /bigobj for cfoa/visit_tests.cpp * suppressed localized maybe-uninitialized warnings * fixed comments * added /bigobj to cfoa/insert_tests.cpp * instrumented double exact comparison to spot a spurious error * fixed pedantic error * refactored byte_span machinery * compromised on sub-epsilon equality for doubles that should be identical * documented boost::concurrent_node_(map|set) * added concurrent_node_set * added missing AlternativeType * tested empty node insertion * tested node_handle allocator management * added nonassignable_allocator and node_handle_allocator_swap_tests * fixed warning disabling * silenced spurious GCC warning * broadened scope of previous pragma * broadened even more * worked around spurious constexpr-related msvc-14.0 bug https://godbolt.org/z/v78545Ebf * added workaround back * replaced previous workaround with built-in one * added workaround back on top of built-in solution (which doesn't work 100% of the time)
This commit is contained in:
parent
35bdabf259
commit
f734e399e3
@ -126,7 +126,7 @@ h|*Method* h|*Description*
|
|||||||
|
|
||||||
|`float max_load_factor(float z)`
|
|`float max_load_factor(float z)`
|
||||||
|Changes the container's maximum load factor, using `z` as a hint. +
|
|Changes the container's maximum load factor, using `z` as a hint. +
|
||||||
**Open-addressing containers:** this function does nothing: users are not allowed to change the maximum load factor.
|
**Open-addressing and concurrent containers:** this function does nothing: users are not allowed to change the maximum load factor.
|
||||||
|
|
||||||
|`void rehash(size_type n)`
|
|`void rehash(size_type n)`
|
||||||
|Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
|
|Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor.
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
:github-pr-url: https://github.com/boostorg/unordered/pull
|
:github-pr-url: https://github.com/boostorg/unordered/pull
|
||||||
:cpp: C++
|
:cpp: C++
|
||||||
|
|
||||||
== Release 1.87.0
|
== Release 1.87.0 - Major update
|
||||||
|
|
||||||
|
* Added concurrent, node-based containers `boost::concurrent_node_map` and `boost::concurrent_node_set`.
|
||||||
* Made visitation exclusive-locked within certain
|
* Made visitation exclusive-locked within certain
|
||||||
`boost::concurrent_flat_set` operations to allow for safe mutable modification of elements
|
`boost::concurrent_flat_set` operations to allow for safe mutable modification of elements
|
||||||
({github-pr-url}/265[PR#265^]).
|
({github-pr-url}/265[PR#265^]).
|
||||||
|
@ -89,7 +89,8 @@ The main differences with C++ unordered associative containers are:
|
|||||||
== Concurrent Containers
|
== Concurrent Containers
|
||||||
|
|
||||||
There is currently no specification in the C++ standard for this or any other type of concurrent
|
There is currently no specification in the C++ standard for this or any other type of concurrent
|
||||||
data structure. The APIs of `boost::concurrent_flat_set` and `boost::concurrent_flat_map`
|
data structure. The APIs of `boost::concurrent_flat_set`/`boost::concurrent_node_set` and
|
||||||
|
`boost::concurrent_flat_map`/`boost::concurrent_node_map`
|
||||||
are modelled after `std::unordered_flat_set` and `std::unordered_flat_map`, respectively,
|
are modelled after `std::unordered_flat_set` and `std::unordered_flat_map`, respectively,
|
||||||
with the crucial difference that iterators are not provided
|
with the crucial difference that iterators are not provided
|
||||||
due to their inherent problems in concurrent scenarios (high contention, prone to deadlocking):
|
due to their inherent problems in concurrent scenarios (high contention, prone to deadlocking):
|
||||||
@ -105,7 +106,7 @@ In a non-concurrent unordered container, iterators serve two main purposes:
|
|||||||
* Access to an element previously located via lookup.
|
* Access to an element previously located via lookup.
|
||||||
* Container traversal.
|
* Container traversal.
|
||||||
|
|
||||||
In place of iterators, `boost::concurrent_flat_set` and `boost::concurrent_flat_map` use _internal visitation_
|
In place of iterators, Boost.Unordered concurrent containers use _internal visitation_
|
||||||
facilities as a thread-safe substitute. Classical operations returning an iterator to an
|
facilities as a thread-safe substitute. Classical operations returning an iterator to an
|
||||||
element already existing in the container, like for instance:
|
element already existing in the container, like for instance:
|
||||||
|
|
||||||
@ -141,7 +142,8 @@ respectively, here visitation is granted mutable or const access depending on
|
|||||||
the constness of the member function used (there are also `*cvisit` overloads for
|
the constness of the member function used (there are also `*cvisit` overloads for
|
||||||
explicit const visitation); In the case of `boost::concurrent_flat_set`, visitation is always const.
|
explicit const visitation); In the case of `boost::concurrent_flat_set`, visitation is always const.
|
||||||
|
|
||||||
One notable operation not provided by `boost::concurrent_flat_map` is `operator[]`/`at`, which can be
|
One notable operation not provided by `boost::concurrent_flat_map`/`boost::concurrent_node_map`
|
||||||
|
is `operator[]`/`at`, which can be
|
||||||
replaced, if in a more convoluted manner, by
|
replaced, if in a more convoluted manner, by
|
||||||
xref:#concurrent_flat_map_try_emplace_or_cvisit[`try_emplace_or_visit`].
|
xref:#concurrent_flat_map_try_emplace_or_cvisit[`try_emplace_or_visit`].
|
||||||
|
|
||||||
|
@ -3,7 +3,8 @@
|
|||||||
|
|
||||||
:idprefix: concurrent_
|
:idprefix: concurrent_
|
||||||
|
|
||||||
Boost.Unordered provides `boost::concurrent_flat_set` and `boost::concurrent_flat_map`,
|
Boost.Unordered provides `boost::concurrent_node_set`, `boost::concurrent_node_map`,
|
||||||
|
`boost::concurrent_flat_set` and `boost::concurrent_flat_map`,
|
||||||
hash tables that allow concurrent write/read access from
|
hash tables that allow concurrent write/read access from
|
||||||
different threads without having to implement any synchronzation mechanism on the user's side.
|
different threads without having to implement any synchronzation mechanism on the user's side.
|
||||||
|
|
||||||
@ -43,7 +44,7 @@ logical cores in the CPU).
|
|||||||
|
|
||||||
== Visitation-based API
|
== Visitation-based API
|
||||||
|
|
||||||
The first thing a new user of `boost::concurrent_flat_set` or `boost::concurrent_flat_map`
|
The first thing a new user of Boost.Unordered concurrent containers
|
||||||
will notice is that these classes _do not provide iterators_ (which makes them technically
|
will notice is that these classes _do not provide iterators_ (which makes them technically
|
||||||
not https://en.cppreference.com/w/cpp/named_req/Container[Containers^]
|
not https://en.cppreference.com/w/cpp/named_req/Container[Containers^]
|
||||||
in the C++ standard sense). The reason for this is that iterators are inherently
|
in the C++ standard sense). The reason for this is that iterators are inherently
|
||||||
@ -62,7 +63,7 @@ thread issues an `m.erase(k)` operation between A and B. There are designs that
|
|||||||
can remedy this by making iterators lock the element they point to, but this
|
can remedy this by making iterators lock the element they point to, but this
|
||||||
approach lends itself to high contention and can easily produce deadlocks in a program.
|
approach lends itself to high contention and can easily produce deadlocks in a program.
|
||||||
`operator[]` has similar concurrency issues, and is not provided by
|
`operator[]` has similar concurrency issues, and is not provided by
|
||||||
`boost::concurrent_flat_map` either. Instead, element access is done through
|
`boost::concurrent_flat_map`/`boost::concurrent_node_map` either. Instead, element access is done through
|
||||||
so-called _visitation functions_:
|
so-called _visitation functions_:
|
||||||
|
|
||||||
[source,c++]
|
[source,c++]
|
||||||
@ -112,7 +113,7 @@ if (found) {
|
|||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
Visitation is prominent in the API provided by `boost::concurrent_flat_set` and `boost::concurrent_flat_map`, and
|
Visitation is prominent in the API provided by concurrent containers, and
|
||||||
many classical operations have visitation-enabled variations:
|
many classical operations have visitation-enabled variations:
|
||||||
|
|
||||||
[source,c++]
|
[source,c++]
|
||||||
@ -125,13 +126,15 @@ m.insert_or_visit(x, [](auto& y) {
|
|||||||
----
|
----
|
||||||
|
|
||||||
Note that in this last example the visitation function could actually _modify_
|
Note that in this last example the visitation function could actually _modify_
|
||||||
the element: as a general rule, operations on a `boost::concurrent_flat_map` `m`
|
the element: as a general rule, operations on a concurrent map `m`
|
||||||
will grant visitation functions const/non-const access to the element depending on whether
|
will grant visitation functions const/non-const access to the element depending on whether
|
||||||
`m` is const/non-const. Const access can be always be explicitly requested
|
`m` is const/non-const. Const access can be always be explicitly requested
|
||||||
by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result
|
by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result
|
||||||
in higher parallelization. For `boost::concurrent_flat_set`, on the other hand,
|
in higher parallelization. For concurrent sets, on the other hand,
|
||||||
visitation is always const access.
|
visitation is always const access.
|
||||||
Consult the references of
|
Consult the references of
|
||||||
|
xref:#concurrent_node_set[`boost::concurrent_node_set`],
|
||||||
|
xref:#concurrent_flat_map[`boost::concurrent_node_map`],
|
||||||
xref:#concurrent_flat_set[`boost::concurrent_flat_set`] and
|
xref:#concurrent_flat_set[`boost::concurrent_flat_set`] and
|
||||||
xref:#concurrent_flat_map[`boost::concurrent_flat_map`]
|
xref:#concurrent_flat_map[`boost::concurrent_flat_map`]
|
||||||
for the complete list of visitation-enabled operations.
|
for the complete list of visitation-enabled operations.
|
||||||
@ -245,7 +248,7 @@ may yield worse performance.
|
|||||||
|
|
||||||
== Blocking Operations
|
== Blocking Operations
|
||||||
|
|
||||||
``boost::concurrent_flat_set``s and ``boost::concurrent_flat_map``s can be copied, assigned, cleared and merged just like any
|
Concurrent containers can be copied, assigned, cleared and merged just like any other
|
||||||
Boost.Unordered container. Unlike most other operations, these are _blocking_,
|
Boost.Unordered container. Unlike most other operations, these are _blocking_,
|
||||||
that is, all other threads are prevented from accesing the tables involved while a copy, assignment,
|
that is, all other threads are prevented from accesing the tables involved while a copy, assignment,
|
||||||
clear or merge operation is in progress. Blocking is taken care of automatically by the library
|
clear or merge operation is in progress. Blocking is taken care of automatically by the library
|
||||||
@ -258,9 +261,25 @@ reserving space in advance of bulk insertions will generally speed up the proces
|
|||||||
== Interoperability with non-concurrent containers
|
== Interoperability with non-concurrent containers
|
||||||
|
|
||||||
As open-addressing and concurrent containers are based on the same internal data structure,
|
As open-addressing and concurrent containers are based on the same internal data structure,
|
||||||
`boost::unordered_flat_set` and `boost::unordered_flat_map` can
|
they can be efficiently move-constructed from their non-concurrent counterpart, and vice versa.
|
||||||
be efficiently move-constructed from `boost::concurrent_flat_set` and `boost::concurrent_flat_map`,
|
|
||||||
respectively, and vice versa.
|
[caption=, title='Table {counter:table-counter}. Concurrent/non-concurrent interoperatibility']
|
||||||
|
[cols="1,1", frame=all, grid=all]
|
||||||
|
|===
|
||||||
|
^|`boost::concurrent_node_set`
|
||||||
|
^|`boost::unordered_node_set`
|
||||||
|
|
||||||
|
^|`boost::concurrent_node_map`
|
||||||
|
^|`boost::unordered_node_map`
|
||||||
|
|
||||||
|
^|`boost::concurrent_flat_set`
|
||||||
|
^|`boost::unordered_flat_set`
|
||||||
|
|
||||||
|
^|`boost::concurrent_flat_map`
|
||||||
|
^|`boost::unordered_flat_map`
|
||||||
|
|
||||||
|
|===
|
||||||
|
|
||||||
This interoperability comes handy in multistage scenarios where parts of the data processing happen
|
This interoperability comes handy in multistage scenarios where parts of the data processing happen
|
||||||
in parallel whereas other steps are non-concurrent (or non-modifying). In the following example,
|
in parallel whereas other steps are non-concurrent (or non-modifying). In the following example,
|
||||||
we want to construct a histogram from a huge input vector of words:
|
we want to construct a histogram from a huge input vector of words:
|
||||||
|
1765
doc/unordered/concurrent_node_map.adoc
Normal file
1765
doc/unordered/concurrent_node_map.adoc
Normal file
File diff suppressed because it is too large
Load Diff
1599
doc/unordered/concurrent_node_set.adoc
Normal file
1599
doc/unordered/concurrent_node_set.adoc
Normal file
File diff suppressed because it is too large
Load Diff
@ -43,7 +43,8 @@ boost::unordered_node_map
|
|||||||
boost::unordered_flat_map
|
boost::unordered_flat_map
|
||||||
|
|
||||||
^.^h|*Concurrent*
|
^.^h|*Concurrent*
|
||||||
^|
|
^| `boost::concurrent_node_set` +
|
||||||
|
`boost::concurrent_node_map`
|
||||||
^| `boost::concurrent_flat_set` +
|
^| `boost::concurrent_flat_set` +
|
||||||
`boost::concurrent_flat_map`
|
`boost::concurrent_flat_map`
|
||||||
|
|
||||||
@ -59,6 +60,7 @@ There are two variants: **flat** (the fastest) and **node-based**, which
|
|||||||
provide pointer stability under rehashing at the expense of being slower.
|
provide pointer stability under rehashing at the expense of being slower.
|
||||||
* Finally, **concurrent containers** are designed and implemented to be used in high-performance
|
* Finally, **concurrent containers** are designed and implemented to be used in high-performance
|
||||||
multithreaded scenarios. Their interface is radically different from that of regular C++ containers.
|
multithreaded scenarios. Their interface is radically different from that of regular C++ containers.
|
||||||
|
Flat and node-based variants are provided.
|
||||||
|
|
||||||
All sets and maps in Boost.Unordered are instantiatied similarly as
|
All sets and maps in Boost.Unordered are instantiatied similarly as
|
||||||
`std::unordered_set` and `std::unordered_map`, respectively:
|
`std::unordered_set` and `std::unordered_map`, respectively:
|
||||||
@ -72,8 +74,8 @@ namespace boost {
|
|||||||
class Pred = std::equal_to<Key>,
|
class Pred = std::equal_to<Key>,
|
||||||
class Alloc = std::allocator<Key> >
|
class Alloc = std::allocator<Key> >
|
||||||
class unordered_set;
|
class unordered_set;
|
||||||
// same for unordered_multiset, unordered_flat_set, unordered_node_set
|
// same for unordered_multiset, unordered_flat_set, unordered_node_set,
|
||||||
// and concurrent_flat_set
|
// concurrent_flat_set and concurrent_node_set
|
||||||
|
|
||||||
template <
|
template <
|
||||||
class Key, class Mapped,
|
class Key, class Mapped,
|
||||||
@ -81,8 +83,8 @@ namespace boost {
|
|||||||
class Pred = std::equal_to<Key>,
|
class Pred = std::equal_to<Key>,
|
||||||
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
|
||||||
class unordered_map;
|
class unordered_map;
|
||||||
// same for unordered_multimap, unordered_flat_map, unordered_node_map
|
// same for unordered_multimap, unordered_flat_map, unordered_node_map,
|
||||||
// and concurrent_flat_map
|
// concurrent_flat_map and concurrent_node_map
|
||||||
}
|
}
|
||||||
----
|
----
|
||||||
|
|
||||||
|
@ -121,7 +121,8 @@ for Visual Studio on an x64-mode Intel CPU with SSE2 and for GCC on an IBM s390x
|
|||||||
== Concurrent Containers
|
== Concurrent Containers
|
||||||
|
|
||||||
The same data structure used by Boost.Unordered open-addressing containers has been chosen
|
The same data structure used by Boost.Unordered open-addressing containers has been chosen
|
||||||
also as the foundation of `boost::concurrent_flat_set` and `boost::concurrent_flat_map`:
|
also as the foundation of `boost::concurrent_flat_set`/`boost::concurrent_node_set` and
|
||||||
|
`boost::concurrent_flat_map`/`boost::concurrent_node_map`:
|
||||||
|
|
||||||
* Open-addressing is faster than closed-addressing alternatives, both in non-concurrent and
|
* Open-addressing is faster than closed-addressing alternatives, both in non-concurrent and
|
||||||
concurrent scenarios.
|
concurrent scenarios.
|
||||||
@ -130,7 +131,7 @@ with minimal locking. In particular, the metadata array can be used for implemen
|
|||||||
lookup that are lock-free up to the last step of actual element comparison.
|
lookup that are lock-free up to the last step of actual element comparison.
|
||||||
* Layout compatibility with Boost.Unordered flat containers allows for
|
* Layout compatibility with Boost.Unordered flat containers allows for
|
||||||
xref:#concurrent_interoperability_with_non_concurrent_containers[fast transfer]
|
xref:#concurrent_interoperability_with_non_concurrent_containers[fast transfer]
|
||||||
of all elements between `boost::concurrent_flat_map` and `boost::unordered_flat_map`,
|
of all elements between a concurrent container and its non-concurrent counterpart,
|
||||||
and vice versa.
|
and vice versa.
|
||||||
|
|
||||||
=== Hash Function and Platform Interoperability
|
=== Hash Function and Platform Interoperability
|
||||||
|
@ -13,3 +13,5 @@ include::unordered_node_map.adoc[]
|
|||||||
include::unordered_node_set.adoc[]
|
include::unordered_node_set.adoc[]
|
||||||
include::concurrent_flat_map.adoc[]
|
include::concurrent_flat_map.adoc[]
|
||||||
include::concurrent_flat_set.adoc[]
|
include::concurrent_flat_set.adoc[]
|
||||||
|
include::concurrent_node_map.adoc[]
|
||||||
|
include::concurrent_node_set.adoc[]
|
||||||
|
@ -129,7 +129,8 @@ xref:#rationale_open_addresing_containers[corresponding section].
|
|||||||
|
|
||||||
== Concurrent Containers
|
== Concurrent Containers
|
||||||
|
|
||||||
`boost::concurrent_flat_set` and `boost::concurrent_flat_map` use the basic
|
`boost::concurrent_flat_set`/`boost::concurrent_node_set` and
|
||||||
|
`boost::concurrent_flat_map`/`boost::concurrent_node_map` use the basic
|
||||||
xref:#structures_open_addressing_containers[open-addressing layout] described above
|
xref:#structures_open_addressing_containers[open-addressing layout] described above
|
||||||
augmented with synchronization mechanisms.
|
augmented with synchronization mechanisms.
|
||||||
|
|
||||||
|
@ -78,6 +78,7 @@ namespace boost {
|
|||||||
explicit xref:#unordered_node_map_allocator_constructor[unordered_node_map](const Allocator& a);
|
explicit xref:#unordered_node_map_allocator_constructor[unordered_node_map](const Allocator& a);
|
||||||
xref:#unordered_node_map_copy_constructor_with_allocator[unordered_node_map](const unordered_node_map& other, const Allocator& a);
|
xref:#unordered_node_map_copy_constructor_with_allocator[unordered_node_map](const unordered_node_map& other, const Allocator& a);
|
||||||
xref:#unordered_node_map_move_constructor_with_allocator[unordered_node_map](unordered_node_map&& other, const Allocator& a);
|
xref:#unordered_node_map_move_constructor_with_allocator[unordered_node_map](unordered_node_map&& other, const Allocator& a);
|
||||||
|
xref:#unordered_node_map_move_constructor_from_concurrent_node_map[unordered_node_map](concurrent_node_map<Key, T, Hash, Pred, Allocator>&& other);
|
||||||
xref:#unordered_node_map_initializer_list_constructor[unordered_node_map](std::initializer_list<value_type> il,
|
xref:#unordered_node_map_initializer_list_constructor[unordered_node_map](std::initializer_list<value_type> il,
|
||||||
size_type n = _implementation-defined_
|
size_type n = _implementation-defined_
|
||||||
const hasher& hf = hasher(),
|
const hasher& hf = hasher(),
|
||||||
@ -537,6 +538,24 @@ and always calls `other.reset_stats()`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
==== Move Constructor from concurrent_node_map
|
||||||
|
|
||||||
|
```c++
|
||||||
|
unordered_node_map(concurrent_node_map<Key, T, Hash, Pred, Allocator>&& other);
|
||||||
|
```
|
||||||
|
|
||||||
|
Move construction from a xref:#concurrent_node_map[`concurrent_node_map`].
|
||||||
|
The internal bucket array of `other` is transferred directly to the new container.
|
||||||
|
The hash function, predicate and allocator are moved-constructed from `other`.
|
||||||
|
If statistics are xref:unordered_node_map_boost_unordered_enable_stats[enabled],
|
||||||
|
transfers the internal statistical information from `other` and calls `other.reset_stats()`.
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
Complexity:;; Constant time.
|
||||||
|
Concurrency:;; Blocking on `other`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
==== Initializer List Constructor
|
==== Initializer List Constructor
|
||||||
[source,c++,subs="+quotes"]
|
[source,c++,subs="+quotes"]
|
||||||
----
|
----
|
||||||
@ -1219,8 +1238,8 @@ Throws:;; Nothing.
|
|||||||
|
|
||||||
==== Extract by Key
|
==== Extract by Key
|
||||||
```c++
|
```c++
|
||||||
node_type erase(const key_type& k);
|
node_type extract(const key_type& k);
|
||||||
template<class K> node_type erase(K&& k);
|
template<class K> node_type extract(K&& k);
|
||||||
```
|
```
|
||||||
|
|
||||||
Extracts the element with key equivalent to `k`, if it exists.
|
Extracts the element with key equivalent to `k`, if it exists.
|
||||||
@ -1228,7 +1247,7 @@ Extracts the element with key equivalent to `k`, if it exists.
|
|||||||
[horizontal]
|
[horizontal]
|
||||||
Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted.
|
Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted.
|
||||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||||
Notes:;; The `template<class K>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. 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.
|
Notes:;; The `template<class K>` overload only participates 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -73,6 +73,7 @@ namespace boost {
|
|||||||
explicit xref:#unordered_node_set_allocator_constructor[unordered_node_set](const Allocator& a);
|
explicit xref:#unordered_node_set_allocator_constructor[unordered_node_set](const Allocator& a);
|
||||||
xref:#unordered_node_set_copy_constructor_with_allocator[unordered_node_set](const unordered_node_set& other, const Allocator& a);
|
xref:#unordered_node_set_copy_constructor_with_allocator[unordered_node_set](const unordered_node_set& other, const Allocator& a);
|
||||||
xref:#unordered_node_set_move_constructor_with_allocator[unordered_node_set](unordered_node_set&& other, const Allocator& a);
|
xref:#unordered_node_set_move_constructor_with_allocator[unordered_node_set](unordered_node_set&& other, const Allocator& a);
|
||||||
|
xref:#unordered_node_set_move_constructor_from_concurrent_node_set[unordered_node_set](concurrent_node_set<Key, Hash, Pred, Allocator>&& other);
|
||||||
xref:#unordered_node_set_initializer_list_constructor[unordered_node_set](std::initializer_list<value_type> il,
|
xref:#unordered_node_set_initializer_list_constructor[unordered_node_set](std::initializer_list<value_type> il,
|
||||||
size_type n = _implementation-defined_
|
size_type n = _implementation-defined_
|
||||||
const hasher& hf = hasher(),
|
const hasher& hf = hasher(),
|
||||||
@ -489,6 +490,24 @@ and always calls `other.reset_stats()`.
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
==== Move Constructor from concurrent_node_set
|
||||||
|
|
||||||
|
```c++
|
||||||
|
unordered_node_set(concurrent_node_set<Key, Hash, Pred, Allocator>&& other);
|
||||||
|
```
|
||||||
|
|
||||||
|
Move construction from a xref:#concurrent_node_set[`concurrent_node_set`].
|
||||||
|
The internal bucket array of `other` is transferred directly to the new container.
|
||||||
|
The hash function, predicate and allocator are moved-constructed from `other`.
|
||||||
|
If statistics are xref:unordered_node_set_boost_unordered_enable_stats[enabled],
|
||||||
|
transfers the internal statistical information from `other` and calls `other.reset_stats()`.
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
Complexity:;; Constant time.
|
||||||
|
Concurrency:;; Blocking on `other`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
==== Initializer List Constructor
|
==== Initializer List Constructor
|
||||||
[source,c++,subs="+quotes"]
|
[source,c++,subs="+quotes"]
|
||||||
----
|
----
|
||||||
@ -1028,8 +1047,8 @@ Throws:;; Nothing.
|
|||||||
|
|
||||||
==== Extract by Key
|
==== Extract by Key
|
||||||
```c++
|
```c++
|
||||||
node_type erase(const key_type& k);
|
node_type extract(const key_type& k);
|
||||||
template<class K> node_type erase(K&& k);
|
template<class K> node_type extract(K&& k);
|
||||||
```
|
```
|
||||||
|
|
||||||
Extracts the element with key equivalent to `k`, if it exists.
|
Extracts the element with key equivalent to `k`, if it exists.
|
||||||
@ -1037,7 +1056,7 @@ Extracts the element with key equivalent to `k`, if it exists.
|
|||||||
[horizontal]
|
[horizontal]
|
||||||
Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted.
|
Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted.
|
||||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||||
Notes:;; The `template<class K>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. 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.
|
Notes:;; The `template<class K>` overload only participates 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.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
@ -421,6 +421,8 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<AlternativeType Name="boost::unordered::unordered_node_set<*>" />
|
<AlternativeType Name="boost::unordered::unordered_node_set<*>" />
|
||||||
<AlternativeType Name="boost::unordered::concurrent_flat_map<*>" />
|
<AlternativeType Name="boost::unordered::concurrent_flat_map<*>" />
|
||||||
<AlternativeType Name="boost::unordered::concurrent_flat_set<*>" />
|
<AlternativeType Name="boost::unordered::concurrent_flat_set<*>" />
|
||||||
|
<AlternativeType Name="boost::unordered::concurrent_node_map<*>" />
|
||||||
|
<AlternativeType Name="boost::unordered::concurrent_node_set<*>" />
|
||||||
<DisplayString>{{ size={table_.size_ctrl.size} }}</DisplayString>
|
<DisplayString>{{ size={table_.size_ctrl.size} }}</DisplayString>
|
||||||
<Expand>
|
<Expand>
|
||||||
<Item Name="[hash_function]" ExcludeView="simple">*reinterpret_cast<hasher*>(static_cast<table_type::super::hash_base*>(&table_))</Item>
|
<Item Name="[hash_function]" ExcludeView="simple">*reinterpret_cast<hasher*>(static_cast<table_type::super::hash_base*>(&table_))</Item>
|
||||||
@ -433,6 +435,7 @@ file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|||||||
<Type Name="boost::unordered::unordered_flat_map<*>" Priority="MediumHigh" ExcludeView="ShowElementsByIndex">
|
<Type Name="boost::unordered::unordered_flat_map<*>" Priority="MediumHigh" ExcludeView="ShowElementsByIndex">
|
||||||
<AlternativeType Name="boost::unordered::unordered_node_map<*>" />
|
<AlternativeType Name="boost::unordered::unordered_node_map<*>" />
|
||||||
<AlternativeType Name="boost::unordered::concurrent_flat_map<*>" />
|
<AlternativeType Name="boost::unordered::concurrent_flat_map<*>" />
|
||||||
|
<AlternativeType Name="boost::unordered::concurrent_node_map<*>" />
|
||||||
<DisplayString>{{ size={table_.size_ctrl.size} }}</DisplayString>
|
<DisplayString>{{ size={table_.size_ctrl.size} }}</DisplayString>
|
||||||
<Expand>
|
<Expand>
|
||||||
<Item Name="[hash_function]" ExcludeView="simple">*reinterpret_cast<hasher*>(static_cast<table_type::super::hash_base*>(&table_))</Item>
|
<Item Name="[hash_function]" ExcludeView="simple">*reinterpret_cast<hasher*>(static_cast<table_type::super::hash_base*>(&table_))</Item>
|
||||||
|
975
include/boost/unordered/concurrent_node_map.hpp
Normal file
975
include/boost/unordered/concurrent_node_map.hpp
Normal file
@ -0,0 +1,975 @@
|
|||||||
|
/* Fast open-addressing, node-based concurrent hashmap.
|
||||||
|
*
|
||||||
|
* Copyright 2023 Christian Mazakas.
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_UNORDERED_CONCURRENT_NODE_MAP_HPP
|
||||||
|
#define BOOST_UNORDERED_CONCURRENT_NODE_MAP_HPP
|
||||||
|
|
||||||
|
#include <boost/unordered/concurrent_node_map_fwd.hpp>
|
||||||
|
#include <boost/unordered/detail/concurrent_static_asserts.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/concurrent_table.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/element_type.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/node_map_handle.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/node_map_types.hpp>
|
||||||
|
#include <boost/unordered/detail/type_traits.hpp>
|
||||||
|
#include <boost/unordered/unordered_node_map_fwd.hpp>
|
||||||
|
|
||||||
|
#include <boost/container_hash/hash.hpp>
|
||||||
|
#include <boost/core/allocator_access.hpp>
|
||||||
|
#include <boost/core/serialization.hpp>
|
||||||
|
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace unordered {
|
||||||
|
template <class Key, class T, class Hash, class Pred, class Allocator>
|
||||||
|
class concurrent_node_map
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
template <class Key2, class T2, class Hash2, class Pred2,
|
||||||
|
class Allocator2>
|
||||||
|
friend class concurrent_node_map;
|
||||||
|
template <class Key2, class T2, class Hash2, class Pred2,
|
||||||
|
class Allocator2>
|
||||||
|
friend class unordered_node_map;
|
||||||
|
|
||||||
|
using type_policy = detail::foa::node_map_types<Key, T,
|
||||||
|
typename boost::allocator_void_pointer<Allocator>::type>;
|
||||||
|
|
||||||
|
using table_type =
|
||||||
|
detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
|
||||||
|
|
||||||
|
table_type table_;
|
||||||
|
|
||||||
|
template <class K, class V, class H, class KE, class A>
|
||||||
|
bool friend operator==(concurrent_node_map<K, V, H, KE, A> const& lhs,
|
||||||
|
concurrent_node_map<K, V, H, KE, A> const& rhs);
|
||||||
|
|
||||||
|
template <class K, class V, class H, class KE, class A, class Predicate>
|
||||||
|
friend typename concurrent_node_map<K, V, H, KE, A>::size_type erase_if(
|
||||||
|
concurrent_node_map<K, V, H, KE, A>& set, Predicate pred);
|
||||||
|
|
||||||
|
template<class Archive, class K, class V, class H, class KE, class A>
|
||||||
|
friend void serialize(
|
||||||
|
Archive& ar, concurrent_node_map<K, V, H, KE, A>& c,
|
||||||
|
unsigned int version);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = Key;
|
||||||
|
using mapped_type = T;
|
||||||
|
using value_type = typename type_policy::value_type;
|
||||||
|
using init_type = typename type_policy::init_type;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
|
||||||
|
using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
|
||||||
|
using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_reference = value_type const&;
|
||||||
|
using pointer = typename boost::allocator_pointer<allocator_type>::type;
|
||||||
|
using const_pointer =
|
||||||
|
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||||
|
using node_type = detail::foa::node_map_handle<type_policy,
|
||||||
|
typename boost::allocator_rebind<Allocator,
|
||||||
|
typename type_policy::value_type>::type>;
|
||||||
|
using insert_return_type =
|
||||||
|
detail::foa::iteratorless_insert_return_type<node_type>;
|
||||||
|
static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
||||||
|
using stats = typename table_type::stats;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
concurrent_node_map()
|
||||||
|
: concurrent_node_map(detail::foa::default_bucket_count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit concurrent_node_map(size_type n, const hasher& hf = hasher(),
|
||||||
|
const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: table_(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
concurrent_node_map(InputIterator f, InputIterator l,
|
||||||
|
size_type n = detail::foa::default_bucket_count,
|
||||||
|
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: table_(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
this->insert(f, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(concurrent_node_map const& rhs)
|
||||||
|
: table_(rhs.table_,
|
||||||
|
boost::allocator_select_on_container_copy_construction(
|
||||||
|
rhs.get_allocator()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(concurrent_node_map&& rhs)
|
||||||
|
: table_(std::move(rhs.table_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
concurrent_node_map(
|
||||||
|
InputIterator f, InputIterator l, allocator_type const& a)
|
||||||
|
: concurrent_node_map(f, l, 0, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit concurrent_node_map(allocator_type const& a)
|
||||||
|
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(
|
||||||
|
concurrent_node_map const& rhs, allocator_type const& a)
|
||||||
|
: table_(rhs.table_, a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(concurrent_node_map&& rhs, allocator_type const& a)
|
||||||
|
: table_(std::move(rhs.table_), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(std::initializer_list<value_type> il,
|
||||||
|
size_type n = detail::foa::default_bucket_count,
|
||||||
|
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: concurrent_node_map(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
this->insert(il.begin(), il.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(size_type n, const allocator_type& a)
|
||||||
|
: concurrent_node_map(n, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(
|
||||||
|
size_type n, const hasher& hf, const allocator_type& a)
|
||||||
|
: concurrent_node_map(n, hf, key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIterator>
|
||||||
|
concurrent_node_map(
|
||||||
|
InputIterator f, InputIterator l, size_type n, const allocator_type& a)
|
||||||
|
: concurrent_node_map(f, l, n, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIterator>
|
||||||
|
concurrent_node_map(InputIterator f, InputIterator l, size_type n,
|
||||||
|
const hasher& hf, const allocator_type& a)
|
||||||
|
: concurrent_node_map(f, l, n, hf, key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(
|
||||||
|
std::initializer_list<value_type> il, const allocator_type& a)
|
||||||
|
: concurrent_node_map(
|
||||||
|
il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(std::initializer_list<value_type> il, size_type n,
|
||||||
|
const allocator_type& a)
|
||||||
|
: concurrent_node_map(il, n, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(std::initializer_list<value_type> il, size_type n,
|
||||||
|
const hasher& hf, const allocator_type& a)
|
||||||
|
: concurrent_node_map(il, n, hf, key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map(
|
||||||
|
unordered_node_map<Key, T, Hash, Pred, Allocator>&& other)
|
||||||
|
: table_(std::move(other.table_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~concurrent_node_map() = default;
|
||||||
|
|
||||||
|
concurrent_node_map& operator=(concurrent_node_map const& rhs)
|
||||||
|
{
|
||||||
|
table_ = rhs.table_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map& operator=(concurrent_node_map&& rhs) noexcept(
|
||||||
|
noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
|
||||||
|
{
|
||||||
|
table_ = std::move(rhs.table_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_map& operator=(std::initializer_list<value_type> ilist)
|
||||||
|
{
|
||||||
|
table_ = ilist;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Capacity
|
||||||
|
///
|
||||||
|
|
||||||
|
size_type size() const noexcept { return table_.size(); }
|
||||||
|
size_type max_size() const noexcept { return table_.max_size(); }
|
||||||
|
|
||||||
|
BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type visit(key_type const& k, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.visit(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
visit(K&& k, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
visit(K&& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
cvisit(K&& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FwdIterator, class F>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
size_t visit(FwdIterator first, FwdIterator last, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.visit(first, last, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FwdIterator, class F>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
size_t visit(FwdIterator first, FwdIterator last, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(first, last, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FwdIterator, class F>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
size_t cvisit(FwdIterator first, FwdIterator last, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(first, last, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> size_type visit_all(F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.visit_all(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> size_type visit_all(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit_all(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> size_type cvisit_all(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.cvisit_all(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
visit_all(ExecPolicy&& p, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.visit_all(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
visit_all(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.visit_all(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
cvisit_all(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.cvisit_all(p, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class F> bool visit_while(F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.visit_while(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> bool visit_while(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit_while(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> bool cvisit_while(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.cvisit_while(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
bool>::type
|
||||||
|
visit_while(ExecPolicy&& p, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
return table_.visit_while(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
bool>::type
|
||||||
|
visit_while(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
return table_.visit_while(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
bool>::type
|
||||||
|
cvisit_while(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
return table_.cvisit_while(p, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Modifiers
|
||||||
|
///
|
||||||
|
|
||||||
|
template <class Ty>
|
||||||
|
BOOST_FORCEINLINE auto insert(Ty&& value)
|
||||||
|
-> decltype(table_.insert(std::forward<Ty>(value)))
|
||||||
|
{
|
||||||
|
return table_.insert(std::forward<Ty>(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE bool insert(init_type&& obj)
|
||||||
|
{
|
||||||
|
return table_.insert(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
void insert(InputIterator begin, InputIterator end)
|
||||||
|
{
|
||||||
|
for (auto pos = begin; pos != end; ++pos) {
|
||||||
|
table_.emplace(*pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(std::initializer_list<value_type> ilist)
|
||||||
|
{
|
||||||
|
this->insert(ilist.begin(), ilist.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_return_type insert(node_type&& nh)
|
||||||
|
{
|
||||||
|
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(std::move(access::element(nh)))) {
|
||||||
|
access::reset(nh);
|
||||||
|
return {true, node_type{}};
|
||||||
|
} else {
|
||||||
|
return {false, std::move(nh)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class M>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_assign(key_type const& k, M&& obj)
|
||||||
|
{
|
||||||
|
return table_.try_emplace_or_visit(k, std::forward<M>(obj),
|
||||||
|
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class M>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_assign(key_type&& k, M&& obj)
|
||||||
|
{
|
||||||
|
return table_.try_emplace_or_visit(std::move(k), std::forward<M>(obj),
|
||||||
|
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class M>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||||
|
insert_or_assign(K&& k, M&& obj)
|
||||||
|
{
|
||||||
|
return table_.try_emplace_or_visit(std::forward<K>(k),
|
||||||
|
std::forward<M>(obj),
|
||||||
|
[&](value_type& m) { m.second = std::forward<M>(obj); });
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Ty, class F>
|
||||||
|
BOOST_FORCEINLINE auto insert_or_visit(Ty&& value, F f)
|
||||||
|
-> decltype(table_.insert_or_visit(std::forward<Ty>(value), f))
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.insert_or_visit(std::forward<Ty>(value), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_visit(init_type&& obj, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
return table_.insert_or_visit(std::move(obj), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator, class F>
|
||||||
|
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
table_.emplace_or_visit(*first, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
insert_return_type insert_or_visit(node_type&& nh, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||||
|
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_or_visit(std::move(access::element(nh)), f)) {
|
||||||
|
access::reset(nh);
|
||||||
|
return {true, node_type{}};
|
||||||
|
} else {
|
||||||
|
return {false, std::move(nh)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Ty, class F>
|
||||||
|
BOOST_FORCEINLINE auto insert_or_cvisit(Ty&& value, F f)
|
||||||
|
-> decltype(table_.insert_or_cvisit(std::forward<Ty>(value), f))
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.insert_or_cvisit(std::forward<Ty>(value), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_cvisit(init_type&& obj, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.insert_or_cvisit(std::move(obj), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator, class F>
|
||||||
|
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
table_.emplace_or_cvisit(*first, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
insert_return_type insert_or_cvisit(node_type&& nh, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
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_or_cvisit(std::move(access::element(nh)), f)) {
|
||||||
|
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)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.emplace_or_visit(
|
||||||
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.emplace_or_cvisit(
|
||||||
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace(key_type const& k, Args&&... args)
|
||||||
|
{
|
||||||
|
return table_.try_emplace(k, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace(key_type&& k, Args&&... args)
|
||||||
|
{
|
||||||
|
return table_.try_emplace(std::move(k), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class... Args>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||||
|
try_emplace(K&& k, Args&&... args)
|
||||||
|
{
|
||||||
|
return table_.try_emplace(
|
||||||
|
std::forward<K>(k), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace_or_visit(
|
||||||
|
key_type const& k, Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.try_emplace_or_visit(
|
||||||
|
k, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace_or_cvisit(
|
||||||
|
key_type const& k, Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.try_emplace_or_cvisit(
|
||||||
|
k, std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace_or_visit(
|
||||||
|
key_type&& k, Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.try_emplace_or_visit(
|
||||||
|
std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace_or_cvisit(
|
||||||
|
key_type&& k, Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.try_emplace_or_cvisit(
|
||||||
|
std::move(k), std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace_or_visit(
|
||||||
|
K&& k, Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.try_emplace_or_visit(std::forward<K>(k),
|
||||||
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool try_emplace_or_cvisit(
|
||||||
|
K&& k, Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.try_emplace_or_cvisit(std::forward<K>(k),
|
||||||
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||||
|
{
|
||||||
|
return table_.erase(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
erase(K&& k)
|
||||||
|
{
|
||||||
|
return table_.erase(std::forward<K>(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
|
||||||
|
{
|
||||||
|
return table_.erase_if(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value &&
|
||||||
|
!detail::is_execution_policy<K>::value,
|
||||||
|
size_type>::type
|
||||||
|
erase_if(K&& k, F f)
|
||||||
|
{
|
||||||
|
return table_.erase_if(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
erase_if(ExecPolicy&& p, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.erase_if(p, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
|
||||||
|
|
||||||
|
void swap(concurrent_node_map& other) noexcept(
|
||||||
|
boost::allocator_is_always_equal<Allocator>::type::value ||
|
||||||
|
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
|
||||||
|
{
|
||||||
|
return table_.swap(other.table_);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_type extract(key_type const& key)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract(key, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, node_type>::type
|
||||||
|
extract(K const& key)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract(key, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
node_type extract_if(key_type const& key, F f)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract_if(key, f, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, node_type>::type
|
||||||
|
extract_if(K const& key, F f)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract_if(key, f, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() noexcept { table_.clear(); }
|
||||||
|
|
||||||
|
template <typename H2, typename P2>
|
||||||
|
size_type merge(concurrent_node_map<Key, T, H2, P2, Allocator>& x)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(get_allocator() == x.get_allocator());
|
||||||
|
return table_.merge(x.table_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename H2, typename P2>
|
||||||
|
size_type merge(concurrent_node_map<Key, T, H2, P2, Allocator>&& x)
|
||||||
|
{
|
||||||
|
return merge(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE size_type count(key_type const& k) const
|
||||||
|
{
|
||||||
|
return table_.count(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
count(K const& k)
|
||||||
|
{
|
||||||
|
return table_.count(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE bool contains(key_type const& k) const
|
||||||
|
{
|
||||||
|
return table_.contains(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||||
|
contains(K const& k) const
|
||||||
|
{
|
||||||
|
return table_.contains(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hash Policy
|
||||||
|
///
|
||||||
|
size_type bucket_count() const noexcept { return table_.capacity(); }
|
||||||
|
|
||||||
|
float load_factor() const noexcept { return table_.load_factor(); }
|
||||||
|
float max_load_factor() const noexcept
|
||||||
|
{
|
||||||
|
return table_.max_load_factor();
|
||||||
|
}
|
||||||
|
void max_load_factor(float) {}
|
||||||
|
size_type max_load() const noexcept { return table_.max_load(); }
|
||||||
|
|
||||||
|
void rehash(size_type n) { table_.rehash(n); }
|
||||||
|
void reserve(size_type n) { table_.reserve(n); }
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
||||||
|
/// Stats
|
||||||
|
///
|
||||||
|
stats get_stats() const { return table_.get_stats(); }
|
||||||
|
|
||||||
|
void reset_stats() noexcept { table_.reset_stats(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Observers
|
||||||
|
///
|
||||||
|
allocator_type get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return table_.get_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
hasher hash_function() const { return table_.hash_function(); }
|
||||||
|
key_equal key_eq() const { return table_.key_eq(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator==(
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.table_ == rhs.table_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class Pred, class Alloc>
|
||||||
|
void swap(concurrent_node_map<Key, T, Hash, Pred, Alloc>& x,
|
||||||
|
concurrent_node_map<Key, T, Hash, Pred, Alloc>& y)
|
||||||
|
noexcept(noexcept(x.swap(y)))
|
||||||
|
{
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class T, class H, class P, class A, class Predicate>
|
||||||
|
typename concurrent_node_map<K, T, H, P, A>::size_type erase_if(
|
||||||
|
concurrent_node_map<K, T, H, P, A>& c, Predicate pred)
|
||||||
|
{
|
||||||
|
return c.table_.erase_if(pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive, class K, class V, class H, class KE, class A>
|
||||||
|
void serialize(
|
||||||
|
Archive& ar, concurrent_node_map<K, V, H, KE, A>& c, unsigned int)
|
||||||
|
{
|
||||||
|
ar & core::make_nvp("table",c.table_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||||
|
|
||||||
|
template <class InputIterator,
|
||||||
|
class Hash =
|
||||||
|
boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
class Pred =
|
||||||
|
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
class Allocator = std::allocator<
|
||||||
|
boost::unordered::detail::iter_to_alloc_t<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(InputIterator, InputIterator,
|
||||||
|
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||||
|
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||||
|
-> concurrent_node_map<
|
||||||
|
boost::unordered::detail::iter_key_t<InputIterator>,
|
||||||
|
boost::unordered::detail::iter_val_t<InputIterator>, Hash, Pred,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class Key, class T,
|
||||||
|
class Hash = boost::hash<std::remove_const_t<Key> >,
|
||||||
|
class Pred = std::equal_to<std::remove_const_t<Key> >,
|
||||||
|
class Allocator = std::allocator<std::pair<const Key, T> >,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(std::initializer_list<std::pair<Key, T> >,
|
||||||
|
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||||
|
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||||
|
-> concurrent_node_map<std::remove_const_t<Key>, T, Hash, Pred,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class InputIterator, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(InputIterator, InputIterator, std::size_t, Allocator)
|
||||||
|
-> concurrent_node_map<
|
||||||
|
boost::unordered::detail::iter_key_t<InputIterator>,
|
||||||
|
boost::unordered::detail::iter_val_t<InputIterator>,
|
||||||
|
boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class InputIterator, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(InputIterator, InputIterator, Allocator)
|
||||||
|
-> concurrent_node_map<
|
||||||
|
boost::unordered::detail::iter_key_t<InputIterator>,
|
||||||
|
boost::unordered::detail::iter_val_t<InputIterator>,
|
||||||
|
boost::hash<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class InputIterator, class Hash, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(
|
||||||
|
InputIterator, InputIterator, std::size_t, Hash, Allocator)
|
||||||
|
-> concurrent_node_map<
|
||||||
|
boost::unordered::detail::iter_key_t<InputIterator>,
|
||||||
|
boost::unordered::detail::iter_val_t<InputIterator>, Hash,
|
||||||
|
std::equal_to<boost::unordered::detail::iter_key_t<InputIterator> >,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class Key, class T, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
|
||||||
|
Allocator) -> concurrent_node_map<std::remove_const_t<Key>, T,
|
||||||
|
boost::hash<std::remove_const_t<Key> >,
|
||||||
|
std::equal_to<std::remove_const_t<Key> >, Allocator>;
|
||||||
|
|
||||||
|
template <class Key, class T, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(std::initializer_list<std::pair<Key, T> >, Allocator)
|
||||||
|
-> concurrent_node_map<std::remove_const_t<Key>, T,
|
||||||
|
boost::hash<std::remove_const_t<Key> >,
|
||||||
|
std::equal_to<std::remove_const_t<Key> >, Allocator>;
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
|
||||||
|
Hash, Allocator) -> concurrent_node_map<std::remove_const_t<Key>, T,
|
||||||
|
Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace unordered
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_UNORDERED_CONCURRENT_NODE_MAP_HPP
|
67
include/boost/unordered/concurrent_node_map_fwd.hpp
Normal file
67
include/boost/unordered/concurrent_node_map_fwd.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* Fast open-addressing, node-based concurrent hashmap.
|
||||||
|
*
|
||||||
|
* Copyright 2023 Christian Mazakas.
|
||||||
|
* Copyright 2024 Braden Ganetsky.
|
||||||
|
* Copyright 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)
|
||||||
|
*
|
||||||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_UNORDERED_CONCURRENT_NODE_MAP_FWD_HPP
|
||||||
|
#define BOOST_UNORDERED_CONCURRENT_NODE_MAP_FWD_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/container_hash/hash_fwd.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
|
||||||
|
#include <memory_resource>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace unordered {
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash = boost::hash<Key>,
|
||||||
|
class Pred = std::equal_to<Key>,
|
||||||
|
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||||
|
class concurrent_node_map;
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator==(
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs);
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs);
|
||||||
|
|
||||||
|
template <class Key, class T, class Hash, class Pred, class Alloc>
|
||||||
|
void swap(concurrent_node_map<Key, T, Hash, Pred, Alloc>& x,
|
||||||
|
concurrent_node_map<Key, T, Hash, Pred, Alloc>& y)
|
||||||
|
noexcept(noexcept(x.swap(y)));
|
||||||
|
|
||||||
|
template <class K, class T, class H, class P, class A, class Predicate>
|
||||||
|
typename concurrent_node_map<K, T, H, P, A>::size_type erase_if(
|
||||||
|
concurrent_node_map<K, T, H, P, A>& c, Predicate pred);
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
|
||||||
|
namespace pmr {
|
||||||
|
template <class Key, class T, class Hash = boost::hash<Key>,
|
||||||
|
class Pred = std::equal_to<Key> >
|
||||||
|
using concurrent_node_map = boost::unordered::concurrent_node_map<Key, T,
|
||||||
|
Hash, Pred, std::pmr::polymorphic_allocator<std::pair<Key const, T> > >;
|
||||||
|
} // namespace pmr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace unordered
|
||||||
|
|
||||||
|
using boost::unordered::concurrent_node_map;
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_UNORDERED_CONCURRENT_NODE_MAP_FWD_HPP
|
888
include/boost/unordered/concurrent_node_set.hpp
Normal file
888
include/boost/unordered/concurrent_node_set.hpp
Normal file
@ -0,0 +1,888 @@
|
|||||||
|
/* Fast open-addressing, node-based concurrent hashset.
|
||||||
|
*
|
||||||
|
* Copyright 2023 Christian Mazakas.
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_UNORDERED_CONCURRENT_NODE_SET_HPP
|
||||||
|
#define BOOST_UNORDERED_CONCURRENT_NODE_SET_HPP
|
||||||
|
|
||||||
|
#include <boost/unordered/concurrent_node_set_fwd.hpp>
|
||||||
|
#include <boost/unordered/detail/concurrent_static_asserts.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/concurrent_table.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/element_type.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/node_set_handle.hpp>
|
||||||
|
#include <boost/unordered/detail/foa/node_set_types.hpp>
|
||||||
|
#include <boost/unordered/detail/type_traits.hpp>
|
||||||
|
#include <boost/unordered/unordered_node_set_fwd.hpp>
|
||||||
|
|
||||||
|
#include <boost/container_hash/hash.hpp>
|
||||||
|
#include <boost/core/allocator_access.hpp>
|
||||||
|
#include <boost/core/serialization.hpp>
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace unordered {
|
||||||
|
template <class Key, class Hash, class Pred, class Allocator>
|
||||||
|
class concurrent_node_set
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
template <class Key2, class Hash2, class Pred2, class Allocator2>
|
||||||
|
friend class concurrent_node_set;
|
||||||
|
template <class Key2, class Hash2, class Pred2, class Allocator2>
|
||||||
|
friend class unordered_node_set;
|
||||||
|
|
||||||
|
using type_policy = detail::foa::node_set_types<Key,
|
||||||
|
typename boost::allocator_void_pointer<Allocator>::type>;
|
||||||
|
|
||||||
|
using table_type =
|
||||||
|
detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
|
||||||
|
|
||||||
|
table_type table_;
|
||||||
|
|
||||||
|
template <class K, class H, class KE, class A>
|
||||||
|
bool friend operator==(concurrent_node_set<K, H, KE, A> const& lhs,
|
||||||
|
concurrent_node_set<K, H, KE, A> const& rhs);
|
||||||
|
|
||||||
|
template <class K, class H, class KE, class A, class Predicate>
|
||||||
|
friend typename concurrent_node_set<K, H, KE, A>::size_type erase_if(
|
||||||
|
concurrent_node_set<K, H, KE, A>& set, Predicate pred);
|
||||||
|
|
||||||
|
template<class Archive, class K, class H, class KE, class A>
|
||||||
|
friend void serialize(
|
||||||
|
Archive& ar, concurrent_node_set<K, H, KE, A>& c,
|
||||||
|
unsigned int version);
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = Key;
|
||||||
|
using value_type = typename type_policy::value_type;
|
||||||
|
using init_type = typename type_policy::init_type;
|
||||||
|
using size_type = std::size_t;
|
||||||
|
using difference_type = std::ptrdiff_t;
|
||||||
|
using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
|
||||||
|
using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
|
||||||
|
using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
|
||||||
|
using reference = value_type&;
|
||||||
|
using const_reference = value_type const&;
|
||||||
|
using pointer = typename boost::allocator_pointer<allocator_type>::type;
|
||||||
|
using const_pointer =
|
||||||
|
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||||
|
using node_type = detail::foa::node_set_handle<type_policy,
|
||||||
|
typename boost::allocator_rebind<Allocator,
|
||||||
|
typename type_policy::value_type>::type>;
|
||||||
|
using insert_return_type =
|
||||||
|
detail::foa::iteratorless_insert_return_type<node_type>;
|
||||||
|
static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
||||||
|
using stats = typename table_type::stats;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
concurrent_node_set()
|
||||||
|
: concurrent_node_set(detail::foa::default_bucket_count)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit concurrent_node_set(size_type n, const hasher& hf = hasher(),
|
||||||
|
const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: table_(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
concurrent_node_set(InputIterator f, InputIterator l,
|
||||||
|
size_type n = detail::foa::default_bucket_count,
|
||||||
|
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: table_(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
this->insert(f, l);
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(concurrent_node_set const& rhs)
|
||||||
|
: table_(rhs.table_,
|
||||||
|
boost::allocator_select_on_container_copy_construction(
|
||||||
|
rhs.get_allocator()))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(concurrent_node_set&& rhs)
|
||||||
|
: table_(std::move(rhs.table_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
concurrent_node_set(
|
||||||
|
InputIterator f, InputIterator l, allocator_type const& a)
|
||||||
|
: concurrent_node_set(f, l, 0, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
explicit concurrent_node_set(allocator_type const& a)
|
||||||
|
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(
|
||||||
|
concurrent_node_set const& rhs, allocator_type const& a)
|
||||||
|
: table_(rhs.table_, a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(concurrent_node_set&& rhs, allocator_type const& a)
|
||||||
|
: table_(std::move(rhs.table_), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(std::initializer_list<value_type> il,
|
||||||
|
size_type n = detail::foa::default_bucket_count,
|
||||||
|
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||||
|
const allocator_type& a = allocator_type())
|
||||||
|
: concurrent_node_set(n, hf, eql, a)
|
||||||
|
{
|
||||||
|
this->insert(il.begin(), il.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(size_type n, const allocator_type& a)
|
||||||
|
: concurrent_node_set(n, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(
|
||||||
|
size_type n, const hasher& hf, const allocator_type& a)
|
||||||
|
: concurrent_node_set(n, hf, key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIterator>
|
||||||
|
concurrent_node_set(
|
||||||
|
InputIterator f, InputIterator l, size_type n, const allocator_type& a)
|
||||||
|
: concurrent_node_set(f, l, n, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename InputIterator>
|
||||||
|
concurrent_node_set(InputIterator f, InputIterator l, size_type n,
|
||||||
|
const hasher& hf, const allocator_type& a)
|
||||||
|
: concurrent_node_set(f, l, n, hf, key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(
|
||||||
|
std::initializer_list<value_type> il, const allocator_type& a)
|
||||||
|
: concurrent_node_set(
|
||||||
|
il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(std::initializer_list<value_type> il, size_type n,
|
||||||
|
const allocator_type& a)
|
||||||
|
: concurrent_node_set(il, n, hasher(), key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(std::initializer_list<value_type> il, size_type n,
|
||||||
|
const hasher& hf, const allocator_type& a)
|
||||||
|
: concurrent_node_set(il, n, hf, key_equal(), a)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set(
|
||||||
|
unordered_node_set<Key, Hash, Pred, Allocator>&& other)
|
||||||
|
: table_(std::move(other.table_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
~concurrent_node_set() = default;
|
||||||
|
|
||||||
|
concurrent_node_set& operator=(concurrent_node_set const& rhs)
|
||||||
|
{
|
||||||
|
table_ = rhs.table_;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set& operator=(concurrent_node_set&& rhs)
|
||||||
|
noexcept(boost::allocator_is_always_equal<Allocator>::type::value ||
|
||||||
|
boost::allocator_propagate_on_container_move_assignment<
|
||||||
|
Allocator>::type::value)
|
||||||
|
{
|
||||||
|
table_ = std::move(rhs.table_);
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
concurrent_node_set& operator=(std::initializer_list<value_type> ilist)
|
||||||
|
{
|
||||||
|
table_ = ilist;
|
||||||
|
return *this;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Capacity
|
||||||
|
///
|
||||||
|
|
||||||
|
size_type size() const noexcept { return table_.size(); }
|
||||||
|
size_type max_size() const noexcept { return table_.max_size(); }
|
||||||
|
|
||||||
|
BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
|
||||||
|
{
|
||||||
|
return size() == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type visit(key_type const& k, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
visit(K&& k, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
visit(K&& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
cvisit(K&& k, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FwdIterator, class F>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
size_t visit(FwdIterator first, FwdIterator last, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(first, last, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FwdIterator, class F>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
size_t visit(FwdIterator first, FwdIterator last, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(first, last, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class FwdIterator, class F>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
size_t cvisit(FwdIterator first, FwdIterator last, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit(first, last, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> size_type visit_all(F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit_all(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> size_type visit_all(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit_all(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> size_type cvisit_all(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.cvisit_all(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
visit_all(ExecPolicy&& p, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.visit_all(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
visit_all(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.visit_all(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
cvisit_all(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.cvisit_all(p, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class F> bool visit_while(F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit_while(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> bool visit_while(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.visit_while(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F> bool cvisit_while(F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.cvisit_while(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
bool>::type
|
||||||
|
visit_while(ExecPolicy&& p, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
return table_.visit_while(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
bool>::type
|
||||||
|
visit_while(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
return table_.visit_while(p, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
bool>::type
|
||||||
|
cvisit_while(ExecPolicy&& p, F f) const
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
return table_.cvisit_while(p, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Modifiers
|
||||||
|
///
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE bool insert(value_type const& obj)
|
||||||
|
{
|
||||||
|
return table_.insert(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE bool insert(value_type&& obj)
|
||||||
|
{
|
||||||
|
return table_.insert(std::move(obj));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value,
|
||||||
|
bool >::type
|
||||||
|
insert(K&& k)
|
||||||
|
{
|
||||||
|
return table_.try_emplace(std::forward<K>(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator>
|
||||||
|
void insert(InputIterator begin, InputIterator end)
|
||||||
|
{
|
||||||
|
for (auto pos = begin; pos != end; ++pos) {
|
||||||
|
table_.emplace(*pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void insert(std::initializer_list<value_type> ilist)
|
||||||
|
{
|
||||||
|
this->insert(ilist.begin(), ilist.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
insert_return_type insert(node_type&& nh)
|
||||||
|
{
|
||||||
|
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(std::move(access::element(nh)))) {
|
||||||
|
access::reset(nh);
|
||||||
|
return {true, node_type{}};
|
||||||
|
} else {
|
||||||
|
return {false, std::move(nh)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_visit(value_type const& obj, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.insert_or_visit(obj, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_visit(value_type&& obj, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.insert_or_visit(std::move(obj), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value,
|
||||||
|
bool >::type
|
||||||
|
insert_or_visit(K&& k, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.try_emplace_or_visit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator, class F>
|
||||||
|
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
table_.emplace_or_visit(*first, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
insert_return_type insert_or_visit(node_type&& nh, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
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_or_visit(std::move(access::element(nh)), f)) {
|
||||||
|
access::reset(nh);
|
||||||
|
return {true, node_type{}};
|
||||||
|
} else {
|
||||||
|
return {false, std::move(nh)};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_cvisit(value_type const& obj, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.insert_or_cvisit(obj, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE bool insert_or_cvisit(value_type&& obj, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.insert_or_cvisit(std::move(obj), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value,
|
||||||
|
bool >::type
|
||||||
|
insert_or_cvisit(K&& k, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class InputIterator, class F>
|
||||||
|
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
for (; first != last; ++first) {
|
||||||
|
table_.emplace_or_cvisit(*first, f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
insert_return_type insert_or_cvisit(node_type&& nh, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||||
|
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_or_cvisit(std::move(access::element(nh)), f)) {
|
||||||
|
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)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.emplace_or_visit(
|
||||||
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Arg, class... Args>
|
||||||
|
BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||||
|
return table_.emplace_or_cvisit(
|
||||||
|
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||||
|
{
|
||||||
|
return table_.erase(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
erase(K&& k)
|
||||||
|
{
|
||||||
|
return table_.erase(std::forward<K>(k));
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
|
||||||
|
{
|
||||||
|
return table_.erase_if(k, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value &&
|
||||||
|
!detail::is_execution_policy<K>::value,
|
||||||
|
size_type>::type
|
||||||
|
erase_if(K&& k, F f)
|
||||||
|
{
|
||||||
|
return table_.erase_if(std::forward<K>(k), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||||
|
template <class ExecPolicy, class F>
|
||||||
|
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||||
|
void>::type
|
||||||
|
erase_if(ExecPolicy&& p, F f)
|
||||||
|
{
|
||||||
|
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||||
|
table_.erase_if(p, f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
|
||||||
|
|
||||||
|
void swap(concurrent_node_set& other) noexcept(
|
||||||
|
boost::allocator_is_always_equal<Allocator>::type::value ||
|
||||||
|
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
|
||||||
|
{
|
||||||
|
return table_.swap(other.table_);
|
||||||
|
}
|
||||||
|
|
||||||
|
node_type extract(key_type const& key)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract(key, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, node_type>::type
|
||||||
|
extract(K const& key)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract(key, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class F>
|
||||||
|
node_type extract_if(key_type const& key, F f)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract_if(key, f, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class F>
|
||||||
|
typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, node_type>::type
|
||||||
|
extract_if(K const& key, F f)
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
table_.extract_if(key, f, detail::foa::node_handle_emplacer(nh));
|
||||||
|
return nh;
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear() noexcept { table_.clear(); }
|
||||||
|
|
||||||
|
template <typename H2, typename P2>
|
||||||
|
size_type merge(concurrent_node_set<Key, H2, P2, Allocator>& x)
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(get_allocator() == x.get_allocator());
|
||||||
|
return table_.merge(x.table_);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename H2, typename P2>
|
||||||
|
size_type merge(concurrent_node_set<Key, H2, P2, Allocator>&& x)
|
||||||
|
{
|
||||||
|
return merge(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE size_type count(key_type const& k) const
|
||||||
|
{
|
||||||
|
return table_.count(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||||
|
count(K const& k)
|
||||||
|
{
|
||||||
|
return table_.count(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOST_FORCEINLINE bool contains(key_type const& k) const
|
||||||
|
{
|
||||||
|
return table_.contains(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K>
|
||||||
|
BOOST_FORCEINLINE typename std::enable_if<
|
||||||
|
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||||
|
contains(K const& k) const
|
||||||
|
{
|
||||||
|
return table_.contains(k);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Hash Policy
|
||||||
|
///
|
||||||
|
size_type bucket_count() const noexcept { return table_.capacity(); }
|
||||||
|
|
||||||
|
float load_factor() const noexcept { return table_.load_factor(); }
|
||||||
|
float max_load_factor() const noexcept
|
||||||
|
{
|
||||||
|
return table_.max_load_factor();
|
||||||
|
}
|
||||||
|
void max_load_factor(float) {}
|
||||||
|
size_type max_load() const noexcept { return table_.max_load(); }
|
||||||
|
|
||||||
|
void rehash(size_type n) { table_.rehash(n); }
|
||||||
|
void reserve(size_type n) { table_.reserve(n); }
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_ENABLE_STATS)
|
||||||
|
/// Stats
|
||||||
|
///
|
||||||
|
stats get_stats() const { return table_.get_stats(); }
|
||||||
|
|
||||||
|
void reset_stats() noexcept { table_.reset_stats(); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/// Observers
|
||||||
|
///
|
||||||
|
allocator_type get_allocator() const noexcept
|
||||||
|
{
|
||||||
|
return table_.get_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
|
hasher hash_function() const { return table_.hash_function(); }
|
||||||
|
key_equal key_eq() const { return table_.key_eq(); }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator==(
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||||
|
{
|
||||||
|
return lhs.table_ == rhs.table_;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||||
|
{
|
||||||
|
return !(lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Key, class Hash, class Pred, class Alloc>
|
||||||
|
void swap(concurrent_node_set<Key, Hash, Pred, Alloc>& x,
|
||||||
|
concurrent_node_set<Key, Hash, Pred, Alloc>& y)
|
||||||
|
noexcept(noexcept(x.swap(y)))
|
||||||
|
{
|
||||||
|
x.swap(y);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class K, class H, class P, class A, class Predicate>
|
||||||
|
typename concurrent_node_set<K, H, P, A>::size_type erase_if(
|
||||||
|
concurrent_node_set<K, H, P, A>& c, Predicate pred)
|
||||||
|
{
|
||||||
|
return c.table_.erase_if(pred);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<class Archive, class K, class H, class KE, class A>
|
||||||
|
void serialize(
|
||||||
|
Archive& ar, concurrent_node_set<K, H, KE, A>& c, unsigned int)
|
||||||
|
{
|
||||||
|
ar & core::make_nvp("table",c.table_);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||||
|
|
||||||
|
template <class InputIterator,
|
||||||
|
class Hash =
|
||||||
|
boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
class Pred =
|
||||||
|
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
class Allocator = std::allocator<
|
||||||
|
typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(InputIterator, InputIterator,
|
||||||
|
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||||
|
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||||
|
-> concurrent_node_set<
|
||||||
|
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class T, class Hash = boost::hash<T>,
|
||||||
|
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(std::initializer_list<T>,
|
||||||
|
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||||
|
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||||
|
-> concurrent_node_set< T, Hash, Pred, Allocator>;
|
||||||
|
|
||||||
|
template <class InputIterator, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(InputIterator, InputIterator, std::size_t, Allocator)
|
||||||
|
-> concurrent_node_set<
|
||||||
|
typename std::iterator_traits<InputIterator>::value_type,
|
||||||
|
boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class InputIterator, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(InputIterator, InputIterator, Allocator)
|
||||||
|
-> concurrent_node_set<
|
||||||
|
typename std::iterator_traits<InputIterator>::value_type,
|
||||||
|
boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class InputIterator, class Hash, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(
|
||||||
|
InputIterator, InputIterator, std::size_t, Hash, Allocator)
|
||||||
|
-> concurrent_node_set<
|
||||||
|
typename std::iterator_traits<InputIterator>::value_type, Hash,
|
||||||
|
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
|
||||||
|
Allocator>;
|
||||||
|
|
||||||
|
template <class T, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(std::initializer_list<T>, std::size_t, Allocator)
|
||||||
|
-> concurrent_node_set<T, boost::hash<T>,std::equal_to<T>, Allocator>;
|
||||||
|
|
||||||
|
template <class T, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(std::initializer_list<T >, Allocator)
|
||||||
|
-> concurrent_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||||
|
|
||||||
|
template <class T, class Hash, class Allocator,
|
||||||
|
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||||
|
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||||
|
concurrent_node_set(std::initializer_list<T >, std::size_t,Hash, Allocator)
|
||||||
|
-> concurrent_node_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace unordered
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_UNORDERED_CONCURRENT_NODE_SET_HPP
|
67
include/boost/unordered/concurrent_node_set_fwd.hpp
Normal file
67
include/boost/unordered/concurrent_node_set_fwd.hpp
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
/* Fast open-addressing, node-based concurrent hashset.
|
||||||
|
*
|
||||||
|
* Copyright 2023 Christian Mazakas.
|
||||||
|
* Copyright 2023-2024 Joaquin M Lopez Munoz.
|
||||||
|
* Copyright 2024 Braden Ganetsky.
|
||||||
|
* 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)
|
||||||
|
*
|
||||||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_UNORDERED_CONCURRENT_NODE_SET_FWD_HPP
|
||||||
|
#define BOOST_UNORDERED_CONCURRENT_NODE_SET_FWD_HPP
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/container_hash/hash_fwd.hpp>
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
|
||||||
|
#include <memory_resource>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
namespace unordered {
|
||||||
|
|
||||||
|
template <class Key, class Hash = boost::hash<Key>,
|
||||||
|
class Pred = std::equal_to<Key>,
|
||||||
|
class Allocator = std::allocator<Key> >
|
||||||
|
class concurrent_node_set;
|
||||||
|
|
||||||
|
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator==(
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& rhs);
|
||||||
|
|
||||||
|
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||||
|
bool operator!=(
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator> const& rhs);
|
||||||
|
|
||||||
|
template <class Key, class Hash, class Pred, class Alloc>
|
||||||
|
void swap(concurrent_node_set<Key, Hash, Pred, Alloc>& x,
|
||||||
|
concurrent_node_set<Key, Hash, Pred, Alloc>& y)
|
||||||
|
noexcept(noexcept(x.swap(y)));
|
||||||
|
|
||||||
|
template <class K, class H, class P, class A, class Predicate>
|
||||||
|
typename concurrent_node_set<K, H, P, A>::size_type erase_if(
|
||||||
|
concurrent_node_set<K, H, P, A>& c, Predicate pred);
|
||||||
|
|
||||||
|
#ifndef BOOST_NO_CXX17_HDR_MEMORY_RESOURCE
|
||||||
|
namespace pmr {
|
||||||
|
template <class Key, class Hash = boost::hash<Key>,
|
||||||
|
class Pred = std::equal_to<Key> >
|
||||||
|
using concurrent_node_set = boost::unordered::concurrent_node_set<Key,
|
||||||
|
Hash, Pred, std::pmr::polymorphic_allocator<Key> >;
|
||||||
|
} // namespace pmr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace unordered
|
||||||
|
|
||||||
|
using boost::unordered::concurrent_node_set;
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
|
#endif // BOOST_UNORDERED_CONCURRENT_NODE_SET_FWD_HPP
|
@ -397,10 +397,10 @@ inline void swap(atomic_size_control& x,atomic_size_control& y)
|
|||||||
* - Parallel versions of [c]visit_all(f) and erase_if(f) are provided based
|
* - Parallel versions of [c]visit_all(f) and erase_if(f) are provided based
|
||||||
* on C++17 stdlib parallel algorithms.
|
* on C++17 stdlib parallel algorithms.
|
||||||
*
|
*
|
||||||
* Consult boost::concurrent_flat_(map|set) docs for the full API reference.
|
* Consult boost::concurrent_(flat|node)_(map|set) docs for the full API
|
||||||
* Heterogeneous lookup is suported by default, that is, without checking for
|
* reference. Heterogeneous lookup is suported by default, that is, without
|
||||||
* any ::is_transparent typedefs --this checking is done by the wrapping
|
* checking for any ::is_transparent typedefs --this checking is done by the
|
||||||
* containers.
|
* wrapping containers.
|
||||||
*
|
*
|
||||||
* Thread-safe concurrency is implemented using a two-level lock system:
|
* Thread-safe concurrency is implemented using a two-level lock system:
|
||||||
*
|
*
|
||||||
@ -724,6 +724,14 @@ public:
|
|||||||
BOOST_FORCEINLINE bool
|
BOOST_FORCEINLINE bool
|
||||||
insert(value_type&& x){return emplace_impl(std::move(x));}
|
insert(value_type&& x){return emplace_impl(std::move(x));}
|
||||||
|
|
||||||
|
template<typename T=element_type>
|
||||||
|
BOOST_FORCEINLINE
|
||||||
|
typename std::enable_if<
|
||||||
|
!std::is_same<T,value_type>::value,
|
||||||
|
bool
|
||||||
|
>::type
|
||||||
|
insert(element_type&& x){return emplace_impl(std::move(x));}
|
||||||
|
|
||||||
template<typename Key,typename... Args>
|
template<typename Key,typename... Args>
|
||||||
BOOST_FORCEINLINE bool try_emplace(Key&& x,Args&&... args)
|
BOOST_FORCEINLINE bool try_emplace(Key&& x,Args&&... args)
|
||||||
{
|
{
|
||||||
@ -819,6 +827,30 @@ public:
|
|||||||
group_shared{},std::forward<F>(f),std::move(x));
|
group_shared{},std::forward<F>(f),std::move(x));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename F,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)
|
||||||
|
{
|
||||||
|
return emplace_or_visit_impl(
|
||||||
|
group_exclusive{},std::forward<F>(f),std::move(x));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename F,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)
|
||||||
|
{
|
||||||
|
return emplace_or_visit_impl(
|
||||||
|
group_shared{},std::forward<F>(f),std::move(x));
|
||||||
|
}
|
||||||
|
|
||||||
template<typename Key>
|
template<typename Key>
|
||||||
BOOST_FORCEINLINE std::size_t erase(const Key& x)
|
BOOST_FORCEINLINE std::size_t erase(const Key& x)
|
||||||
{
|
{
|
||||||
@ -889,6 +921,29 @@ public:
|
|||||||
super::clear();
|
super::clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename Key,typename Extractor>
|
||||||
|
BOOST_FORCEINLINE void extract(const Key& x,Extractor&& ext)
|
||||||
|
{
|
||||||
|
extract_if(
|
||||||
|
x,[](const value_type&){return true;},std::forward<Extractor>(ext));
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename Key,typename F,typename Extractor>
|
||||||
|
BOOST_FORCEINLINE void extract_if(const Key& x,F&& f,Extractor&& ext)
|
||||||
|
{
|
||||||
|
auto lck=shared_access();
|
||||||
|
auto hash=this->hash_for(x);
|
||||||
|
unprotected_internal_visit(
|
||||||
|
group_exclusive{},x,this->position_for(hash),hash,
|
||||||
|
[&,this](group_type* pg,unsigned int n,element_type* p)
|
||||||
|
{
|
||||||
|
if(f(cast_for(group_exclusive{},type_policy::value_from(*p)))){
|
||||||
|
ext(std::move(*p),this->al());
|
||||||
|
super::erase(pg,n,p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: should we accept different allocator too?
|
// TODO: should we accept different allocator too?
|
||||||
template<typename Hash2,typename Pred2>
|
template<typename Hash2,typename Pred2>
|
||||||
size_type merge(concurrent_table<TypePolicy,Hash2,Pred2,Allocator>& x)
|
size_type merge(concurrent_table<TypePolicy,Hash2,Pred2,Allocator>& x)
|
||||||
@ -1733,7 +1788,8 @@ private:
|
|||||||
|
|
||||||
if(this->find(x,pos0,hash))throw_exception(bad_archive_exception());
|
if(this->find(x,pos0,hash))throw_exception(bad_archive_exception());
|
||||||
auto loc=this->unchecked_emplace_at(pos0,hash,std::move(x));
|
auto loc=this->unchecked_emplace_at(pos0,hash,std::move(x));
|
||||||
ar.reset_object_address(std::addressof(*loc.p),std::addressof(x));
|
ar.reset_object_address(
|
||||||
|
std::addressof(type_policy::value_from(*loc.p)),std::addressof(x));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1742,7 +1798,7 @@ private:
|
|||||||
{
|
{
|
||||||
using raw_key_type=typename std::remove_const<key_type>::type;
|
using raw_key_type=typename std::remove_const<key_type>::type;
|
||||||
using raw_mapped_type=typename std::remove_const<
|
using raw_mapped_type=typename std::remove_const<
|
||||||
typename TypePolicy::mapped_type>::type;
|
typename type_policy::mapped_type>::type;
|
||||||
|
|
||||||
auto lck=exclusive_access();
|
auto lck=exclusive_access();
|
||||||
std::size_t s;
|
std::size_t s;
|
||||||
@ -1766,8 +1822,12 @@ private:
|
|||||||
|
|
||||||
if(this->find(k,pos0,hash))throw_exception(bad_archive_exception());
|
if(this->find(k,pos0,hash))throw_exception(bad_archive_exception());
|
||||||
auto loc=this->unchecked_emplace_at(pos0,hash,std::move(k),std::move(m));
|
auto loc=this->unchecked_emplace_at(pos0,hash,std::move(k),std::move(m));
|
||||||
ar.reset_object_address(std::addressof(loc.p->first),std::addressof(k));
|
ar.reset_object_address(
|
||||||
ar.reset_object_address(std::addressof(loc.p->second),std::addressof(m));
|
std::addressof(type_policy::value_from(*loc.p).first),
|
||||||
|
std::addressof(k));
|
||||||
|
ar.reset_object_address(
|
||||||
|
std::addressof(type_policy::value_from(*loc.p).second),
|
||||||
|
std::addressof(m));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1459,6 +1459,11 @@ public:
|
|||||||
using stats=table_core_stats;
|
using stats=table_core_stats;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_GCC)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
#endif
|
||||||
|
|
||||||
table_core(
|
table_core(
|
||||||
std::size_t n=default_bucket_count,const Hash& h_=Hash(),
|
std::size_t n=default_bucket_count,const Hash& h_=Hash(),
|
||||||
const Pred& pred_=Pred(),const Allocator& al_=Allocator()):
|
const Pred& pred_=Pred(),const Allocator& al_=Allocator()):
|
||||||
@ -1467,6 +1472,10 @@ public:
|
|||||||
size_ctrl{initial_max_load(),0}
|
size_ctrl{initial_max_load(),0}
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
#if defined(BOOST_GCC)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
/* genericize on an ArraysFn so that we can do things like delay an
|
/* genericize on an ArraysFn so that we can do things like delay an
|
||||||
* allocation for the group_access data required by cfoa after the move
|
* allocation for the group_access data required by cfoa after the move
|
||||||
* constructors of Hash, Pred have been invoked
|
* constructors of Hash, Pred have been invoked
|
||||||
@ -2081,6 +2090,11 @@ private:
|
|||||||
using pred_base=empty_value<Pred,1>;
|
using pred_base=empty_value<Pred,1>;
|
||||||
using allocator_base=empty_value<Allocator,2>;
|
using allocator_base=empty_value<Allocator,2>;
|
||||||
|
|
||||||
|
#if defined(BOOST_GCC)
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
#endif
|
||||||
|
|
||||||
/* used by allocator-extended move ctor */
|
/* used by allocator-extended move ctor */
|
||||||
|
|
||||||
table_core(Hash&& h_,Pred&& pred_,const Allocator& al_):
|
table_core(Hash&& h_,Pred&& pred_,const Allocator& al_):
|
||||||
@ -2091,6 +2105,10 @@ private:
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(BOOST_GCC)
|
||||||
|
#pragma GCC diagnostic pop
|
||||||
|
#endif
|
||||||
|
|
||||||
arrays_type new_arrays(std::size_t n)const
|
arrays_type new_arrays(std::size_t n)const
|
||||||
{
|
{
|
||||||
return arrays_type::new_(typename arrays_type::allocator_type(al()),n);
|
return arrays_type::new_(typename arrays_type::allocator_type(al()),n);
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
/* Copyright 2023 Christian Mazakas.
|
/* Copyright 2023 Christian Mazakas.
|
||||||
|
* Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
* Distributed under the Boost Software License, Version 1.0.
|
* Distributed under the Boost Software License, Version 1.0.
|
||||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||||
* http://www.boost.org/LICENSE_1_0.txt)
|
* http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@ -11,8 +12,11 @@
|
|||||||
|
|
||||||
#include <boost/unordered/detail/opt_storage.hpp>
|
#include <boost/unordered/detail/opt_storage.hpp>
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
|
#include <boost/config/workaround.hpp>
|
||||||
#include <boost/core/allocator_access.hpp>
|
#include <boost/core/allocator_access.hpp>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
namespace boost{
|
namespace boost{
|
||||||
namespace unordered{
|
namespace unordered{
|
||||||
@ -27,6 +31,13 @@ struct insert_return_type
|
|||||||
NodeType node;
|
NodeType node;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <class NodeType>
|
||||||
|
struct iteratorless_insert_return_type
|
||||||
|
{
|
||||||
|
bool inserted;
|
||||||
|
NodeType node;
|
||||||
|
};
|
||||||
|
|
||||||
template <class TypePolicy,class Allocator>
|
template <class TypePolicy,class Allocator>
|
||||||
struct node_handle_base
|
struct node_handle_base
|
||||||
{
|
{
|
||||||
@ -42,7 +53,27 @@ struct node_handle_base
|
|||||||
element_type p_;
|
element_type p_;
|
||||||
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
|
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
|
||||||
|
|
||||||
protected:
|
friend struct node_handle_access;
|
||||||
|
|
||||||
|
template<bool B>
|
||||||
|
void move_assign_allocator_if(node_handle_base&& nh)noexcept
|
||||||
|
{
|
||||||
|
move_assign_allocator_if(
|
||||||
|
std::integral_constant<bool,B>{}, std::move(nh));
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_assign_allocator_if(
|
||||||
|
std::true_type, node_handle_base&& nh)noexcept
|
||||||
|
{
|
||||||
|
al()=std::move(nh.al());
|
||||||
|
}
|
||||||
|
|
||||||
|
void move_assign_allocator_if(
|
||||||
|
std::false_type, node_handle_base&&)noexcept
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
node_value_type& data()noexcept
|
node_value_type& data()noexcept
|
||||||
{
|
{
|
||||||
return *(p_.p);
|
return *(p_.p);
|
||||||
@ -126,9 +157,7 @@ struct node_handle_base
|
|||||||
BOOST_ASSERT(pocma||al()==nh.al());
|
BOOST_ASSERT(pocma||al()==nh.al());
|
||||||
|
|
||||||
type_policy::destroy(al(),&p_);
|
type_policy::destroy(al(),&p_);
|
||||||
if(pocma){
|
move_assign_allocator_if<pocma>(std::move(nh));
|
||||||
al()=std::move(nh.al());
|
|
||||||
}
|
|
||||||
|
|
||||||
p_=std::move(nh.p_);
|
p_=std::move(nh.p_);
|
||||||
nh.reset();
|
nh.reset();
|
||||||
@ -153,7 +182,17 @@ struct node_handle_base
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allocator_type get_allocator()const noexcept{return al();}
|
allocator_type get_allocator()const
|
||||||
|
{
|
||||||
|
#if defined(BOOST_GCC)
|
||||||
|
/* GCC lifetime analysis incorrectly warns about uninitialized
|
||||||
|
* allocator object under some circumstances.
|
||||||
|
*/
|
||||||
|
if(empty())__builtin_unreachable();
|
||||||
|
#endif
|
||||||
|
return al();
|
||||||
|
}
|
||||||
|
|
||||||
explicit operator bool()const noexcept{ return !empty();}
|
explicit operator bool()const noexcept{ return !empty();}
|
||||||
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_.p==nullptr;}
|
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_.p==nullptr;}
|
||||||
|
|
||||||
@ -196,6 +235,82 @@ struct node_handle_base
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Internal usage of node_handle_base protected API
|
||||||
|
|
||||||
|
struct node_handle_access
|
||||||
|
{
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
using node_type = node_handle_base<TypePolicy, Allocator>;
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_CLANG_VERSION,<190000)
|
||||||
|
// https://github.com/llvm/llvm-project/issues/25708
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
struct element_type_impl
|
||||||
|
{
|
||||||
|
using type = typename node_type<TypePolicy, Allocator>::element_type;
|
||||||
|
};
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
using element_type = typename element_type_impl<TypePolicy, Allocator>::type;
|
||||||
|
#else
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
using element_type = typename node_type<TypePolicy, Allocator>::element_type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
static element_type<TypePolicy, Allocator>&
|
||||||
|
element(node_type<TypePolicy, Allocator>& nh)noexcept
|
||||||
|
{
|
||||||
|
return nh.element();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
static element_type<TypePolicy, Allocator>
|
||||||
|
const& element(node_type<TypePolicy, Allocator> const& nh)noexcept
|
||||||
|
{
|
||||||
|
return nh.element();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
static void emplace(
|
||||||
|
node_type<TypePolicy, Allocator>& nh,
|
||||||
|
element_type<TypePolicy, Allocator>&& x, Allocator a)
|
||||||
|
{
|
||||||
|
nh.emplace(std::move(x), a);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class TypePolicy,class Allocator>
|
||||||
|
static void reset(node_type<TypePolicy, Allocator>& nh)
|
||||||
|
{
|
||||||
|
nh.reset();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
class node_handle_emplacer_class
|
||||||
|
{
|
||||||
|
using access = node_handle_access;
|
||||||
|
using node_type = access::node_type<TypePolicy, Allocator>;
|
||||||
|
using element_type = access::element_type<TypePolicy, Allocator>;
|
||||||
|
|
||||||
|
node_type & nh;
|
||||||
|
|
||||||
|
public:
|
||||||
|
node_handle_emplacer_class(node_type& nh_): nh(nh_) {}
|
||||||
|
|
||||||
|
void operator()(element_type&& x,Allocator a)
|
||||||
|
{
|
||||||
|
access::emplace(nh, std::move(x), a);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
node_handle_emplacer_class<TypePolicy, Allocator>
|
||||||
|
node_handle_emplacer(node_handle_base<TypePolicy, Allocator>& nh)
|
||||||
|
{
|
||||||
|
return {nh};
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
56
include/boost/unordered/detail/foa/node_map_handle.hpp
Normal file
56
include/boost/unordered/detail/foa/node_map_handle.hpp
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
/* Copyright 2023 Christian Mazakas.
|
||||||
|
* Copyright 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)
|
||||||
|
*
|
||||||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_HANDLE_HPP
|
||||||
|
#define BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_HANDLE_HPP
|
||||||
|
|
||||||
|
#include <boost/unordered/detail/foa/node_handle.hpp>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
namespace unordered{
|
||||||
|
namespace detail{
|
||||||
|
namespace foa{
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
struct node_map_handle
|
||||||
|
: public node_handle_base<TypePolicy, Allocator>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using base_type = node_handle_base<TypePolicy, Allocator>;
|
||||||
|
|
||||||
|
using typename base_type::type_policy;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using key_type = typename TypePolicy::key_type;
|
||||||
|
using mapped_type = typename TypePolicy::mapped_type;
|
||||||
|
|
||||||
|
constexpr node_map_handle() noexcept = default;
|
||||||
|
node_map_handle(node_map_handle&& nh) noexcept = default;
|
||||||
|
|
||||||
|
node_map_handle& operator=(node_map_handle&&) noexcept = default;
|
||||||
|
|
||||||
|
key_type& key() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!this->empty());
|
||||||
|
return const_cast<key_type&>(this->data().first);
|
||||||
|
}
|
||||||
|
|
||||||
|
mapped_type& mapped() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!this->empty());
|
||||||
|
return const_cast<mapped_type&>(this->data().second);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_MAP_HANDLE_HPP
|
48
include/boost/unordered/detail/foa/node_set_handle.hpp
Normal file
48
include/boost/unordered/detail/foa/node_set_handle.hpp
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
/* Copyright 2023 Christian Mazakas.
|
||||||
|
* Copyright 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)
|
||||||
|
*
|
||||||
|
* See https://www.boost.org/libs/unordered for library home page.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BOOST_UNORDERED_DETAIL_FOA_NODE_SET_HANDLE_HPP
|
||||||
|
#define BOOST_UNORDERED_DETAIL_FOA_NODE_SET_HANDLE_HPP
|
||||||
|
|
||||||
|
#include <boost/unordered/detail/foa/node_handle.hpp>
|
||||||
|
|
||||||
|
namespace boost{
|
||||||
|
namespace unordered{
|
||||||
|
namespace detail{
|
||||||
|
namespace foa{
|
||||||
|
|
||||||
|
template <class TypePolicy, class Allocator>
|
||||||
|
struct node_set_handle
|
||||||
|
: public detail::foa::node_handle_base<TypePolicy, Allocator>
|
||||||
|
{
|
||||||
|
private:
|
||||||
|
using base_type = detail::foa::node_handle_base<TypePolicy, Allocator>;
|
||||||
|
|
||||||
|
using typename base_type::type_policy;
|
||||||
|
|
||||||
|
public:
|
||||||
|
using value_type = typename TypePolicy::value_type;
|
||||||
|
|
||||||
|
constexpr node_set_handle() noexcept = default;
|
||||||
|
node_set_handle(node_set_handle&& nh) noexcept = default;
|
||||||
|
node_set_handle& operator=(node_set_handle&&) noexcept = default;
|
||||||
|
|
||||||
|
value_type& value() const
|
||||||
|
{
|
||||||
|
BOOST_ASSERT(!this->empty());
|
||||||
|
return const_cast<value_type&>(this->data());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_SET_HANDLE_HPP
|
@ -1,4 +1,5 @@
|
|||||||
// Copyright (C) 2022-2023 Christian Mazakas
|
// Copyright (C) 2022-2023 Christian Mazakas
|
||||||
|
// Copyright (C) 2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -10,8 +11,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <boost/unordered/detail/foa/element_type.hpp>
|
#include <boost/unordered/concurrent_node_map_fwd.hpp>
|
||||||
#include <boost/unordered/detail/foa/node_handle.hpp>
|
#include <boost/unordered/detail/foa/node_map_handle.hpp>
|
||||||
#include <boost/unordered/detail/foa/node_map_types.hpp>
|
#include <boost/unordered/detail/foa/node_map_types.hpp>
|
||||||
#include <boost/unordered/detail/foa/table.hpp>
|
#include <boost/unordered/detail/foa/table.hpp>
|
||||||
#include <boost/unordered/detail/serialize_container.hpp>
|
#include <boost/unordered/detail/serialize_container.hpp>
|
||||||
@ -36,45 +37,13 @@ namespace boost {
|
|||||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <class TypePolicy, class Allocator>
|
|
||||||
struct node_map_handle
|
|
||||||
: public detail::foa::node_handle_base<TypePolicy, Allocator>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using base_type = detail::foa::node_handle_base<TypePolicy, Allocator>;
|
|
||||||
|
|
||||||
using typename base_type::type_policy;
|
|
||||||
|
|
||||||
template <class Key, class T, class Hash, class Pred, class Alloc>
|
|
||||||
friend class boost::unordered::unordered_node_map;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using key_type = typename TypePolicy::key_type;
|
|
||||||
using mapped_type = typename TypePolicy::mapped_type;
|
|
||||||
|
|
||||||
constexpr node_map_handle() noexcept = default;
|
|
||||||
node_map_handle(node_map_handle&& nh) noexcept = default;
|
|
||||||
|
|
||||||
node_map_handle& operator=(node_map_handle&&) noexcept = default;
|
|
||||||
|
|
||||||
key_type& key() const
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(!this->empty());
|
|
||||||
return const_cast<key_type&>(this->data().first);
|
|
||||||
}
|
|
||||||
|
|
||||||
mapped_type& mapped() const
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(!this->empty());
|
|
||||||
return const_cast<mapped_type&>(this->data().second);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||||
class unordered_node_map
|
class unordered_node_map
|
||||||
{
|
{
|
||||||
|
template <class Key2, class T2, class Hash2, class Pred2,
|
||||||
|
class Allocator2>
|
||||||
|
friend class concurrent_node_map;
|
||||||
|
|
||||||
using map_types = detail::foa::node_map_types<Key, T,
|
using map_types = detail::foa::node_map_types<Key, T,
|
||||||
typename boost::allocator_void_pointer<Allocator>::type>;
|
typename boost::allocator_void_pointer<Allocator>::type>;
|
||||||
|
|
||||||
@ -109,7 +78,7 @@ namespace boost {
|
|||||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||||
using iterator = typename table_type::iterator;
|
using iterator = typename table_type::iterator;
|
||||||
using const_iterator = typename table_type::const_iterator;
|
using const_iterator = typename table_type::const_iterator;
|
||||||
using node_type = detail::node_map_handle<map_types,
|
using node_type = detail::foa::node_map_handle<map_types,
|
||||||
typename boost::allocator_rebind<Allocator,
|
typename boost::allocator_rebind<Allocator,
|
||||||
typename map_types::value_type>::type>;
|
typename map_types::value_type>::type>;
|
||||||
using insert_return_type =
|
using insert_return_type =
|
||||||
@ -220,6 +189,12 @@ namespace boost {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unordered_node_map(
|
||||||
|
concurrent_node_map<Key, T, Hash, KeyEqual, Allocator>&& other)
|
||||||
|
: table_(std::move(other.table_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
~unordered_node_map() = default;
|
~unordered_node_map() = default;
|
||||||
|
|
||||||
unordered_node_map& operator=(unordered_node_map const& other)
|
unordered_node_map& operator=(unordered_node_map const& other)
|
||||||
@ -307,15 +282,17 @@ namespace boost {
|
|||||||
|
|
||||||
insert_return_type insert(node_type&& nh)
|
insert_return_type insert(node_type&& nh)
|
||||||
{
|
{
|
||||||
|
using access = detail::foa::node_handle_access;
|
||||||
|
|
||||||
if (nh.empty()) {
|
if (nh.empty()) {
|
||||||
return {end(), false, node_type{}};
|
return {end(), false, node_type{}};
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||||
|
|
||||||
auto itp = table_.insert(std::move(nh.element()));
|
auto itp = table_.insert(std::move(access::element(nh)));
|
||||||
if (itp.second) {
|
if (itp.second) {
|
||||||
nh.reset();
|
access::reset(nh);
|
||||||
return {itp.first, true, node_type{}};
|
return {itp.first, true, node_type{}};
|
||||||
} else {
|
} else {
|
||||||
return {itp.first, false, std::move(nh)};
|
return {itp.first, false, std::move(nh)};
|
||||||
@ -324,15 +301,17 @@ namespace boost {
|
|||||||
|
|
||||||
iterator insert(const_iterator, node_type&& nh)
|
iterator insert(const_iterator, node_type&& nh)
|
||||||
{
|
{
|
||||||
|
using access = detail::foa::node_handle_access;
|
||||||
|
|
||||||
if (nh.empty()) {
|
if (nh.empty()) {
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||||
|
|
||||||
auto itp = table_.insert(std::move(nh.element()));
|
auto itp = table_.insert(std::move(access::element(nh)));
|
||||||
if (itp.second) {
|
if (itp.second) {
|
||||||
nh.reset();
|
access::reset(nh);
|
||||||
return itp.first;
|
return itp.first;
|
||||||
} else {
|
} else {
|
||||||
return itp.first;
|
return itp.first;
|
||||||
@ -507,7 +486,8 @@ namespace boost {
|
|||||||
BOOST_ASSERT(pos != end());
|
BOOST_ASSERT(pos != end());
|
||||||
node_type nh;
|
node_type nh;
|
||||||
auto elem = table_.extract(pos);
|
auto elem = table_.extract(pos);
|
||||||
nh.emplace(std::move(elem), get_allocator());
|
detail::foa::node_handle_emplacer(nh)(
|
||||||
|
std::move(elem), get_allocator());
|
||||||
return nh;
|
return nh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
// Copyright (C) 2022-2023 Christian Mazakas
|
// Copyright (C) 2022-2023 Christian Mazakas
|
||||||
|
// Copyright (C) 2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -10,8 +11,9 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <boost/unordered/concurrent_node_set_fwd.hpp>
|
||||||
#include <boost/unordered/detail/foa/element_type.hpp>
|
#include <boost/unordered/detail/foa/element_type.hpp>
|
||||||
#include <boost/unordered/detail/foa/node_handle.hpp>
|
#include <boost/unordered/detail/foa/node_set_handle.hpp>
|
||||||
#include <boost/unordered/detail/foa/node_set_types.hpp>
|
#include <boost/unordered/detail/foa/node_set_types.hpp>
|
||||||
#include <boost/unordered/detail/foa/table.hpp>
|
#include <boost/unordered/detail/foa/table.hpp>
|
||||||
#include <boost/unordered/detail/serialize_container.hpp>
|
#include <boost/unordered/detail/serialize_container.hpp>
|
||||||
@ -35,37 +37,12 @@ namespace boost {
|
|||||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace detail {
|
|
||||||
template <class TypePolicy, class Allocator>
|
|
||||||
struct node_set_handle
|
|
||||||
: public detail::foa::node_handle_base<TypePolicy, Allocator>
|
|
||||||
{
|
|
||||||
private:
|
|
||||||
using base_type = detail::foa::node_handle_base<TypePolicy, Allocator>;
|
|
||||||
|
|
||||||
using typename base_type::type_policy;
|
|
||||||
|
|
||||||
template <class Key, class Hash, class Pred, class Alloc>
|
|
||||||
friend class boost::unordered::unordered_node_set;
|
|
||||||
|
|
||||||
public:
|
|
||||||
using value_type = typename TypePolicy::value_type;
|
|
||||||
|
|
||||||
constexpr node_set_handle() noexcept = default;
|
|
||||||
node_set_handle(node_set_handle&& nh) noexcept = default;
|
|
||||||
node_set_handle& operator=(node_set_handle&&) noexcept = default;
|
|
||||||
|
|
||||||
value_type& value() const
|
|
||||||
{
|
|
||||||
BOOST_ASSERT(!this->empty());
|
|
||||||
return const_cast<value_type&>(this->data());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} // namespace detail
|
|
||||||
|
|
||||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||||
class unordered_node_set
|
class unordered_node_set
|
||||||
{
|
{
|
||||||
|
template <class Key2, class Hash2, class Pred2, class Allocator2>
|
||||||
|
friend class concurrent_node_set;
|
||||||
|
|
||||||
using set_types = detail::foa::node_set_types<Key,
|
using set_types = detail::foa::node_set_types<Key,
|
||||||
typename boost::allocator_void_pointer<Allocator>::type>;
|
typename boost::allocator_void_pointer<Allocator>::type>;
|
||||||
|
|
||||||
@ -99,7 +76,7 @@ namespace boost {
|
|||||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||||
using iterator = typename table_type::iterator;
|
using iterator = typename table_type::iterator;
|
||||||
using const_iterator = typename table_type::const_iterator;
|
using const_iterator = typename table_type::const_iterator;
|
||||||
using node_type = detail::node_set_handle<set_types,
|
using node_type = detail::foa::node_set_handle<set_types,
|
||||||
typename boost::allocator_rebind<Allocator,
|
typename boost::allocator_rebind<Allocator,
|
||||||
typename set_types::value_type>::type>;
|
typename set_types::value_type>::type>;
|
||||||
using insert_return_type =
|
using insert_return_type =
|
||||||
@ -210,6 +187,12 @@ namespace boost {
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
unordered_node_set(
|
||||||
|
concurrent_node_set<Key, Hash, KeyEqual, Allocator>&& other)
|
||||||
|
: table_(std::move(other.table_))
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
~unordered_node_set() = default;
|
~unordered_node_set() = default;
|
||||||
|
|
||||||
unordered_node_set& operator=(unordered_node_set const& other)
|
unordered_node_set& operator=(unordered_node_set const& other)
|
||||||
@ -312,15 +295,17 @@ namespace boost {
|
|||||||
|
|
||||||
insert_return_type insert(node_type&& nh)
|
insert_return_type insert(node_type&& nh)
|
||||||
{
|
{
|
||||||
|
using access = detail::foa::node_handle_access;
|
||||||
|
|
||||||
if (nh.empty()) {
|
if (nh.empty()) {
|
||||||
return {end(), false, node_type{}};
|
return {end(), false, node_type{}};
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||||
|
|
||||||
auto itp = table_.insert(std::move(nh.element()));
|
auto itp = table_.insert(std::move(access::element(nh)));
|
||||||
if (itp.second) {
|
if (itp.second) {
|
||||||
nh.reset();
|
access::reset(nh);
|
||||||
return {itp.first, true, node_type{}};
|
return {itp.first, true, node_type{}};
|
||||||
} else {
|
} else {
|
||||||
return {itp.first, false, std::move(nh)};
|
return {itp.first, false, std::move(nh)};
|
||||||
@ -329,15 +314,17 @@ namespace boost {
|
|||||||
|
|
||||||
iterator insert(const_iterator, node_type&& nh)
|
iterator insert(const_iterator, node_type&& nh)
|
||||||
{
|
{
|
||||||
|
using access = detail::foa::node_handle_access;
|
||||||
|
|
||||||
if (nh.empty()) {
|
if (nh.empty()) {
|
||||||
return end();
|
return end();
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||||
|
|
||||||
auto itp = table_.insert(std::move(nh.element()));
|
auto itp = table_.insert(std::move(access::element(nh)));
|
||||||
if (itp.second) {
|
if (itp.second) {
|
||||||
nh.reset();
|
access::reset(nh);
|
||||||
return itp.first;
|
return itp.first;
|
||||||
} else {
|
} else {
|
||||||
return itp.first;
|
return itp.first;
|
||||||
@ -395,7 +382,8 @@ namespace boost {
|
|||||||
BOOST_ASSERT(pos != end());
|
BOOST_ASSERT(pos != end());
|
||||||
node_type nh;
|
node_type nh;
|
||||||
auto elem = table_.extract(pos);
|
auto elem = table_.extract(pos);
|
||||||
nh.emplace(std::move(elem), get_allocator());
|
detail::foa::node_handle_emplacer(nh)(
|
||||||
|
std::move(elem), get_allocator());
|
||||||
return nh;
|
return nh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,7 +135,7 @@ foa_tests(SOURCES exception/merge_exception_tests.cpp)
|
|||||||
|
|
||||||
# CFOA tests
|
# CFOA tests
|
||||||
|
|
||||||
cfoa_tests(SOURCES cfoa/insert_tests.cpp)
|
cfoa_tests(SOURCES cfoa/insert_tests.cpp COMPILE_OPTIONS $<$<CXX_COMPILER_ID:MSVC>:/bigobj>)
|
||||||
cfoa_tests(SOURCES cfoa/erase_tests.cpp)
|
cfoa_tests(SOURCES cfoa/erase_tests.cpp)
|
||||||
cfoa_tests(SOURCES cfoa/try_emplace_tests.cpp)
|
cfoa_tests(SOURCES cfoa/try_emplace_tests.cpp)
|
||||||
cfoa_tests(SOURCES cfoa/emplace_tests.cpp)
|
cfoa_tests(SOURCES cfoa/emplace_tests.cpp)
|
||||||
|
@ -110,6 +110,7 @@ local FCA_TESTS =
|
|||||||
move_tests
|
move_tests
|
||||||
narrow_cast_tests
|
narrow_cast_tests
|
||||||
node_handle_tests
|
node_handle_tests
|
||||||
|
node_handle_allocator_tests
|
||||||
noexcept_tests
|
noexcept_tests
|
||||||
post_move_tests
|
post_move_tests
|
||||||
prime_fmod_tests
|
prime_fmod_tests
|
||||||
@ -232,6 +233,7 @@ local FOA_TESTS =
|
|||||||
fancy_pointer_noleak
|
fancy_pointer_noleak
|
||||||
pmr_allocator_tests
|
pmr_allocator_tests
|
||||||
stats_tests
|
stats_tests
|
||||||
|
node_handle_allocator_tests
|
||||||
;
|
;
|
||||||
|
|
||||||
for local test in $(FOA_TESTS)
|
for local test in $(FOA_TESTS)
|
||||||
@ -308,11 +310,10 @@ alias foa_tests :
|
|||||||
;
|
;
|
||||||
|
|
||||||
local CFOA_TESTS =
|
local CFOA_TESTS =
|
||||||
insert_tests
|
|
||||||
erase_tests
|
erase_tests
|
||||||
try_emplace_tests
|
try_emplace_tests
|
||||||
emplace_tests
|
emplace_tests
|
||||||
visit_tests
|
extract_insert_tests
|
||||||
constructor_tests
|
constructor_tests
|
||||||
assign_tests
|
assign_tests
|
||||||
clear_tests
|
clear_tests
|
||||||
@ -338,6 +339,7 @@ local CFOA_TESTS =
|
|||||||
explicit_alloc_ctor_tests
|
explicit_alloc_ctor_tests
|
||||||
pmr_allocator_tests
|
pmr_allocator_tests
|
||||||
stats_tests
|
stats_tests
|
||||||
|
node_handle_allocator_tests
|
||||||
;
|
;
|
||||||
|
|
||||||
for local test in $(CFOA_TESTS)
|
for local test in $(CFOA_TESTS)
|
||||||
@ -348,6 +350,28 @@ for local test in $(CFOA_TESTS)
|
|||||||
;
|
;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
run cfoa/insert_tests.cpp
|
||||||
|
:
|
||||||
|
:
|
||||||
|
: $(CPP11) <threading>multi
|
||||||
|
<toolset>msvc:<cxxflags>/bigobj
|
||||||
|
<toolset>gcc:<inlining>on
|
||||||
|
<toolset>gcc:<optimization>space
|
||||||
|
<toolset>clang:<inlining>on
|
||||||
|
<toolset>clang:<optimization>space
|
||||||
|
: cfoa_insert_tests ;
|
||||||
|
|
||||||
|
run cfoa/visit_tests.cpp
|
||||||
|
:
|
||||||
|
:
|
||||||
|
: $(CPP11) <threading>multi
|
||||||
|
<toolset>msvc:<cxxflags>/bigobj
|
||||||
|
<toolset>gcc:<inlining>on
|
||||||
|
<toolset>gcc:<optimization>space
|
||||||
|
<toolset>clang:<inlining>on
|
||||||
|
<toolset>clang:<optimization>space
|
||||||
|
: cfoa_visit_tests ;
|
||||||
|
|
||||||
run cfoa/serialization_tests.cpp
|
run cfoa/serialization_tests.cpp
|
||||||
:
|
:
|
||||||
:
|
:
|
||||||
@ -383,6 +407,8 @@ make_cfoa_interprocess_concurrency_tests cfoa_interproc_conc_tests_stats
|
|||||||
|
|
||||||
alias cfoa_tests :
|
alias cfoa_tests :
|
||||||
cfoa_$(CFOA_TESTS)
|
cfoa_$(CFOA_TESTS)
|
||||||
|
cfoa_insert_tests
|
||||||
|
cfoa_visit_tests
|
||||||
cfoa_serialization_tests
|
cfoa_serialization_tests
|
||||||
cfoa_interproc_conc_tests
|
cfoa_interproc_conc_tests
|
||||||
cfoa_interproc_conc_tests_stats ;
|
cfoa_interproc_conc_tests_stats ;
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#if defined(__clang__) && defined(__has_warning)
|
#if defined(__clang__) && defined(__has_warning)
|
||||||
|
|
||||||
@ -37,19 +39,35 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
using fancy_map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using fancy_map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator2<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator2<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using fancy_node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator2<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using fancy_set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using fancy_set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator2<raii> >;
|
key_equal, stateful_allocator2<raii> >;
|
||||||
|
|
||||||
|
using fancy_node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator2<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
fancy_map_type* fancy_test_map;
|
fancy_map_type* fancy_test_map;
|
||||||
|
fancy_node_map_type* fancy_test_node_map;
|
||||||
fancy_set_type* fancy_test_set;
|
fancy_set_type* fancy_test_set;
|
||||||
|
fancy_node_set_type* fancy_test_node_set;
|
||||||
|
|
||||||
std::initializer_list<map_type::value_type> map_init_list{
|
std::initializer_list<map_type::value_type> map_init_list{
|
||||||
{raii{0}, raii{0}},
|
{raii{0}, raii{0}},
|
||||||
@ -102,7 +120,9 @@ std::initializer_list<set_type::value_type> set_init_list{
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
||||||
|
auto test_node_map_and_init_list=std::make_pair(test_node_map,map_init_list);
|
||||||
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
||||||
|
auto test_node_set_and_init_list=std::make_pair(test_node_set,set_init_list);
|
||||||
|
|
||||||
template <class T,bool POCCA, bool POCMA>
|
template <class T,bool POCCA, bool POCMA>
|
||||||
struct poca_allocator: fancy_allocator<T>
|
struct poca_allocator: fancy_allocator<T>
|
||||||
@ -928,7 +948,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class GF>
|
template <class X, class GF>
|
||||||
void flat_move_assign(X*, GF gen_factory, test::random_generator rg)
|
void nonconcurrent_move_assign(X*, GF gen_factory, test::random_generator rg)
|
||||||
{
|
{
|
||||||
using value_type = typename X::value_type;
|
using value_type = typename X::value_type;
|
||||||
static constexpr auto value_type_cardinality =
|
static constexpr auto value_type_cardinality =
|
||||||
@ -950,16 +970,17 @@ namespace {
|
|||||||
{
|
{
|
||||||
raii::reset_counts();
|
raii::reset_counts();
|
||||||
|
|
||||||
flat_container<X> flat(values.begin(), values.end(), values.size(),
|
nonconcurrent_container<X> nonc(
|
||||||
|
values.begin(), values.end(), values.size(),
|
||||||
hasher(1), key_equal(2), allocator_type(3));
|
hasher(1), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
X x(0, hasher(2), key_equal(1), allocator_type(3));
|
X x(0, hasher(2), key_equal(1), allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST(flat.get_allocator() == x.get_allocator());
|
BOOST_TEST(nonc.get_allocator() == x.get_allocator());
|
||||||
|
|
||||||
x = std::move(flat);
|
x = std::move(nonc);
|
||||||
|
|
||||||
BOOST_TEST(flat.empty());
|
BOOST_TEST(nonc.empty());
|
||||||
BOOST_TEST_EQ(x.size(), reference_cont.size());
|
BOOST_TEST_EQ(x.size(), reference_cont.size());
|
||||||
|
|
||||||
test_fuzzy_matches_reference(x, reference_cont, rg);
|
test_fuzzy_matches_reference(x, reference_cont, rg);
|
||||||
@ -983,17 +1004,18 @@ namespace {
|
|||||||
X x(values.begin(), values.end(), values.size(), hasher(1),
|
X x(values.begin(), values.end(), values.size(), hasher(1),
|
||||||
key_equal(2), allocator_type(3));
|
key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
flat_container<X> flat(0, hasher(2), key_equal(1), allocator_type(3));
|
nonconcurrent_container<X> nonc(
|
||||||
|
0, hasher(2), key_equal(1), allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST(flat.get_allocator() == x.get_allocator());
|
BOOST_TEST(nonc.get_allocator() == x.get_allocator());
|
||||||
|
|
||||||
flat = std::move(x);
|
nonc = std::move(x);
|
||||||
|
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST_EQ(flat.size(), reference_cont.size());
|
BOOST_TEST_EQ(nonc.size(), reference_cont.size());
|
||||||
|
|
||||||
BOOST_TEST_EQ(flat.hash_function(), hasher(1));
|
BOOST_TEST_EQ(nonc.hash_function(), hasher(1));
|
||||||
BOOST_TEST_EQ(flat.key_eq(), key_equal(2));
|
BOOST_TEST_EQ(nonc.key_eq(), key_equal(2));
|
||||||
|
|
||||||
BOOST_TEST_EQ(
|
BOOST_TEST_EQ(
|
||||||
raii::copy_constructor, value_type_cardinality * reference_cont.size());
|
raii::copy_constructor, value_type_cardinality * reference_cont.size());
|
||||||
@ -1008,16 +1030,17 @@ namespace {
|
|||||||
{
|
{
|
||||||
raii::reset_counts();
|
raii::reset_counts();
|
||||||
|
|
||||||
flat_container<X> flat(values.begin(), values.end(), values.size(),
|
nonconcurrent_container<X> nonc(
|
||||||
|
values.begin(), values.end(), values.size(),
|
||||||
hasher(1), key_equal(2), allocator_type(3));
|
hasher(1), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
X x(0, hasher(2), key_equal(1), allocator_type(4));
|
X x(0, hasher(2), key_equal(1), allocator_type(4));
|
||||||
|
|
||||||
BOOST_TEST(flat.get_allocator() != x.get_allocator());
|
BOOST_TEST(nonc.get_allocator() != x.get_allocator());
|
||||||
|
|
||||||
x = std::move(flat);
|
x = std::move(nonc);
|
||||||
|
|
||||||
BOOST_TEST(flat.empty());
|
BOOST_TEST(nonc.empty());
|
||||||
BOOST_TEST_EQ(x.size(), reference_cont.size());
|
BOOST_TEST_EQ(x.size(), reference_cont.size());
|
||||||
|
|
||||||
test_fuzzy_matches_reference(x, reference_cont, rg);
|
test_fuzzy_matches_reference(x, reference_cont, rg);
|
||||||
@ -1043,17 +1066,18 @@ namespace {
|
|||||||
X x(values.begin(), values.end(), values.size(), hasher(1),
|
X x(values.begin(), values.end(), values.size(), hasher(1),
|
||||||
key_equal(2), allocator_type(3));
|
key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
flat_container<X> flat(0, hasher(2), key_equal(1), allocator_type(4));
|
nonconcurrent_container<X> nonc(
|
||||||
|
0, hasher(2), key_equal(1), allocator_type(4));
|
||||||
|
|
||||||
BOOST_TEST(flat.get_allocator() != x.get_allocator());
|
BOOST_TEST(nonc.get_allocator() != x.get_allocator());
|
||||||
|
|
||||||
flat = std::move(x);
|
nonc = std::move(x);
|
||||||
|
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
BOOST_TEST_EQ(flat.size(), reference_cont.size());
|
BOOST_TEST_EQ(nonc.size(), reference_cont.size());
|
||||||
|
|
||||||
BOOST_TEST_EQ(flat.hash_function(), hasher(1));
|
BOOST_TEST_EQ(nonc.hash_function(), hasher(1));
|
||||||
BOOST_TEST_EQ(flat.key_eq(), key_equal(2));
|
BOOST_TEST_EQ(nonc.key_eq(), key_equal(2));
|
||||||
|
|
||||||
BOOST_TEST_EQ(
|
BOOST_TEST_EQ(
|
||||||
raii::copy_constructor, value_type_cardinality * reference_cont.size());
|
raii::copy_constructor, value_type_cardinality * reference_cont.size());
|
||||||
@ -1073,29 +1097,31 @@ namespace {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
copy_assign,
|
copy_assign,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
move_assign,
|
move_assign,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
initializer_list_assign,
|
initializer_list_assign,
|
||||||
((test_map_and_init_list)(test_set_and_init_list)))
|
((test_map_and_init_list)(test_node_map_and_init_list)
|
||||||
|
(test_set_and_init_list)(test_node_set_and_init_list)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert_and_assign,
|
insert_and_assign,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((init_type_generator_factory))
|
((init_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
flat_move_assign,
|
nonconcurrent_move_assign,
|
||||||
((test_map)(test_set)(fancy_test_map)(fancy_test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set)
|
||||||
|
(fancy_test_map)(fancy_test_node_map)(fancy_test_set)(fancy_test_node_set))
|
||||||
((init_type_generator_factory))
|
((init_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
test::seed_t initialize_seed{674140082};
|
test::seed_t initialize_seed{674140082};
|
||||||
|
|
||||||
@ -20,11 +22,19 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
template <class X, class GF>
|
template <class X, class GF>
|
||||||
@ -130,12 +140,12 @@ namespace {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
clear_tests,
|
clear_tests,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(insert_and_clear,
|
UNORDERED_TEST(insert_and_clear,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -1,15 +1,19 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifndef BOOST_UNORDERED_TEST_CFOA_COMMON_HELPERS_HPP
|
#ifndef BOOST_UNORDERED_TEST_CFOA_COMMON_HELPERS_HPP
|
||||||
#define BOOST_UNORDERED_TEST_CFOA_COMMON_HELPERS_HPP
|
#define BOOST_UNORDERED_TEST_CFOA_COMMON_HELPERS_HPP
|
||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
|
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set_fwd.hpp>
|
#include <boost/unordered/concurrent_flat_set_fwd.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map_fwd.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set_fwd.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/unordered/unordered_flat_map.hpp>
|
||||||
#include <boost/unordered/unordered_flat_set.hpp>
|
#include <boost/unordered/unordered_flat_set.hpp>
|
||||||
|
#include <boost/unordered/unordered_node_map.hpp>
|
||||||
|
#include <boost/unordered/unordered_node_set.hpp>
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
@ -27,6 +31,31 @@ struct value_cardinality<std::pair<K, V> >
|
|||||||
static constexpr std::size_t value=2;
|
static constexpr std::size_t value=2;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename K>
|
||||||
|
struct value_nonconst_cardinality
|
||||||
|
{
|
||||||
|
static constexpr std::size_t value=1;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V>
|
||||||
|
struct value_nonconst_cardinality<std::pair<K, V> >
|
||||||
|
{
|
||||||
|
static constexpr std::size_t value=
|
||||||
|
1 * !std::is_const<K>::value +
|
||||||
|
1 * !std::is_const<V>::value ;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
struct is_container_node_based: std::false_type {};
|
||||||
|
|
||||||
|
template <typename K, typename V, typename H, typename P, typename A>
|
||||||
|
struct is_container_node_based<boost::concurrent_node_map<K, V, H, P, A> >
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
|
template <typename K, typename H, typename P, typename A>
|
||||||
|
struct is_container_node_based<boost::concurrent_node_set<K, H, P, A> >
|
||||||
|
: std::true_type {};
|
||||||
|
|
||||||
template <class Container>
|
template <class Container>
|
||||||
struct reference_container_impl;
|
struct reference_container_impl;
|
||||||
|
|
||||||
@ -39,30 +68,55 @@ struct reference_container_impl<boost::concurrent_flat_map<K, V, H, P, A> >
|
|||||||
using type = boost::unordered_flat_map<K, V>;
|
using type = boost::unordered_flat_map<K, V>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V, typename H, typename P, typename A>
|
||||||
|
struct reference_container_impl<boost::concurrent_node_map<K, V, H, P, A> >
|
||||||
|
{
|
||||||
|
using type = boost::unordered_node_map<K, V>;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename K, typename H, typename P, typename A>
|
template <typename K, typename H, typename P, typename A>
|
||||||
struct reference_container_impl<boost::concurrent_flat_set<K, H, P, A> >
|
struct reference_container_impl<boost::concurrent_flat_set<K, H, P, A> >
|
||||||
{
|
{
|
||||||
using type = boost::unordered_flat_set<K>;
|
using type = boost::unordered_flat_set<K>;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class Container>
|
template <typename K, typename H, typename P, typename A>
|
||||||
struct flat_container_impl;
|
struct reference_container_impl<boost::concurrent_node_set<K, H, P, A> >
|
||||||
|
{
|
||||||
|
using type = boost::unordered_node_set<K>;
|
||||||
|
};
|
||||||
|
|
||||||
template <class Container>
|
template <class Container>
|
||||||
using flat_container = typename flat_container_impl<Container>::type;
|
struct nonconcurrent_container_impl;
|
||||||
|
|
||||||
|
template <class Container>
|
||||||
|
using nonconcurrent_container =
|
||||||
|
typename nonconcurrent_container_impl<Container>::type;
|
||||||
|
|
||||||
template <typename K, typename V, typename H, typename P, typename A>
|
template <typename K, typename V, typename H, typename P, typename A>
|
||||||
struct flat_container_impl<boost::concurrent_flat_map<K, V, H, P, A> >
|
struct nonconcurrent_container_impl<boost::concurrent_flat_map<K, V, H, P, A> >
|
||||||
{
|
{
|
||||||
using type = boost::unordered_flat_map<K, V, H, P, A>;
|
using type = boost::unordered_flat_map<K, V, H, P, A>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename K, typename V, typename H, typename P, typename A>
|
||||||
|
struct nonconcurrent_container_impl<boost::concurrent_node_map<K, V, H, P, A> >
|
||||||
|
{
|
||||||
|
using type = boost::unordered_node_map<K, V, H, P, A>;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename K, typename H, typename P, typename A>
|
template <typename K, typename H, typename P, typename A>
|
||||||
struct flat_container_impl<boost::concurrent_flat_set<K, H, P, A> >
|
struct nonconcurrent_container_impl<boost::concurrent_flat_set<K, H, P, A> >
|
||||||
{
|
{
|
||||||
using type = boost::unordered_flat_set<K, H, P, A>;
|
using type = boost::unordered_flat_set<K, H, P, A>;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename K, typename H, typename P, typename A>
|
||||||
|
struct nonconcurrent_container_impl<boost::concurrent_node_set<K, H, P, A> >
|
||||||
|
{
|
||||||
|
using type = boost::unordered_node_set<K, H, P, A>;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename Container, template <typename> class Allocator>
|
template <typename Container, template <typename> class Allocator>
|
||||||
struct replace_allocator_impl;
|
struct replace_allocator_impl;
|
||||||
|
|
||||||
@ -95,7 +149,33 @@ struct replace_allocator_impl<
|
|||||||
using type =
|
using type =
|
||||||
boost::concurrent_flat_set<K, H, P, Allocator<value_type> >;
|
boost::concurrent_flat_set<K, H, P, Allocator<value_type> >;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename K, typename V, typename H, typename P, typename A,
|
||||||
|
template <typename> class Allocator
|
||||||
|
>
|
||||||
|
struct replace_allocator_impl<
|
||||||
|
boost::concurrent_node_map<K, V, H, P, A>, Allocator>
|
||||||
|
{
|
||||||
|
using value_type =
|
||||||
|
typename boost::concurrent_node_map<K, V, H, P, A>::value_type;
|
||||||
|
using type =
|
||||||
|
boost::concurrent_node_map<K, V, H, P, Allocator<value_type> >;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename K, typename H, typename P, typename A,
|
||||||
|
template <typename> class Allocator
|
||||||
|
>
|
||||||
|
struct replace_allocator_impl<
|
||||||
|
boost::concurrent_node_set<K, H, P, A>, Allocator>
|
||||||
|
{
|
||||||
|
using value_type =
|
||||||
|
typename boost::concurrent_node_set<K, H, P, A>::value_type;
|
||||||
|
using type =
|
||||||
|
boost::concurrent_node_set<K, H, P, Allocator<value_type> >;
|
||||||
|
};
|
||||||
|
|
||||||
template <typename K>
|
template <typename K>
|
||||||
K const& get_key(K const& x) { return x; }
|
K const& get_key(K const& x) { return x; }
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
test::seed_t initialize_seed(4122023);
|
test::seed_t initialize_seed(4122023);
|
||||||
|
|
||||||
@ -52,11 +54,19 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
std::initializer_list<map_type::value_type> map_init_list{
|
std::initializer_list<map_type::value_type> map_init_list{
|
||||||
{raii{0}, raii{0}},
|
{raii{0}, raii{0}},
|
||||||
@ -109,7 +119,9 @@ std::initializer_list<set_type::value_type> set_init_list{
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
||||||
|
auto test_node_map_and_init_list=std::make_pair(test_node_map,map_init_list);
|
||||||
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
||||||
|
auto test_node_set_and_init_list=std::make_pair(test_node_set,set_init_list);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
template <class X>
|
template <class X>
|
||||||
@ -865,7 +877,7 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <class X, class GF>
|
template <class X, class GF>
|
||||||
void flat_constructor(X*, GF gen_factory, test::random_generator rg)
|
void nonconcurrent_constructor(X*, GF gen_factory, test::random_generator rg)
|
||||||
{
|
{
|
||||||
using value_type = typename X::value_type;
|
using value_type = typename X::value_type;
|
||||||
static constexpr auto value_type_cardinality =
|
static constexpr auto value_type_cardinality =
|
||||||
@ -875,12 +887,13 @@ namespace {
|
|||||||
auto gen = gen_factory.template get<X>();
|
auto gen = gen_factory.template get<X>();
|
||||||
auto values = make_random_values(1024 * 16, [&] { return gen(rg); });
|
auto values = make_random_values(1024 * 16, [&] { return gen(rg); });
|
||||||
auto reference_cont = reference_container<X>(values.begin(), values.end());
|
auto reference_cont = reference_container<X>(values.begin(), values.end());
|
||||||
auto reference_flat= flat_container<X>(values.begin(), values.end());
|
auto reference_nonc =
|
||||||
|
nonconcurrent_container<X>(values.begin(), values.end());
|
||||||
|
|
||||||
raii::reset_counts();
|
raii::reset_counts();
|
||||||
|
|
||||||
{
|
{
|
||||||
flat_container<X> flat(
|
nonconcurrent_container<X> nonc(
|
||||||
values.begin(), values.end(), reference_cont.size(), hasher(1),
|
values.begin(), values.end(), reference_cont.size(), hasher(1),
|
||||||
key_equal(2), allocator_type(3));
|
key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
@ -890,9 +903,9 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(old_dc, 0u);
|
BOOST_TEST_EQ(old_dc, 0u);
|
||||||
BOOST_TEST_EQ(old_mc, 0u);
|
BOOST_TEST_EQ(old_mc, 0u);
|
||||||
BOOST_TEST_EQ(old_cc, value_type_cardinality * flat.size());
|
BOOST_TEST_EQ(old_cc, value_type_cardinality * nonc.size());
|
||||||
|
|
||||||
X x(std::move(flat));
|
X x(std::move(nonc));
|
||||||
|
|
||||||
test_fuzzy_matches_reference(x, reference_cont, rg);
|
test_fuzzy_matches_reference(x, reference_cont, rg);
|
||||||
|
|
||||||
@ -904,15 +917,16 @@ namespace {
|
|||||||
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
||||||
BOOST_TEST(x.get_allocator() == allocator_type(3));
|
BOOST_TEST(x.get_allocator() == allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST(flat.empty());
|
BOOST_TEST(nonc.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
check_raii_counts();
|
check_raii_counts();
|
||||||
|
|
||||||
{
|
{
|
||||||
flat_container<X> flat(0, hasher(1), key_equal(2), allocator_type(3));
|
nonconcurrent_container<X> nonc(
|
||||||
|
0, hasher(1), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
X x(std::move(flat));
|
X x(std::move(nonc));
|
||||||
|
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
|
|
||||||
@ -920,7 +934,7 @@ namespace {
|
|||||||
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
BOOST_TEST_EQ(x.key_eq(), key_equal(2));
|
||||||
BOOST_TEST(x.get_allocator() == allocator_type(3));
|
BOOST_TEST(x.get_allocator() == allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST(flat.empty());
|
BOOST_TEST(nonc.empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
check_raii_counts();
|
check_raii_counts();
|
||||||
@ -937,17 +951,17 @@ namespace {
|
|||||||
BOOST_TEST_EQ(old_mc, 0u);
|
BOOST_TEST_EQ(old_mc, 0u);
|
||||||
BOOST_TEST_EQ(old_cc, 2u * value_type_cardinality * x.size());
|
BOOST_TEST_EQ(old_cc, 2u * value_type_cardinality * x.size());
|
||||||
|
|
||||||
flat_container<X> flat(std::move(x));
|
nonconcurrent_container<X> nonc(std::move(x));
|
||||||
|
|
||||||
BOOST_TEST(flat == reference_flat);
|
BOOST_TEST(nonc == reference_nonc);
|
||||||
|
|
||||||
BOOST_TEST_EQ(+raii::default_constructor, old_dc);
|
BOOST_TEST_EQ(+raii::default_constructor, old_dc);
|
||||||
BOOST_TEST_EQ(+raii::move_constructor, old_mc);
|
BOOST_TEST_EQ(+raii::move_constructor, old_mc);
|
||||||
BOOST_TEST_EQ(+raii::copy_constructor, old_cc);
|
BOOST_TEST_EQ(+raii::copy_constructor, old_cc);
|
||||||
|
|
||||||
BOOST_TEST_EQ(flat.hash_function(), hasher(1));
|
BOOST_TEST_EQ(nonc.hash_function(), hasher(1));
|
||||||
BOOST_TEST_EQ(flat.key_eq(), key_equal(2));
|
BOOST_TEST_EQ(nonc.key_eq(), key_equal(2));
|
||||||
BOOST_TEST(flat.get_allocator() == allocator_type(3));
|
BOOST_TEST(nonc.get_allocator() == allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
}
|
}
|
||||||
@ -957,13 +971,13 @@ namespace {
|
|||||||
{
|
{
|
||||||
X x(0, hasher(1), key_equal(2), allocator_type(3));
|
X x(0, hasher(1), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
flat_container<X> flat(std::move(x));
|
nonconcurrent_container<X> nonc(std::move(x));
|
||||||
|
|
||||||
BOOST_TEST(flat.empty());
|
BOOST_TEST(nonc.empty());
|
||||||
|
|
||||||
BOOST_TEST_EQ(flat.hash_function(), hasher(1));
|
BOOST_TEST_EQ(nonc.hash_function(), hasher(1));
|
||||||
BOOST_TEST_EQ(flat.key_eq(), key_equal(2));
|
BOOST_TEST_EQ(nonc.key_eq(), key_equal(2));
|
||||||
BOOST_TEST(flat.get_allocator() == allocator_type(3));
|
BOOST_TEST(nonc.get_allocator() == allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST(x.empty());
|
BOOST_TEST(x.empty());
|
||||||
}
|
}
|
||||||
@ -976,83 +990,84 @@ namespace {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
default_constructor,
|
default_constructor,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
bucket_count_with_hasher_key_equal_and_allocator,
|
bucket_count_with_hasher_key_equal_and_allocator,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
soccc,
|
soccc,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
from_iterator_range,
|
from_iterator_range,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
copy_constructor,
|
copy_constructor,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
copy_constructor_with_insertion,
|
copy_constructor_with_insertion,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
move_constructor,
|
move_constructor,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
move_constructor_with_insertion,
|
move_constructor_with_insertion,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
iterator_range_with_allocator,
|
iterator_range_with_allocator,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
explicit_allocator,
|
explicit_allocator,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
initializer_list_with_all_params,
|
initializer_list_with_all_params,
|
||||||
((test_map_and_init_list)(test_set_and_init_list)))
|
((test_map_and_init_list)(test_node_map_and_init_list)
|
||||||
|
(test_set_and_init_list)(test_node_set_and_init_list)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
bucket_count_and_allocator,
|
bucket_count_and_allocator,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
bucket_count_with_hasher_and_allocator,
|
bucket_count_with_hasher_and_allocator,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
iterator_range_with_bucket_count_and_allocator,
|
iterator_range_with_bucket_count_and_allocator,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
iterator_range_with_bucket_count_hasher_and_allocator,
|
iterator_range_with_bucket_count_hasher_and_allocator,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
flat_constructor,
|
nonconcurrent_constructor,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Copyright (C) 2024 Braden Ganetsky
|
// Copyright (C) 2024 Braden Ganetsky
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@ -9,6 +9,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -80,11 +82,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
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;
|
|
||||||
|
|
||||||
call_impl(values, x);
|
call_impl(values, x);
|
||||||
BOOST_TEST_GE(raii::move_constructor, value_type_cardinality * x.size());
|
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||||
}
|
}
|
||||||
} lvalue_emplacer;
|
} lvalue_emplacer;
|
||||||
|
|
||||||
@ -197,7 +196,12 @@ namespace {
|
|||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, value_type_cardinality * x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, value_type_cardinality * x.size());
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||||
@ -208,8 +212,8 @@ namespace {
|
|||||||
{
|
{
|
||||||
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
template <class T, class X> void operator()(std::vector<T>& values, X& x)
|
||||||
{
|
{
|
||||||
static constexpr auto value_type_cardinality =
|
static constexpr auto input_type_nonconst_cardinality =
|
||||||
value_cardinality<typename X::value_type>::value;
|
value_nonconst_cardinality<T>::value;
|
||||||
|
|
||||||
std::atomic<std::uint64_t> num_inserts{0};
|
std::atomic<std::uint64_t> num_inserts{0};
|
||||||
thread_runner(values, [&x, &num_inserts](boost::span<T> s) {
|
thread_runner(values, [&x, &num_inserts](boost::span<T> s) {
|
||||||
@ -235,10 +239,18 @@ namespace {
|
|||||||
} else {
|
} else {
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
raii::move_constructor, input_type_nonconst_cardinality * x.size());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
BOOST_TEST_GT(
|
||||||
|
raii::move_constructor, input_type_nonconst_cardinality * x.size());
|
||||||
|
}
|
||||||
#if defined(BOOST_MSVC)
|
#if defined(BOOST_MSVC)
|
||||||
#pragma warning(pop) // C4127
|
#pragma warning(pop) // C4127
|
||||||
#endif
|
#endif
|
||||||
BOOST_TEST_GT(raii::move_constructor, value_type_cardinality * x.size());
|
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||||
@ -280,7 +292,9 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii>* node_map;
|
||||||
boost::unordered::concurrent_flat_set<raii>* set;
|
boost::unordered::concurrent_flat_set<raii>* set;
|
||||||
|
boost::unordered::concurrent_node_set<raii>* node_set;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -292,7 +306,7 @@ using test::sequential;
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
emplace,
|
emplace,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((lvalue_emplacer)(norehash_lvalue_emplacer)
|
((lvalue_emplacer)(norehash_lvalue_emplacer)
|
||||||
(lvalue_emplace_or_cvisit)(lvalue_emplace_or_visit)(copy_emplacer)(move_emplacer))
|
(lvalue_emplace_or_cvisit)(lvalue_emplace_or_visit)(copy_emplacer)(move_emplacer))
|
||||||
@ -455,6 +469,8 @@ namespace {
|
|||||||
|
|
||||||
boost::unordered::concurrent_flat_map<counted_key_type, counted_value_type>*
|
boost::unordered::concurrent_flat_map<counted_key_type, counted_value_type>*
|
||||||
test_counted_flat_map = {};
|
test_counted_flat_map = {};
|
||||||
|
boost::unordered::concurrent_node_map<counted_key_type, counted_value_type>*
|
||||||
|
test_counted_node_map = {};
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -462,7 +478,7 @@ namespace {
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
emplace_map_key_value,
|
emplace_map_key_value,
|
||||||
((test_counted_flat_map))
|
((test_counted_flat_map)(test_counted_node_map))
|
||||||
((copy)(move))
|
((copy)(move))
|
||||||
((counted_key_checker)(converting_key_checker))
|
((counted_key_checker)(converting_key_checker))
|
||||||
((counted_value_checker)(converting_value_checker))
|
((counted_value_checker)(converting_value_checker))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
test::seed_t initialize_seed{1634048962};
|
test::seed_t initialize_seed{1634048962};
|
||||||
|
|
||||||
@ -20,28 +22,38 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST (simple_map_equality) {
|
template <class X>
|
||||||
using allocator_type = map_type::allocator_type;
|
void simple_map_equality(X*)
|
||||||
|
{
|
||||||
|
using allocator_type = typename X::allocator_type;
|
||||||
|
|
||||||
{
|
{
|
||||||
map_type x1(
|
X x1(
|
||||||
{{1, 11}, {2, 22}}, 0, hasher(1), key_equal(2), allocator_type(3));
|
{{1, 11}, {2, 22}}, 0, hasher(1), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
map_type x2(
|
X x2(
|
||||||
{{1, 11}, {2, 22}}, 0, hasher(2), key_equal(2), allocator_type(3));
|
{{1, 11}, {2, 22}}, 0, hasher(2), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
map_type x3(
|
X x3(
|
||||||
{{1, 11}, {2, 23}}, 0, hasher(2), key_equal(2), allocator_type(3));
|
{{1, 11}, {2, 23}}, 0, hasher(2), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
map_type x4({{1, 11}}, 0, hasher(2), key_equal(2), allocator_type(3));
|
X x4({{1, 11}}, 0, hasher(2), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST_EQ(x1.size(), x2.size());
|
BOOST_TEST_EQ(x1.size(), x2.size());
|
||||||
BOOST_TEST(x1 == x2);
|
BOOST_TEST(x1 == x2);
|
||||||
@ -57,17 +69,19 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST (simple_set_equality) {
|
template <class X>
|
||||||
using allocator_type = set_type::allocator_type;
|
void simple_set_equality(X*)
|
||||||
|
{
|
||||||
|
using allocator_type = typename X::allocator_type;
|
||||||
|
|
||||||
{
|
{
|
||||||
set_type x1(
|
X x1(
|
||||||
{1, 2}, 0, hasher(1), key_equal(2), allocator_type(3));
|
{1, 2}, 0, hasher(1), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
set_type x2(
|
X x2(
|
||||||
{1, 2}, 0, hasher(2), key_equal(2), allocator_type(3));
|
{1, 2}, 0, hasher(2), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
set_type x3({1}, 0, hasher(2), key_equal(2), allocator_type(3));
|
X x3({1}, 0, hasher(2), key_equal(2), allocator_type(3));
|
||||||
|
|
||||||
BOOST_TEST_EQ(x1.size(), x2.size());
|
BOOST_TEST_EQ(x1.size(), x2.size());
|
||||||
BOOST_TEST(x1 == x2);
|
BOOST_TEST(x1 == x2);
|
||||||
@ -165,9 +179,17 @@ namespace {
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
UNORDERED_TEST(
|
||||||
|
simple_map_equality,
|
||||||
|
((test_map)(test_node_map)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
simple_set_equality,
|
||||||
|
((test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert_and_compare,
|
insert_and_compare,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -439,11 +441,17 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii>* node_map;
|
||||||
boost::unordered::concurrent_flat_set<raii>* set;
|
boost::unordered::concurrent_flat_set<raii>* set;
|
||||||
|
boost::unordered::concurrent_node_set<raii>* node_set;
|
||||||
boost::unordered::concurrent_flat_map<raii, raii, transp_hash,
|
boost::unordered::concurrent_flat_map<raii, raii, transp_hash,
|
||||||
transp_key_equal>* transparent_map;
|
transp_key_equal>* transparent_map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, transp_hash,
|
||||||
|
transp_key_equal>* transparent_node_map;
|
||||||
boost::unordered::concurrent_flat_set<raii, transp_hash,
|
boost::unordered::concurrent_flat_set<raii, transp_hash,
|
||||||
transp_key_equal>* transparent_set;
|
transp_key_equal>* transparent_set;
|
||||||
|
boost::unordered::concurrent_node_set<raii, transp_hash,
|
||||||
|
transp_key_equal>* transparent_node_set;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -454,14 +462,14 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
erase,
|
erase,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((lvalue_eraser)(lvalue_eraser_if)(erase_if)(free_fn_erase_if)(erase_if_exec_policy))
|
((lvalue_eraser)(lvalue_eraser_if)(erase_if)(free_fn_erase_if)(erase_if_exec_policy))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
erase,
|
erase,
|
||||||
((transparent_map)(transparent_set))
|
((transparent_map)(transparent_node_map)(transparent_set)(transparent_node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((transp_lvalue_eraser)(transp_lvalue_eraser_if)(erase_if_exec_policy))
|
((transp_lvalue_eraser)(transp_lvalue_eraser_if)(erase_if_exec_policy))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
using hasher = stateful_hash;
|
using hasher = stateful_hash;
|
||||||
using key_equal = stateful_key_equal;
|
using key_equal = stateful_key_equal;
|
||||||
@ -14,11 +16,19 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
std::initializer_list<map_type::value_type> map_init_list{
|
std::initializer_list<map_type::value_type> map_init_list{
|
||||||
{raii{0}, raii{0}},
|
{raii{0}, raii{0}},
|
||||||
@ -71,7 +81,9 @@ std::initializer_list<set_type::value_type> set_init_list{
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
||||||
|
auto test_node_map_and_init_list=std::make_pair(test_node_map,map_init_list);
|
||||||
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
||||||
|
auto test_node_set_and_init_list=std::make_pair(test_node_set,set_init_list);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
test::seed_t initialize_seed(1794114520);
|
test::seed_t initialize_seed(1794114520);
|
||||||
@ -206,19 +218,20 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
copy_assign,
|
copy_assign,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((exception_value_type_generator_factory))
|
((exception_value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
move_assign,
|
move_assign,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((exception_value_type_generator_factory))
|
((exception_value_type_generator_factory))
|
||||||
((default_generator)(sequential)))
|
((default_generator)(sequential)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
intializer_list_assign,
|
intializer_list_assign,
|
||||||
((test_map_and_init_list)(test_set_and_init_list)))
|
((test_map_and_init_list)(test_node_map_and_init_list)
|
||||||
|
(test_set_and_init_list)(test_node_set_and_init_list)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
using hasher = stateful_hash;
|
using hasher = stateful_hash;
|
||||||
using key_equal = stateful_key_equal;
|
using key_equal = stateful_key_equal;
|
||||||
@ -14,11 +16,19 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
std::initializer_list<map_type::value_type> map_init_list{
|
std::initializer_list<map_type::value_type> map_init_list{
|
||||||
{raii{0}, raii{0}},
|
{raii{0}, raii{0}},
|
||||||
@ -71,7 +81,9 @@ std::initializer_list<set_type::value_type> set_init_list{
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
auto test_map_and_init_list=std::make_pair(test_map,map_init_list);
|
||||||
|
auto test_node_map_and_init_list=std::make_pair(test_node_map,map_init_list);
|
||||||
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
auto test_set_and_init_list=std::make_pair(test_set,set_init_list);
|
||||||
|
auto test_node_set_and_init_list=std::make_pair(test_node_set,set_init_list);
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
test::seed_t initialize_seed(795610904);
|
test::seed_t initialize_seed(795610904);
|
||||||
@ -339,29 +351,30 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
bucket_constructor,
|
bucket_constructor,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
iterator_range,
|
iterator_range,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((exception_value_type_generator_factory))
|
((exception_value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
copy_constructor,
|
copy_constructor,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((exception_value_type_generator_factory))
|
((exception_value_type_generator_factory))
|
||||||
((default_generator)(sequential)))
|
((default_generator)(sequential)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
move_constructor,
|
move_constructor,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((exception_value_type_generator_factory))
|
((exception_value_type_generator_factory))
|
||||||
((default_generator)(sequential)))
|
((default_generator)(sequential)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
initializer_list_bucket_count,
|
initializer_list_bucket_count,
|
||||||
((test_map_and_init_list)(test_set_and_init_list)))
|
((test_map_and_init_list)(test_node_map_and_init_list)
|
||||||
|
(test_set_and_init_list)(test_node_set_and_init_list)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -283,8 +285,12 @@ namespace {
|
|||||||
|
|
||||||
boost::unordered::concurrent_flat_map<raii, raii, stateful_hash,
|
boost::unordered::concurrent_flat_map<raii, raii, stateful_hash,
|
||||||
stateful_key_equal, stateful_allocator<std::pair<raii const, raii> > >* map;
|
stateful_key_equal, stateful_allocator<std::pair<raii const, raii> > >* map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, stateful_hash,
|
||||||
|
stateful_key_equal, stateful_allocator<std::pair<raii const, raii> > >* node_map;
|
||||||
boost::unordered::concurrent_flat_set<raii, stateful_hash,
|
boost::unordered::concurrent_flat_set<raii, stateful_hash,
|
||||||
stateful_key_equal, stateful_allocator<raii> >* set;
|
stateful_key_equal, stateful_allocator<raii> >* set;
|
||||||
|
boost::unordered::concurrent_node_set<raii, stateful_hash,
|
||||||
|
stateful_key_equal, stateful_allocator<raii> >* node_set;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -295,7 +301,7 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
erase,
|
erase,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((exception_value_type_generator_factory)
|
((exception_value_type_generator_factory)
|
||||||
(exception_init_type_generator_factory))
|
(exception_init_type_generator_factory))
|
||||||
((lvalue_eraser)(lvalue_eraser_if)(erase_if)(free_fn_erase_if))
|
((lvalue_eraser)(lvalue_eraser_if)(erase_if)(free_fn_erase_if))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -153,7 +155,15 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_GT(raii::copy_constructor, 0u);
|
BOOST_TEST_GT(raii::copy_constructor, 0u);
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
|
||||||
|
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::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
} lvalue_insert_or_assign_copy_assign;
|
} lvalue_insert_or_assign_copy_assign;
|
||||||
@ -198,7 +208,7 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_GT(raii::copy_constructor, 0u);
|
BOOST_TEST_GT(raii::copy_constructor, 0u);
|
||||||
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
BOOST_TEST_GT(raii::move_constructor, 0u);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
} rvalue_insert_or_assign_copy_assign;
|
} rvalue_insert_or_assign_copy_assign;
|
||||||
@ -249,8 +259,15 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_GT(num_inserts, 0u);
|
BOOST_TEST_GT(num_inserts, 0u);
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
// don't check move construction count here because of rehashing
|
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
} lvalue_insert_or_cvisit;
|
} lvalue_insert_or_cvisit;
|
||||||
@ -288,8 +305,14 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
|
|
||||||
// don't check move construction count here because of rehashing
|
if (is_container_node_based<X>::value) {
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
} lvalue_insert_or_visit;
|
} lvalue_insert_or_visit;
|
||||||
@ -426,8 +449,12 @@ namespace {
|
|||||||
|
|
||||||
boost::unordered::concurrent_flat_map<raii, raii, stateful_hash,
|
boost::unordered::concurrent_flat_map<raii, raii, stateful_hash,
|
||||||
stateful_key_equal, stateful_allocator<std::pair<raii const, raii> > >* map;
|
stateful_key_equal, stateful_allocator<std::pair<raii const, raii> > >* map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, stateful_hash,
|
||||||
|
stateful_key_equal, stateful_allocator<std::pair<raii const, raii> > >* node_map;
|
||||||
boost::unordered::concurrent_flat_set<raii, stateful_hash,
|
boost::unordered::concurrent_flat_set<raii, stateful_hash,
|
||||||
stateful_key_equal, stateful_allocator<raii> >* set;
|
stateful_key_equal, stateful_allocator<raii> >* set;
|
||||||
|
boost::unordered::concurrent_node_set<raii, stateful_hash,
|
||||||
|
stateful_key_equal, stateful_allocator<raii> >* node_set;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -438,7 +465,7 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert,
|
insert,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((exception_value_type_generator_factory)
|
((exception_value_type_generator_factory)
|
||||||
(exception_init_type_generator_factory))
|
(exception_init_type_generator_factory))
|
||||||
((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter)
|
((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter)
|
||||||
@ -450,7 +477,7 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert,
|
insert,
|
||||||
((map))
|
((map)(node_map))
|
||||||
((exception_init_type_generator_factory))
|
((exception_init_type_generator_factory))
|
||||||
((lvalue_insert_or_assign_copy_assign)(lvalue_insert_or_assign_move_assign)
|
((lvalue_insert_or_assign_copy_assign)(lvalue_insert_or_assign_move_assign)
|
||||||
(rvalue_insert_or_assign_copy_assign)(rvalue_insert_or_assign_move_assign))
|
(rvalue_insert_or_assign_copy_assign)(rvalue_insert_or_assign_move_assign))
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -16,11 +18,19 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
test::seed_t initialize_seed(223333016);
|
test::seed_t initialize_seed(223333016);
|
||||||
@ -79,7 +89,7 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
merge,
|
merge,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((exception_value_type_generator_factory))
|
((exception_value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// Copyright 2024 Joaquin M Lopez Muoz.
|
// Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
// file LICENSE_1_0.txt or copy at htT://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#define BOOST_UNORDERED_CFOA_TESTS
|
#define BOOST_UNORDERED_CFOA_TESTS
|
||||||
#include "../unordered/explicit_alloc_ctor_tests.cpp"
|
#include "../unordered/explicit_alloc_ctor_tests.cpp"
|
||||||
|
162
test/cfoa/extract_insert_tests.cpp
Normal file
162
test/cfoa/extract_insert_tests.cpp
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
// Copyright (C) 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)
|
||||||
|
|
||||||
|
#include "helpers.hpp"
|
||||||
|
|
||||||
|
#include <boost/assert.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
|
using hasher = stateful_hash;
|
||||||
|
using key_equal = stateful_key_equal;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
node_map_type* test_node_map;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
template <class X, class GF>
|
||||||
|
void extract_insert_tests(X*, GF gen_factory)
|
||||||
|
{
|
||||||
|
using value_type = typename X::value_type;
|
||||||
|
using allocator_type = typename X::allocator_type;
|
||||||
|
|
||||||
|
// set visit is always const access
|
||||||
|
using arg_visit_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;
|
||||||
|
|
||||||
|
test::random_generator rg = test::sequential;
|
||||||
|
auto gen = gen_factory.template get<X>();
|
||||||
|
auto values = make_random_values(1024 * 16, [&] { return gen(rg); });
|
||||||
|
|
||||||
|
|
||||||
|
X in(0,hasher(1),key_equal(2), allocator_type(3));
|
||||||
|
std::vector<X> out(2,in);
|
||||||
|
for(std::size_t i = 0; i < values.size(); ++i) {
|
||||||
|
in.insert(values[i]);
|
||||||
|
out[i % 3 == 0? 0 : 1].insert(values[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
raii::reset_counts();
|
||||||
|
|
||||||
|
thread_runner(values, [&](boost::span<value_type> s) {
|
||||||
|
std::size_t br1 = 0, br2 = 0, br3 = 0;
|
||||||
|
|
||||||
|
for(auto const& v: s) {
|
||||||
|
typename X::node_type nh;
|
||||||
|
|
||||||
|
while (nh.empty()) {
|
||||||
|
switch (br1++ % 3) {
|
||||||
|
case 0:
|
||||||
|
nh = in.extract(test::get_key<X>(v));
|
||||||
|
BOOST_ASSERT(!nh.empty());
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
nh = in.extract_if(
|
||||||
|
test::get_key<X>(v), [&](arg_visit_type& v2) {
|
||||||
|
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||||
|
(void)v2;
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
BOOST_ASSERT(nh.empty());
|
||||||
|
break;
|
||||||
|
case 2: default:
|
||||||
|
nh = in.extract_if(
|
||||||
|
test::get_key<X>(v), [&](arg_visit_type& v2) {
|
||||||
|
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||||
|
(void)v2;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
BOOST_ASSERT(!nh.empty());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(nh.get_allocator() == in.get_allocator());
|
||||||
|
|
||||||
|
while (!nh.empty()) {
|
||||||
|
auto& o = out[br2++ % out.size()];
|
||||||
|
typename X::insert_return_type r;
|
||||||
|
switch (br3++ % 3) {
|
||||||
|
case 0:
|
||||||
|
r = o.insert(std::move(nh));
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
r = o.insert_or_visit(
|
||||||
|
std::move(nh), [&](arg_visit_type& v2) {
|
||||||
|
BOOST_ASSERT(test::get_key<X>(v) == test::get_key<X>(v2));
|
||||||
|
(void)v2;
|
||||||
|
});
|
||||||
|
break;
|
||||||
|
case 2: default:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
BOOST_ASSERT(r.inserted || !r.node.empty());
|
||||||
|
nh = std::move(r.node);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
BOOST_TEST_EQ(in.size(), 0u);
|
||||||
|
BOOST_TEST_EQ(out[0].size() + out[1].size(), 2 * values.size());
|
||||||
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
|
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||||
|
BOOST_TEST_EQ(raii::destructor, 0u);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class X>
|
||||||
|
void insert_empty_node_tests(X*)
|
||||||
|
{
|
||||||
|
using value_type = typename X::value_type;
|
||||||
|
using node_type = typename X::node_type ;
|
||||||
|
|
||||||
|
X x;
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
auto r = x.insert(std::move(nh));
|
||||||
|
BOOST_TEST(!r.inserted);
|
||||||
|
BOOST_TEST(r.node.empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
auto r = x.insert_or_visit(std::move(nh), [](value_type const&) {});
|
||||||
|
BOOST_TEST(!r.inserted);
|
||||||
|
BOOST_TEST(r.node.empty());
|
||||||
|
}
|
||||||
|
{
|
||||||
|
node_type nh;
|
||||||
|
auto r = x.insert_or_cvisit(std::move(nh), [](value_type const&) {});
|
||||||
|
BOOST_TEST(!r.inserted);
|
||||||
|
BOOST_TEST(r.node.empty());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
UNORDERED_TEST(
|
||||||
|
extract_insert_tests,
|
||||||
|
((test_node_map)(test_node_set))
|
||||||
|
((value_type_generator_factory)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
insert_empty_node_tests,
|
||||||
|
((test_node_map)(test_node_set)))
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RUN_TESTS()
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
#include <boost/config/workaround.hpp>
|
#include <boost/config/workaround.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
|
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set_fwd.hpp>
|
#include <boost/unordered/concurrent_flat_set_fwd.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map_fwd.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set_fwd.hpp>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
|
|
||||||
test::seed_t initialize_seed{32304628};
|
test::seed_t initialize_seed{32304628};
|
||||||
@ -36,6 +38,27 @@ bool unequal_call(boost::unordered::concurrent_flat_map<T, T>& x1,
|
|||||||
return x1 != x2;
|
return x1 != x2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void swap_call(boost::unordered::concurrent_node_map<T, T>& x1,
|
||||||
|
boost::unordered::concurrent_node_map<T, T>& x2)
|
||||||
|
{
|
||||||
|
swap(x1, x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool equal_call(boost::unordered::concurrent_node_map<T, T>& x1,
|
||||||
|
boost::unordered::concurrent_node_map<T, T>& x2)
|
||||||
|
{
|
||||||
|
return x1 == x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool unequal_call(boost::unordered::concurrent_node_map<T, T>& x1,
|
||||||
|
boost::unordered::concurrent_node_map<T, T>& x2)
|
||||||
|
{
|
||||||
|
return x1 != x2;
|
||||||
|
}
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
void swap_call(boost::unordered::concurrent_flat_set<T>& x1,
|
void swap_call(boost::unordered::concurrent_flat_set<T>& x1,
|
||||||
boost::unordered::concurrent_flat_set<T>& x2)
|
boost::unordered::concurrent_flat_set<T>& x2)
|
||||||
@ -57,14 +80,41 @@ bool unequal_call(boost::unordered::concurrent_flat_set<T>& x1,
|
|||||||
return x1 != x2;
|
return x1 != x2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
void swap_call(boost::unordered::concurrent_node_set<T>& x1,
|
||||||
|
boost::unordered::concurrent_node_set<T>& x2)
|
||||||
|
{
|
||||||
|
swap(x1, x2);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool equal_call(boost::unordered::concurrent_node_set<T>& x1,
|
||||||
|
boost::unordered::concurrent_node_set<T>& x2)
|
||||||
|
{
|
||||||
|
return x1 == x2;
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
bool unequal_call(boost::unordered::concurrent_node_set<T>& x1,
|
||||||
|
boost::unordered::concurrent_node_set<T>& x2)
|
||||||
|
{
|
||||||
|
return x1 != x2;
|
||||||
|
}
|
||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
using map_type = boost::unordered::concurrent_flat_map<int, int>;
|
using map_type = boost::unordered::concurrent_flat_map<int, int>;
|
||||||
using set_type = boost::unordered::concurrent_flat_map<int, int>;
|
using node_map_type = boost::unordered::concurrent_node_map<int, int>;
|
||||||
|
using set_type = boost::unordered::concurrent_flat_set<int>;
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<int>;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
template <typename X>
|
template <typename X>
|
||||||
void fwd_swap_call(X*)
|
void fwd_swap_call(X*)
|
||||||
@ -106,19 +156,19 @@ void max_size(X*)
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
fwd_swap_call,
|
fwd_swap_call,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
fwd_equal_call,
|
fwd_equal_call,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
fwd_unequal_call,
|
fwd_unequal_call,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
max_size,
|
max_size,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Copyright (C) 2024 Braden Ganetsky
|
// Copyright (C) 2024 Braden Ganetsky
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
@ -147,9 +147,15 @@ public:
|
|||||||
cfoa_ptr(std::nullptr_t) : p_(nullptr){};
|
cfoa_ptr(std::nullptr_t) : p_(nullptr){};
|
||||||
template <class U> using rebind = cfoa_ptr<U>;
|
template <class U> using rebind = cfoa_ptr<U>;
|
||||||
|
|
||||||
|
operator bool() const { return !!p_; }
|
||||||
|
|
||||||
|
template <typename Q = T>
|
||||||
|
Q& operator*() const noexcept { return *p_; }
|
||||||
|
|
||||||
T* operator->() const noexcept { return p_; }
|
T* operator->() const noexcept { return p_; }
|
||||||
|
|
||||||
static cfoa_ptr<T> pointer_to(element_type& r) { return {std::addressof(r)}; }
|
template<typename Q = T>
|
||||||
|
static cfoa_ptr<Q> pointer_to(Q& r) { return {std::addressof(r)}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T> struct stateful_allocator
|
template <class T> struct stateful_allocator
|
||||||
@ -670,4 +676,17 @@ public:
|
|||||||
fancy_allocator& operator=(fancy_allocator const&) { return *this; }
|
fancy_allocator& operator=(fancy_allocator const&) { return *this; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace boost {
|
||||||
|
template <> struct pointer_traits<void_ptr>
|
||||||
|
{
|
||||||
|
template <class U> struct rebind_to
|
||||||
|
{
|
||||||
|
typedef ptr<U> type;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<class U>
|
||||||
|
using rebind=typename rebind_to<U>::type;
|
||||||
|
};
|
||||||
|
} // namespace boost
|
||||||
|
|
||||||
#endif // BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP
|
#endif // BOOST_UNORDERED_TEST_CFOA_HELPERS_HPP
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -8,6 +8,8 @@
|
|||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -179,8 +181,15 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, 2 * x.size());
|
||||||
// don't check move construction count here because of rehashing
|
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::copy_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
||||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
@ -198,7 +207,14 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
|
||||||
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, x.size());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
||||||
}
|
}
|
||||||
@ -216,7 +232,14 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
|
||||||
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, x.size());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
||||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
@ -234,7 +257,14 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||||
BOOST_TEST_GE(raii::move_constructor, 2 * x.size());
|
|
||||||
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, 2 * x.size());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BOOST_TEST_GE(raii::move_constructor, 2 * x.size()); // rehashing
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
||||||
}
|
}
|
||||||
@ -260,7 +290,14 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
|
||||||
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, 0u); // rehashing
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::copy_assignment, values.size() - x.size());
|
||||||
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
BOOST_TEST_EQ(raii::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
@ -284,7 +321,14 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||||
BOOST_TEST_GT(raii::move_constructor, 2 * x.size()); // rehashing
|
|
||||||
|
if (is_container_node_based<X>::value) {
|
||||||
|
BOOST_TEST_EQ(raii::move_constructor, x.size());
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BOOST_TEST_GT(raii::move_constructor, x.size()); // rehashing
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
BOOST_TEST_EQ(raii::move_assignment, values.size() - x.size());
|
||||||
}
|
}
|
||||||
@ -319,8 +363,15 @@ namespace {
|
|||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_EQ(
|
BOOST_TEST_EQ(
|
||||||
raii::copy_constructor, value_type_cardinality * x.size());
|
raii::copy_constructor, value_type_cardinality * x.size());
|
||||||
// don't check move construction count here because of rehashing
|
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
} lvalue_insert_or_cvisit;
|
} lvalue_insert_or_cvisit;
|
||||||
@ -360,8 +411,15 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
BOOST_TEST_EQ(raii::default_constructor, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, value_type_cardinality * x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, value_type_cardinality * x.size());
|
||||||
// don't check move construction count here because of rehashing
|
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::move_assignment, 0u);
|
||||||
}
|
}
|
||||||
} lvalue_insert_or_visit;
|
} lvalue_insert_or_visit;
|
||||||
@ -665,12 +723,14 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UNORDERED_AUTO_TEST (insert_sfinae_test) {
|
|
||||||
|
template <class X>
|
||||||
|
void insert_map_sfinae_test(X*)
|
||||||
|
{
|
||||||
// mostly a compile-time tests to ensure that there's no ambiguity when a
|
// mostly a compile-time tests to ensure that there's no ambiguity when a
|
||||||
// user does this
|
// user does this
|
||||||
using value_type =
|
using value_type = typename X::value_type;
|
||||||
typename boost::unordered::concurrent_flat_map<raii, raii>::value_type;
|
X x;
|
||||||
boost::unordered::concurrent_flat_map<raii, raii> x;
|
|
||||||
x.insert({1, 2});
|
x.insert({1, 2});
|
||||||
|
|
||||||
x.insert_or_visit({2, 3}, [](value_type&) {});
|
x.insert_or_visit({2, 3}, [](value_type&) {});
|
||||||
@ -684,11 +744,23 @@ namespace {
|
|||||||
std::equal_to<raii>, fancy_allocator<std::pair<raii const, raii> > >*
|
std::equal_to<raii>, fancy_allocator<std::pair<raii const, raii> > >*
|
||||||
fancy_map;
|
fancy_map;
|
||||||
|
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii>* node_map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, transp_hash,
|
||||||
|
transp_key_equal>* trans_node_map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, boost::hash<raii>,
|
||||||
|
std::equal_to<raii>, fancy_allocator<std::pair<raii const, raii> > >*
|
||||||
|
fancy_node_map;
|
||||||
|
|
||||||
boost::unordered::concurrent_flat_set<raii>* set;
|
boost::unordered::concurrent_flat_set<raii>* set;
|
||||||
boost::unordered::concurrent_flat_set<raii, boost::hash<raii>,
|
boost::unordered::concurrent_flat_set<raii, boost::hash<raii>,
|
||||||
std::equal_to<raii>, fancy_allocator<std::pair<raii const, raii> > >*
|
std::equal_to<raii>, fancy_allocator<raii> >*
|
||||||
fancy_set;
|
fancy_set;
|
||||||
|
|
||||||
|
boost::unordered::concurrent_node_set<raii>* node_set;
|
||||||
|
boost::unordered::concurrent_node_set<raii, boost::hash<raii>,
|
||||||
|
std::equal_to<raii>, fancy_allocator<raii> >*
|
||||||
|
fancy_node_set;
|
||||||
|
|
||||||
std::initializer_list<std::pair<raii const, raii> > map_init_list{
|
std::initializer_list<std::pair<raii const, raii> > map_init_list{
|
||||||
{raii{0}, raii{0}},
|
{raii{0}, raii{0}},
|
||||||
{raii{1}, raii{1}},
|
{raii{1}, raii{1}},
|
||||||
@ -740,7 +812,9 @@ namespace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
auto map_and_init_list=std::make_pair(map,map_init_list);
|
auto map_and_init_list=std::make_pair(map,map_init_list);
|
||||||
|
auto node_map_and_init_list=std::make_pair(node_map,map_init_list);
|
||||||
auto set_and_init_list=std::make_pair(set,set_init_list);
|
auto set_and_init_list=std::make_pair(set,set_init_list);
|
||||||
|
auto node_set_and_init_list=std::make_pair(node_set,set_init_list);
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -751,11 +825,12 @@ using test::sequential;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert_initializer_list,
|
insert_initializer_list,
|
||||||
((map_and_init_list)(set_and_init_list)))
|
((map_and_init_list)(node_map_and_init_list)(set_and_init_list)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert,
|
insert,
|
||||||
((map)(fancy_map)(set)(fancy_set))
|
((map)(fancy_map)(node_map)(fancy_node_map)
|
||||||
|
(set)(fancy_set)(node_set)(fancy_node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter)
|
((lvalue_inserter)(rvalue_inserter)(iterator_range_inserter)
|
||||||
(norehash_lvalue_inserter)(norehash_rvalue_inserter)
|
(norehash_lvalue_inserter)(norehash_rvalue_inserter)
|
||||||
@ -766,7 +841,7 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert,
|
insert,
|
||||||
((map))
|
((map)(node_map))
|
||||||
((init_type_generator_factory))
|
((init_type_generator_factory))
|
||||||
((lvalue_insert_or_assign_copy_assign)(lvalue_insert_or_assign_move_assign)
|
((lvalue_insert_or_assign_copy_assign)(lvalue_insert_or_assign_move_assign)
|
||||||
(rvalue_insert_or_assign_copy_assign)(rvalue_insert_or_assign_move_assign))
|
(rvalue_insert_or_assign_copy_assign)(rvalue_insert_or_assign_move_assign))
|
||||||
@ -774,10 +849,14 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert,
|
insert,
|
||||||
((trans_map))
|
((trans_map)(trans_node_map))
|
||||||
((init_type_generator_factory))
|
((init_type_generator_factory))
|
||||||
((trans_insert_or_assign_copy_assign)(trans_insert_or_assign_move_assign))
|
((trans_insert_or_assign_copy_assign)(trans_insert_or_assign_move_assign))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
insert_map_sfinae_test,
|
||||||
|
((map)(node_map)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
RUN_TESTS()
|
RUN_TESTS()
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
test::seed_t initialize_seed{402031699};
|
test::seed_t initialize_seed{402031699};
|
||||||
|
|
||||||
@ -23,19 +25,38 @@ using map2_type = boost::unordered::concurrent_flat_map<raii, raii,
|
|||||||
std::hash<raii>, std::equal_to<raii>,
|
std::hash<raii>, std::equal_to<raii>,
|
||||||
stateful_allocator<std::pair<raii const, raii> > >;
|
stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii,
|
||||||
|
hasher, key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
using node_map2_type = boost::unordered::concurrent_node_map<raii, raii,
|
||||||
|
std::hash<raii>, std::equal_to<raii>,
|
||||||
|
stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
using set2_type = boost::unordered::concurrent_flat_set<raii, std::hash<raii>,
|
using set2_type = boost::unordered::concurrent_flat_set<raii, std::hash<raii>,
|
||||||
std::equal_to<raii>, stateful_allocator<raii> >;
|
std::equal_to<raii>, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
using node_set2_type = boost::unordered::concurrent_node_set<raii, std::hash<raii>,
|
||||||
|
std::equal_to<raii>, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
map2_type* test_map2;
|
map2_type* test_map2;
|
||||||
auto test_maps=std::make_pair(test_map,test_map2);
|
auto test_maps=std::make_pair(test_map,test_map2);
|
||||||
|
|
||||||
|
node_map_type* test_node_map;
|
||||||
|
node_map2_type* test_node_map2;
|
||||||
|
auto test_node_maps=std::make_pair(test_node_map,test_node_map2);
|
||||||
|
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
set2_type* test_set2;
|
set2_type* test_set2;
|
||||||
auto test_sets=std::make_pair(test_set,test_set2);
|
auto test_sets=std::make_pair(test_set,test_set2);
|
||||||
|
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
node_set2_type* test_node_set2;
|
||||||
|
auto test_node_sets=std::make_pair(test_node_set,test_node_set2);
|
||||||
|
|
||||||
struct
|
struct
|
||||||
{
|
{
|
||||||
template <class X1, class X2>
|
template <class X1, class X2>
|
||||||
@ -91,9 +112,16 @@ namespace {
|
|||||||
});
|
});
|
||||||
|
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, old_cc + expected_copies);
|
BOOST_TEST_EQ(raii::copy_constructor, old_cc + expected_copies);
|
||||||
BOOST_TEST_EQ(
|
|
||||||
raii::move_constructor,
|
if (is_container_node_based<X>::value) {
|
||||||
value_type_cardinality * reference_cont.size());
|
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
raii::move_constructor,
|
||||||
|
value_type_cardinality * reference_cont.size());
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_EQ(+num_merged, reference_cont.size());
|
BOOST_TEST_EQ(+num_merged, reference_cont.size());
|
||||||
|
|
||||||
test_fuzzy_matches_reference(x, reference_cont, rg);
|
test_fuzzy_matches_reference(x, reference_cont, rg);
|
||||||
@ -210,10 +238,17 @@ namespace {
|
|||||||
t3.join();
|
t3.join();
|
||||||
|
|
||||||
if (num_merges > 0) {
|
if (num_merges > 0) {
|
||||||
// num merges is 0 most commonly in the cast of the limited_range
|
|
||||||
// generator as both maps will contains keys from 0 to 99
|
if (is_container_node_based<X>::value) {
|
||||||
BOOST_TEST_EQ(
|
BOOST_TEST_EQ(raii::move_constructor, 0u);
|
||||||
+raii::move_constructor, value_type_cardinality * num_merges);
|
}
|
||||||
|
else{
|
||||||
|
// num merges is 0 most commonly in the cast of the limited_range
|
||||||
|
// generator as both maps will contains keys from 0 to 99
|
||||||
|
BOOST_TEST_EQ(
|
||||||
|
raii::move_constructor, value_type_cardinality * num_merges);
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_TEST_GE(call_count, 1u);
|
BOOST_TEST_GE(call_count, 1u);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,14 +264,14 @@ namespace {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
merge_tests,
|
merge_tests,
|
||||||
((test_maps)(test_sets))
|
((test_maps)(test_node_maps)(test_sets)(test_node_sets))
|
||||||
((lvalue_merge)(rvalue_merge))
|
((lvalue_merge)(rvalue_merge))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert_and_merge_tests,
|
insert_and_merge_tests,
|
||||||
((test_maps)(test_sets))
|
((test_maps)(test_node_maps)(test_sets)(test_node_sets))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
6
test/cfoa/node_handle_allocator_tests.cpp
Normal file
6
test/cfoa/node_handle_allocator_tests.cpp
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
// Copyright 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)
|
||||||
|
|
||||||
|
#define BOOST_UNORDERED_CFOA_TESTS
|
||||||
|
#include "../unordered/node_handle_allocator_tests.cpp"
|
@ -5,4 +5,6 @@
|
|||||||
#define BOOST_UNORDERED_CFOA_TESTS
|
#define BOOST_UNORDERED_CFOA_TESTS
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
#include "../unordered/pmr_allocator_tests.cpp"
|
#include "../unordered/pmr_allocator_tests.cpp"
|
||||||
|
@ -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.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
@ -32,15 +32,21 @@ namespace boost {
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
#include <boost/core/lightweight_test.hpp>
|
#include <boost/core/lightweight_test.hpp>
|
||||||
|
|
||||||
using test::default_generator;
|
using test::default_generator;
|
||||||
|
|
||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii>;
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii>;
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii>;
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii>;
|
using set_type = boost::unordered::concurrent_flat_set<raii>;
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii>;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
template<typename F>
|
template<typename F>
|
||||||
void detect_reentrancy(F f)
|
void detect_reentrancy(F f)
|
||||||
@ -105,7 +111,7 @@ namespace {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
reentrancy_tests,
|
reentrancy_tests,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)))
|
((default_generator)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
using test::default_generator;
|
using test::default_generator;
|
||||||
using test::limited_range;
|
using test::limited_range;
|
||||||
@ -18,11 +20,19 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
map_type* test_map;
|
map_type* test_map;
|
||||||
|
node_map_type* test_node_map;
|
||||||
set_type* test_set;
|
set_type* test_set;
|
||||||
|
node_set_type* test_node_set;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
test::seed_t initialize_seed{748775921};
|
test::seed_t initialize_seed{748775921};
|
||||||
@ -187,15 +197,15 @@ namespace {
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
rehash_no_insert,
|
rehash_no_insert,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
reserve_no_insert,
|
reserve_no_insert,
|
||||||
((test_map)(test_set)))
|
((test_map)(test_node_map)(test_set)(test_node_set)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert_and_erase_with_rehash,
|
insert_and_erase_with_rehash,
|
||||||
((test_map)(test_set))
|
((test_map)(test_node_map)(test_set)(test_node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -12,6 +12,8 @@
|
|||||||
#include <boost/serialization/nvp.hpp>
|
#include <boost/serialization/nvp.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -70,11 +72,15 @@ namespace {
|
|||||||
|
|
||||||
boost::concurrent_flat_map<
|
boost::concurrent_flat_map<
|
||||||
test::object, test::object, test::hash, test::equal_to>* test_flat_map;
|
test::object, test::object, test::hash, test::equal_to>* test_flat_map;
|
||||||
|
boost::concurrent_node_map<
|
||||||
|
test::object, test::object, test::hash, test::equal_to>* test_node_map;
|
||||||
boost::concurrent_flat_set<
|
boost::concurrent_flat_set<
|
||||||
test::object, test::hash, test::equal_to>* test_flat_set;
|
test::object, test::hash, test::equal_to>* test_flat_set;
|
||||||
|
boost::concurrent_node_set<
|
||||||
|
test::object, test::hash, test::equal_to>* test_node_set;
|
||||||
|
|
||||||
UNORDERED_TEST(serialization_tests,
|
UNORDERED_TEST(serialization_tests,
|
||||||
((test_flat_map)(test_flat_set))
|
((test_flat_map)(test_node_map)(test_flat_set)(test_node_set))
|
||||||
((text_archive)(xml_archive))
|
((text_archive)(xml_archive))
|
||||||
((default_generator)))
|
((default_generator)))
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Joaquin M Lopez Muoz.
|
// Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
// Copyright (C) 2023 Joaquin M Lopez Munoz
|
// Copyright (C) 2023-2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,6 +7,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
test::seed_t initialize_seed{996130204};
|
test::seed_t initialize_seed{996130204};
|
||||||
|
|
||||||
@ -62,9 +64,15 @@ using key_equal = stateful_key_equal;
|
|||||||
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
using map_type = boost::unordered::concurrent_flat_map<raii, raii, hasher,
|
||||||
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
|
using node_map_type = boost::unordered::concurrent_node_map<raii, raii, hasher,
|
||||||
|
key_equal, stateful_allocator<std::pair<raii const, raii> > >;
|
||||||
|
|
||||||
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
using set_type = boost::unordered::concurrent_flat_set<raii, hasher,
|
||||||
key_equal, stateful_allocator<raii> >;
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
|
using node_set_type = boost::unordered::concurrent_node_set<raii, hasher,
|
||||||
|
key_equal, stateful_allocator<raii> >;
|
||||||
|
|
||||||
template <class T> struct is_nothrow_member_swappable
|
template <class T> struct is_nothrow_member_swappable
|
||||||
{
|
{
|
||||||
static bool const value =
|
static bool const value =
|
||||||
@ -293,21 +301,28 @@ namespace {
|
|||||||
map_type* map;
|
map_type* map;
|
||||||
replace_allocator<map_type, pocs_allocator>* pocs_map;
|
replace_allocator<map_type, pocs_allocator>* pocs_map;
|
||||||
|
|
||||||
|
node_map_type* node_map;
|
||||||
|
replace_allocator<node_map_type, pocs_allocator>* pocs_node_map;
|
||||||
|
|
||||||
set_type* set;
|
set_type* set;
|
||||||
replace_allocator<set_type, pocs_allocator>* pocs_set;
|
replace_allocator<set_type, pocs_allocator>* pocs_set;
|
||||||
|
|
||||||
|
node_set_type* node_set;
|
||||||
|
replace_allocator<node_set_type, pocs_allocator>* pocs_node_set;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
swap_tests,
|
swap_tests,
|
||||||
((map)(pocs_map)(set)(pocs_set))
|
((map)(pocs_map)(node_map)(pocs_node_map)
|
||||||
|
(set)(pocs_set)(node_set)(pocs_node_set))
|
||||||
((member_fn_swap)(free_fn_swap))
|
((member_fn_swap)(free_fn_swap))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(insert_and_swap,
|
UNORDERED_TEST(insert_and_swap,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((member_fn_swap)(free_fn_swap))
|
((member_fn_swap)(free_fn_swap))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
@ -1,10 +1,12 @@
|
|||||||
// Copyright (C) 2023 Christian Mazakas
|
// Copyright (C) 2023 Christian Mazakas
|
||||||
|
// Copyright (C) 2024 Joaquin M Lopez Munoz
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#include "helpers.hpp"
|
#include "helpers.hpp"
|
||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
|
|
||||||
@ -161,8 +163,15 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
// don't check move construction count here because of rehashing
|
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::move_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
}
|
}
|
||||||
@ -194,8 +203,15 @@ namespace {
|
|||||||
|
|
||||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
// don't check move construction count here because of rehashing
|
|
||||||
BOOST_TEST_GT(raii::move_constructor, 0u);
|
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::move_assignment, 0u);
|
||||||
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
BOOST_TEST_EQ(raii::copy_assignment, 0u);
|
||||||
}
|
}
|
||||||
@ -229,7 +245,12 @@ namespace {
|
|||||||
|
|
||||||
if (std::is_same<T, typename X::value_type>::value) {
|
if (std::is_same<T, typename X::value_type>::value) {
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GE(raii::move_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 {
|
} else {
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||||
@ -264,7 +285,12 @@ namespace {
|
|||||||
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
BOOST_TEST_EQ(raii::default_constructor, x.size());
|
||||||
if (std::is_same<T, typename X::value_type>::value) {
|
if (std::is_same<T, typename X::value_type>::value) {
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
BOOST_TEST_EQ(raii::copy_constructor, x.size());
|
||||||
BOOST_TEST_GE(raii::move_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 {
|
} else {
|
||||||
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
BOOST_TEST_EQ(raii::copy_constructor, 0u);
|
||||||
BOOST_TEST_GE(raii::move_constructor, x.size());
|
BOOST_TEST_GE(raii::move_constructor, x.size());
|
||||||
@ -367,6 +393,10 @@ namespace {
|
|||||||
boost::unordered::concurrent_flat_map<raii, raii, transp_hash,
|
boost::unordered::concurrent_flat_map<raii, raii, transp_hash,
|
||||||
transp_key_equal>* transp_map;
|
transp_key_equal>* transp_map;
|
||||||
|
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii>* node_map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, transp_hash,
|
||||||
|
transp_key_equal>* transp_node_map;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
using test::default_generator;
|
using test::default_generator;
|
||||||
@ -379,7 +409,7 @@ value_generator<std::pair<raii, raii> > init_type_generator;
|
|||||||
// clang-format off
|
// clang-format off
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
try_emplace,
|
try_emplace,
|
||||||
((map))
|
((map)(node_map))
|
||||||
((value_type_generator)(init_type_generator))
|
((value_type_generator)(init_type_generator))
|
||||||
((lvalue_try_emplacer)(norehash_lvalue_try_emplacer)
|
((lvalue_try_emplacer)(norehash_lvalue_try_emplacer)
|
||||||
(rvalue_try_emplacer)(norehash_rvalue_try_emplacer)
|
(rvalue_try_emplacer)(norehash_rvalue_try_emplacer)
|
||||||
@ -389,7 +419,7 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
try_emplace,
|
try_emplace,
|
||||||
((transp_map))
|
((transp_map)(transp_node_map))
|
||||||
((init_type_generator))
|
((init_type_generator))
|
||||||
((transp_try_emplace)(norehash_transp_try_emplace)
|
((transp_try_emplace)(norehash_transp_try_emplace)
|
||||||
(transp_try_emplace_or_cvisit)(transp_try_emplace_or_visit))
|
(transp_try_emplace_or_cvisit)(transp_try_emplace_or_visit))
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
|
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
|
||||||
#include <boost/compat/latch.hpp>
|
#include <boost/compat/latch.hpp>
|
||||||
#include <boost/core/ignore_unused.hpp>
|
#include <boost/core/ignore_unused.hpp>
|
||||||
@ -971,9 +973,15 @@ namespace {
|
|||||||
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
boost::unordered::concurrent_flat_map<raii, raii>* map;
|
||||||
boost::unordered::concurrent_flat_map<raii, raii, transp_hash,
|
boost::unordered::concurrent_flat_map<raii, raii, transp_hash,
|
||||||
transp_key_equal>* transp_map;
|
transp_key_equal>* transp_map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii>* node_map;
|
||||||
|
boost::unordered::concurrent_node_map<raii, raii, transp_hash,
|
||||||
|
transp_key_equal>* transp_node_map;
|
||||||
boost::unordered::concurrent_flat_set<raii>* set;
|
boost::unordered::concurrent_flat_set<raii>* set;
|
||||||
boost::unordered::concurrent_flat_set<raii, transp_hash,
|
boost::unordered::concurrent_flat_set<raii, transp_hash,
|
||||||
transp_key_equal>* transp_set;
|
transp_key_equal>* transp_set;
|
||||||
|
boost::unordered::concurrent_node_set<raii>* node_set;
|
||||||
|
boost::unordered::concurrent_node_set<raii, transp_hash,
|
||||||
|
transp_key_equal>* transp_node_set;
|
||||||
|
|
||||||
struct mutable_pair
|
struct mutable_pair
|
||||||
{
|
{
|
||||||
@ -1114,7 +1122,9 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
boost::concurrent_flat_set<
|
boost::concurrent_flat_set<
|
||||||
mutable_pair, mutable_pair_hash, mutable_pair_equal_to>* mutable_set;
|
mutable_pair, mutable_pair_hash, mutable_pair_equal_to>* mutable_set;
|
||||||
|
boost::concurrent_node_set<
|
||||||
|
mutable_pair, mutable_pair_hash, mutable_pair_equal_to>* mutable_node_set;
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
@ -1126,7 +1136,7 @@ using test::sequential;
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
visit,
|
visit,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((lvalue_visitor)(visit_all)(visit_while)(exec_policy_visit_all)
|
((lvalue_visitor)(visit_all)(visit_while)(exec_policy_visit_all)
|
||||||
(exec_policy_visit_while))
|
(exec_policy_visit_while))
|
||||||
@ -1134,28 +1144,29 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
visit,
|
visit,
|
||||||
((transp_map)(transp_set))
|
((transp_map)(transp_node_map)(transp_set)(transp_node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((transp_visitor))
|
((transp_visitor))
|
||||||
((default_generator)(sequential)(limited_range)))
|
((default_generator)(sequential)(limited_range)))
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
empty_visit,
|
empty_visit,
|
||||||
((map)(transp_map)(set)(transp_set))
|
((map)(transp_map)(node_map)(transp_node_map)
|
||||||
|
(set)(transp_set)(node_set)(transp_node_set))
|
||||||
((value_type_generator_factory)(init_type_generator_factory))
|
((value_type_generator_factory)(init_type_generator_factory))
|
||||||
((default_generator)(sequential)(limited_range))
|
((default_generator)(sequential)(limited_range))
|
||||||
)
|
)
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
insert_and_visit,
|
insert_and_visit,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((sequential))
|
((sequential))
|
||||||
)
|
)
|
||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
bulk_visit,
|
bulk_visit,
|
||||||
((map)(set))
|
((map)(node_map)(set)(node_set))
|
||||||
((regular_key_extract))
|
((regular_key_extract))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((sequential))
|
((sequential))
|
||||||
@ -1163,7 +1174,7 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
bulk_visit,
|
bulk_visit,
|
||||||
((transp_map)(transp_set))
|
((transp_map)(transp_node_map)(transp_set)(transp_node_set))
|
||||||
((transp_key_extract))
|
((transp_key_extract))
|
||||||
((value_type_generator_factory))
|
((value_type_generator_factory))
|
||||||
((sequential))
|
((sequential))
|
||||||
@ -1173,7 +1184,7 @@ UNORDERED_TEST(
|
|||||||
|
|
||||||
UNORDERED_TEST(
|
UNORDERED_TEST(
|
||||||
exclusive_access_set_visit,
|
exclusive_access_set_visit,
|
||||||
((mutable_set))
|
((mutable_set)(mutable_node_set))
|
||||||
)
|
)
|
||||||
|
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
@ -20,6 +20,8 @@
|
|||||||
#include <boost/interprocess/managed_shared_memory.hpp>
|
#include <boost/interprocess/managed_shared_memory.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/unordered/unordered_flat_map.hpp>
|
||||||
#include <boost/unordered/unordered_flat_set.hpp>
|
#include <boost/unordered/unordered_flat_set.hpp>
|
||||||
#include <boost/unordered/unordered_map.hpp>
|
#include <boost/unordered/unordered_map.hpp>
|
||||||
@ -61,8 +63,12 @@ template <class Tester> void visualization_test(Tester& tester)
|
|||||||
|
|
||||||
auto cfoa_flat_map_ptr = tester.template construct_map<boost::concurrent_flat_map>();
|
auto cfoa_flat_map_ptr = tester.template construct_map<boost::concurrent_flat_map>();
|
||||||
auto cfoa_flat_set_ptr = tester.template construct_set<boost::concurrent_flat_set>();
|
auto cfoa_flat_set_ptr = tester.template construct_set<boost::concurrent_flat_set>();
|
||||||
|
auto cfoa_node_map_ptr = tester.template construct_map<boost::concurrent_node_map>();
|
||||||
|
auto cfoa_node_set_ptr = tester.template construct_set<boost::concurrent_node_set>();
|
||||||
auto& cfoa_flat_map = *cfoa_flat_map_ptr;
|
auto& cfoa_flat_map = *cfoa_flat_map_ptr;
|
||||||
auto& cfoa_flat_set = *cfoa_flat_set_ptr;
|
auto& cfoa_flat_set = *cfoa_flat_set_ptr;
|
||||||
|
auto& cfoa_node_map = *cfoa_node_map_ptr;
|
||||||
|
auto& cfoa_node_set = *cfoa_node_set_ptr;
|
||||||
// clang-format on
|
// clang-format on
|
||||||
|
|
||||||
for (int i = 0; i < 5; ++i) {
|
for (int i = 0; i < 5; ++i) {
|
||||||
@ -75,6 +81,7 @@ template <class Tester> void visualization_test(Tester& tester)
|
|||||||
foa_flat_map.emplace(str, num);
|
foa_flat_map.emplace(str, num);
|
||||||
foa_node_map.emplace(str, num);
|
foa_node_map.emplace(str, num);
|
||||||
cfoa_flat_map.emplace(str, num);
|
cfoa_flat_map.emplace(str, num);
|
||||||
|
cfoa_node_map.emplace(str, num);
|
||||||
|
|
||||||
fca_set.emplace(str);
|
fca_set.emplace(str);
|
||||||
fca_multiset.emplace(str);
|
fca_multiset.emplace(str);
|
||||||
@ -82,6 +89,7 @@ template <class Tester> void visualization_test(Tester& tester)
|
|||||||
foa_flat_set.emplace(str);
|
foa_flat_set.emplace(str);
|
||||||
foa_node_set.emplace(str);
|
foa_node_set.emplace(str);
|
||||||
cfoa_flat_set.emplace(str);
|
cfoa_flat_set.emplace(str);
|
||||||
|
cfoa_node_set.emplace(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto fca_map_begin = fca_map.begin();
|
auto fca_map_begin = fca_map.begin();
|
||||||
@ -102,7 +110,7 @@ template <class Tester> void visualization_test(Tester& tester)
|
|||||||
auto foa_node_set_begin = foa_node_set.begin();
|
auto foa_node_set_begin = foa_node_set.begin();
|
||||||
auto foa_node_set_end = foa_node_set.end();
|
auto foa_node_set_end = foa_node_set.end();
|
||||||
|
|
||||||
use(cfoa_flat_map, cfoa_flat_set);
|
use(cfoa_flat_map, cfoa_flat_set, cfoa_node_map, cfoa_node_set);
|
||||||
use(fca_map_begin, fca_map_end, fca_multimap_begin, fca_multimap_end,
|
use(fca_map_begin, fca_map_end, fca_multimap_begin, fca_multimap_end,
|
||||||
fca_set_begin, fca_set_end, fca_multiset_begin, fca_multiset_end);
|
fca_set_begin, fca_set_end, fca_multiset_begin, fca_multiset_end);
|
||||||
use(foa_flat_map_begin, foa_flat_map_end, foa_flat_set_begin,
|
use(foa_flat_map_begin, foa_flat_map_end, foa_flat_set_begin,
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
// Copyright 2024 Joaquin M Lopez Muoz.
|
// Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
// file LICENSE_1_0.txt or copy at htT://www.boost.org/LICENSE_1_0.txt)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
#ifdef BOOST_UNORDERED_CFOA_TESTS
|
#ifdef BOOST_UNORDERED_CFOA_TESTS
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
#else
|
#else
|
||||||
#include "../helpers/unordered.hpp"
|
#include "../helpers/unordered.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "../helpers/helpers.hpp"
|
||||||
#include "../helpers/test.hpp"
|
#include "../helpers/test.hpp"
|
||||||
#include <boost/type_traits/make_void.hpp>
|
#include <boost/type_traits/make_void.hpp>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@ -62,7 +65,16 @@ template <class Container> void test_explicit_alloc_ctor_extract(
|
|||||||
template <class Container> void test_explicit_alloc_ctor_extract(
|
template <class Container> void test_explicit_alloc_ctor_extract(
|
||||||
Container& c, std::true_type)
|
Container& c, std::true_type)
|
||||||
{
|
{
|
||||||
|
#ifdef BOOST_UNORDERED_CFOA_TESTS
|
||||||
|
typename Container::key_type k;
|
||||||
|
c.cvisit_while([&](typename Container::value_type const & x) {
|
||||||
|
k = test::get_key<Container>(x);
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
auto n = c.extract(k);
|
||||||
|
#else
|
||||||
auto n = c.extract(c.begin());
|
auto n = c.extract(c.begin());
|
||||||
|
#endif
|
||||||
c.insert(std::move(n));
|
c.insert(std::move(n));
|
||||||
n = c.extract(typename Container::key_type());
|
n = c.extract(typename Container::key_type());
|
||||||
c.insert(std::move(n));
|
c.insert(std::move(n));
|
||||||
@ -122,8 +134,13 @@ UNORDERED_AUTO_TEST (explicit_alloc_ctor) {
|
|||||||
test_explicit_alloc_ctor<boost::concurrent_flat_map<int, int,
|
test_explicit_alloc_ctor<boost::concurrent_flat_map<int, int,
|
||||||
boost::hash<int>, std::equal_to<int>,
|
boost::hash<int>, std::equal_to<int>,
|
||||||
explicit_allocator<std::pair<const int, int> > > >();
|
explicit_allocator<std::pair<const int, int> > > >();
|
||||||
|
test_explicit_alloc_ctor<boost::concurrent_node_map<int, int,
|
||||||
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
explicit_allocator<std::pair<const int, int> > > >();
|
||||||
test_explicit_alloc_ctor<boost::concurrent_flat_set<
|
test_explicit_alloc_ctor<boost::concurrent_flat_set<
|
||||||
int, boost::hash<int>, std::equal_to<int>, explicit_allocator<int> > >();
|
int, boost::hash<int>, std::equal_to<int>, explicit_allocator<int> > >();
|
||||||
|
test_explicit_alloc_ctor<boost::concurrent_node_set<
|
||||||
|
int, boost::hash<int>, std::equal_to<int>, explicit_allocator<int> > >();
|
||||||
#elif defined(BOOST_UNORDERED_FOA_TESTS)
|
#elif defined(BOOST_UNORDERED_FOA_TESTS)
|
||||||
test_explicit_alloc_ctor<boost::unordered_flat_map<int, int,
|
test_explicit_alloc_ctor<boost::unordered_flat_map<int, int,
|
||||||
boost::hash<int>, std::equal_to<int>,
|
boost::hash<int>, std::equal_to<int>,
|
||||||
|
213
test/unordered/node_handle_allocator_tests.cpp
Normal file
213
test/unordered/node_handle_allocator_tests.cpp
Normal file
@ -0,0 +1,213 @@
|
|||||||
|
// Copyright (C) 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)
|
||||||
|
|
||||||
|
#include <boost/config.hpp>
|
||||||
|
|
||||||
|
#if defined(BOOST_GCC)
|
||||||
|
// Spurious maybe-uninitialized warnings with allocators contained
|
||||||
|
// in node handles.
|
||||||
|
// Maybe related to https://gcc.gnu.org/bugzilla/show_bug.cgi?id=108230
|
||||||
|
#pragma GCC diagnostic push
|
||||||
|
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef BOOST_UNORDERED_CFOA_TESTS
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
|
#else
|
||||||
|
#include "../helpers/unordered.hpp"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "../helpers/test.hpp"
|
||||||
|
|
||||||
|
#include <boost/config/workaround.hpp>
|
||||||
|
#include <boost/core/allocator_access.hpp>
|
||||||
|
#include <memory>
|
||||||
|
#include <type_traits>
|
||||||
|
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
template <class T> struct nonassignable_allocator
|
||||||
|
{
|
||||||
|
using value_type = T;
|
||||||
|
|
||||||
|
nonassignable_allocator() = default;
|
||||||
|
nonassignable_allocator(nonassignable_allocator const&) = default;
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
nonassignable_allocator(nonassignable_allocator<U> const&) {}
|
||||||
|
|
||||||
|
nonassignable_allocator& operator=(nonassignable_allocator const&) = delete;
|
||||||
|
|
||||||
|
T* allocate(std::size_t n)
|
||||||
|
{
|
||||||
|
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T* p, std::size_t) { ::operator delete(p); }
|
||||||
|
|
||||||
|
bool operator==(nonassignable_allocator const&) const { return true; }
|
||||||
|
bool operator!=(nonassignable_allocator const&) const { return false; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <class T> struct pocx_allocator
|
||||||
|
{
|
||||||
|
int x_;
|
||||||
|
|
||||||
|
using value_type = T;
|
||||||
|
using propagate_on_container_copy_assignment = std::true_type;
|
||||||
|
using propagate_on_container_move_assignment = std::true_type;
|
||||||
|
using propagate_on_container_swap = std::true_type;
|
||||||
|
|
||||||
|
pocx_allocator() : x_{-1} {}
|
||||||
|
pocx_allocator(pocx_allocator const&) = default;
|
||||||
|
pocx_allocator(int const x) : x_{x} {}
|
||||||
|
|
||||||
|
template <class U>
|
||||||
|
pocx_allocator(pocx_allocator<U> const& rhs) : x_{rhs.x_}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
pocx_allocator& operator=(pocx_allocator const&) = default;
|
||||||
|
|
||||||
|
T* allocate(std::size_t n)
|
||||||
|
{
|
||||||
|
return static_cast<T*>(::operator new(n * sizeof(T)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void deallocate(T* p, std::size_t) { ::operator delete(p); }
|
||||||
|
|
||||||
|
bool operator==(pocx_allocator const& rhs) const { return x_ == rhs.x_; }
|
||||||
|
bool operator!=(pocx_allocator const& rhs) const { return x_ != rhs.x_; }
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename Container, typename Allocator>
|
||||||
|
struct replace_allocator_impl;
|
||||||
|
|
||||||
|
template <typename Container, typename Allocator>
|
||||||
|
using replace_allocator =
|
||||||
|
typename replace_allocator_impl<Container, Allocator>::type;
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename K, typename H, typename P, typename A,
|
||||||
|
template <typename, typename, typename, typename> class Set,
|
||||||
|
typename Allocator
|
||||||
|
>
|
||||||
|
struct replace_allocator_impl<Set<K, H, P, A>, Allocator>
|
||||||
|
{
|
||||||
|
using type = Set<
|
||||||
|
K, H, P, boost::allocator_rebind_t<Allocator, K> >;
|
||||||
|
};
|
||||||
|
|
||||||
|
template <
|
||||||
|
typename K, typename H, typename T, typename P, typename A,
|
||||||
|
template <typename, typename, typename, typename, typename> class Map,
|
||||||
|
typename Allocator
|
||||||
|
>
|
||||||
|
struct replace_allocator_impl<Map<K, T, H, P, A>, Allocator>
|
||||||
|
{
|
||||||
|
using type = Map<
|
||||||
|
K, T, H, P,
|
||||||
|
boost::allocator_rebind_t<Allocator, std::pair<K const, T> > >;
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename X, typename Allocator>
|
||||||
|
void node_handle_allocator_tests(
|
||||||
|
X*, std::pair<Allocator, Allocator> allocators)
|
||||||
|
{
|
||||||
|
using value_type = typename X::value_type;
|
||||||
|
using replaced_allocator_container = replace_allocator<X, Allocator>;
|
||||||
|
using node_type = typename replaced_allocator_container::node_type;
|
||||||
|
|
||||||
|
replaced_allocator_container x1(allocators.first);
|
||||||
|
node_type nh;
|
||||||
|
|
||||||
|
x1.emplace(value_type());
|
||||||
|
nh = x1.extract(0);
|
||||||
|
|
||||||
|
BOOST_TEST(!nh.empty());
|
||||||
|
BOOST_TEST(nh.get_allocator() == x1.get_allocator());
|
||||||
|
|
||||||
|
replaced_allocator_container x2(allocators.second);
|
||||||
|
|
||||||
|
x2.emplace(value_type());
|
||||||
|
nh = x2.extract(0);
|
||||||
|
|
||||||
|
BOOST_TEST(!nh.empty());
|
||||||
|
BOOST_TEST(nh.get_allocator() == x2.get_allocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename X, typename Allocator>
|
||||||
|
void node_handle_allocator_swap_tests(
|
||||||
|
X*, std::pair<Allocator, Allocator> allocators)
|
||||||
|
{
|
||||||
|
using value_type = typename X::value_type;
|
||||||
|
using replaced_allocator_container = replace_allocator<X, Allocator>;
|
||||||
|
using node_type = typename replaced_allocator_container::node_type;
|
||||||
|
|
||||||
|
replaced_allocator_container x1(allocators.first), x2(allocators.second);
|
||||||
|
x1.emplace(value_type());
|
||||||
|
x2.emplace(value_type());
|
||||||
|
|
||||||
|
node_type nh1, nh2;
|
||||||
|
|
||||||
|
nh1 = x1.extract(0);
|
||||||
|
swap(nh1, nh2);
|
||||||
|
|
||||||
|
BOOST_TEST(nh1.empty());
|
||||||
|
BOOST_TEST(!nh2.empty());
|
||||||
|
BOOST_TEST(nh2.get_allocator() == x1.get_allocator());
|
||||||
|
|
||||||
|
nh1 = x2.extract(0);
|
||||||
|
swap(nh1, nh2);
|
||||||
|
|
||||||
|
BOOST_TEST(!nh1.empty());
|
||||||
|
BOOST_TEST(nh1.get_allocator() == x1.get_allocator());
|
||||||
|
BOOST_TEST(!nh2.empty());
|
||||||
|
BOOST_TEST(nh2.get_allocator() == x2.get_allocator());
|
||||||
|
}
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1900)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable : 4592) // symbol will be dynamically initialized
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::pair<
|
||||||
|
std::allocator<int>, std::allocator<int> > test_std_allocators({},{});
|
||||||
|
std::pair<
|
||||||
|
nonassignable_allocator<int>,
|
||||||
|
nonassignable_allocator<int> > test_nonassignable_allocators({},{});
|
||||||
|
std::pair<
|
||||||
|
pocx_allocator<int>, pocx_allocator<int> > test_pocx_allocators(5,6);
|
||||||
|
|
||||||
|
#if BOOST_WORKAROUND(BOOST_MSVC, <= 1900)
|
||||||
|
#pragma warning(pop) // C4592
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||||
|
boost::unordered_node_map<int, int>* test_map;
|
||||||
|
boost::unordered_node_set<int>* test_set;
|
||||||
|
#elif defined(BOOST_UNORDERED_CFOA_TESTS)
|
||||||
|
boost::concurrent_node_map<int, int>* test_map;
|
||||||
|
boost::concurrent_node_set<int>* test_set;
|
||||||
|
#else
|
||||||
|
boost::unordered_map<int, int>* test_map;
|
||||||
|
boost::unordered_set<int>* test_set;
|
||||||
|
#endif
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
UNORDERED_TEST(
|
||||||
|
node_handle_allocator_tests,
|
||||||
|
((test_map)(test_set))
|
||||||
|
((test_std_allocators)(test_nonassignable_allocators)
|
||||||
|
(test_pocx_allocators)))
|
||||||
|
|
||||||
|
UNORDERED_TEST(
|
||||||
|
node_handle_allocator_swap_tests,
|
||||||
|
((test_map)(test_set))
|
||||||
|
((test_std_allocators)(test_pocx_allocators)))
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
RUN_TESTS()
|
@ -33,12 +33,23 @@ namespace pmr_allocator_tests {
|
|||||||
test_string_flat_map;
|
test_string_flat_map;
|
||||||
static boost::unordered::pmr::concurrent_flat_map<pmr_string, pmr_string>*
|
static boost::unordered::pmr::concurrent_flat_map<pmr_string, pmr_string>*
|
||||||
test_pmr_string_flat_map;
|
test_pmr_string_flat_map;
|
||||||
|
static boost::unordered::pmr::concurrent_node_map<std::string, std::string>*
|
||||||
|
test_string_node_map;
|
||||||
|
static boost::unordered::pmr::concurrent_node_map<pmr_string, pmr_string>*
|
||||||
|
test_pmr_string_node_map;
|
||||||
static boost::unordered::pmr::concurrent_flat_set<std::string>*
|
static boost::unordered::pmr::concurrent_flat_set<std::string>*
|
||||||
test_string_flat_set;
|
test_string_flat_set;
|
||||||
static boost::unordered::pmr::concurrent_flat_set<pmr_string>*
|
static boost::unordered::pmr::concurrent_flat_set<pmr_string>*
|
||||||
test_pmr_string_flat_set;
|
test_pmr_string_flat_set;
|
||||||
|
static boost::unordered::pmr::concurrent_node_set<std::string>*
|
||||||
|
test_string_node_set;
|
||||||
|
static boost::unordered::pmr::concurrent_node_set<pmr_string>*
|
||||||
|
test_pmr_string_node_set;
|
||||||
#define PMR_ALLOCATOR_TESTS_ARGS \
|
#define PMR_ALLOCATOR_TESTS_ARGS \
|
||||||
((test_string_flat_map)(test_pmr_string_flat_map)(test_string_flat_set)(test_pmr_string_flat_set))
|
((test_string_flat_map)(test_pmr_string_flat_map) \
|
||||||
|
(test_string_node_map)(test_pmr_string_node_map) \
|
||||||
|
(test_string_flat_set)(test_pmr_string_flat_set) \
|
||||||
|
(test_string_node_set)(test_pmr_string_node_set))
|
||||||
#elif defined(BOOST_UNORDERED_FOA_TESTS)
|
#elif defined(BOOST_UNORDERED_FOA_TESTS)
|
||||||
static boost::unordered::pmr::unordered_flat_map<std::string, std::string>*
|
static boost::unordered::pmr::unordered_flat_map<std::string, std::string>*
|
||||||
test_string_flat_map;
|
test_string_flat_map;
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
// Copyright 2024 Joaquin M Lopez Muoz.
|
// Copyright 2024 Joaquin M Lopez Munoz.
|
||||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
// 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)
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
@ -7,8 +7,12 @@
|
|||||||
#ifdef BOOST_UNORDERED_CFOA_TESTS
|
#ifdef BOOST_UNORDERED_CFOA_TESTS
|
||||||
#include <boost/unordered/concurrent_flat_map.hpp>
|
#include <boost/unordered/concurrent_flat_map.hpp>
|
||||||
#include <boost/unordered/concurrent_flat_set.hpp>
|
#include <boost/unordered/concurrent_flat_set.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_map.hpp>
|
||||||
|
#include <boost/unordered/concurrent_node_set.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/unordered/unordered_flat_map.hpp>
|
||||||
#include <boost/unordered/unordered_flat_set.hpp>
|
#include <boost/unordered/unordered_flat_set.hpp>
|
||||||
|
#include <boost/unordered/unordered_node_map.hpp>
|
||||||
|
#include <boost/unordered/unordered_node_set.hpp>
|
||||||
#include "../cfoa/helpers.hpp"
|
#include "../cfoa/helpers.hpp"
|
||||||
#else
|
#else
|
||||||
#include "../helpers/unordered.hpp"
|
#include "../helpers/unordered.hpp"
|
||||||
@ -19,6 +23,7 @@
|
|||||||
#include "../helpers/test.hpp"
|
#include "../helpers/test.hpp"
|
||||||
#include <boost/assert.hpp>
|
#include <boost/assert.hpp>
|
||||||
#include <boost/core/make_span.hpp>
|
#include <boost/core/make_span.hpp>
|
||||||
|
#include <cmath>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
template <class T> struct unequal_allocator
|
template <class T> struct unequal_allocator
|
||||||
@ -45,16 +50,20 @@ template <class T> struct unequal_allocator
|
|||||||
int n_;
|
int n_;
|
||||||
};
|
};
|
||||||
|
|
||||||
bool exact_same(double x, double y)
|
bool esentially_same(double x, double y)
|
||||||
{
|
{
|
||||||
return std::memcmp(
|
// Some optimizer-related issues in GCC X86 result in last-bit differences
|
||||||
reinterpret_cast<void*>(&x), reinterpret_cast<void*>(&y),
|
// on doubles that should otherwise be identical.
|
||||||
sizeof(double))==0;
|
|
||||||
|
// https://stackoverflow.com/a/253874/213114
|
||||||
|
|
||||||
|
static constexpr double epsilon = 1.0E-6;
|
||||||
|
return fabs(x - y) <= ( (fabs(x) > fabs(y) ? fabs(x) : fabs(y)) * epsilon);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool not_exact_same(double x, double y)
|
bool not_esentially_same(double x, double y)
|
||||||
{
|
{
|
||||||
return !exact_same(x, y);
|
return !esentially_same(x, y);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum check_stats_contition
|
enum check_stats_contition
|
||||||
@ -69,19 +78,19 @@ void check_stat(const Stats& s, check_stats_contition cond)
|
|||||||
{
|
{
|
||||||
switch (cond) {
|
switch (cond) {
|
||||||
case stats_empty:
|
case stats_empty:
|
||||||
BOOST_TEST(exact_same(s.average, 0.0));
|
BOOST_TEST(esentially_same(s.average, 0.0));
|
||||||
BOOST_TEST(exact_same(s.variance, 0.0));
|
BOOST_TEST(esentially_same(s.variance, 0.0));
|
||||||
BOOST_TEST(exact_same(s.deviation, 0.0));
|
BOOST_TEST(esentially_same(s.deviation, 0.0));
|
||||||
break;
|
break;
|
||||||
case stats_full:
|
case stats_full:
|
||||||
BOOST_TEST_GT(s.average, 0.0);
|
BOOST_TEST_GT(s.average, 0.0);
|
||||||
if(not_exact_same(s.variance, 0.0)) {
|
if(not_esentially_same(s.variance, 0.0)) {
|
||||||
BOOST_TEST_GT(s.variance, 0.0);
|
BOOST_TEST_GT(s.variance, 0.0);
|
||||||
BOOST_TEST_GT(s.deviation, 0.0);
|
BOOST_TEST_GT(s.deviation, 0.0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case stats_mostly_full:
|
case stats_mostly_full:
|
||||||
if(not_exact_same(s.variance, 0.0)) {
|
if(not_esentially_same(s.variance, 0.0)) {
|
||||||
BOOST_TEST_GT(s.average, 0.0);
|
BOOST_TEST_GT(s.average, 0.0);
|
||||||
BOOST_TEST_GT(s.variance, 0.0);
|
BOOST_TEST_GT(s.variance, 0.0);
|
||||||
BOOST_TEST_GT(s.deviation, 0.0);
|
BOOST_TEST_GT(s.deviation, 0.0);
|
||||||
@ -94,9 +103,9 @@ void check_stat(const Stats& s, check_stats_contition cond)
|
|||||||
|
|
||||||
template <class Stats> void check_stat(const Stats& s1, const Stats& s2)
|
template <class Stats> void check_stat(const Stats& s1, const Stats& s2)
|
||||||
{
|
{
|
||||||
BOOST_TEST(exact_same(s1.average, s2.average));
|
BOOST_TEST(esentially_same(s1.average, s2.average));
|
||||||
BOOST_TEST(exact_same(s1.variance, s2.variance));
|
BOOST_TEST(esentially_same(s1.variance, s2.variance));
|
||||||
BOOST_TEST(exact_same(s1.deviation, s2.deviation));
|
BOOST_TEST(esentially_same(s1.deviation, s2.deviation));
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Stats>
|
template <class Stats>
|
||||||
@ -345,15 +354,28 @@ UNORDERED_AUTO_TEST (stats_) {
|
|||||||
boost::concurrent_flat_map<
|
boost::concurrent_flat_map<
|
||||||
int, int, boost::hash<int>, std::equal_to<int>,
|
int, int, boost::hash<int>, std::equal_to<int>,
|
||||||
unequal_allocator< std::pair< const int, int> >>>();
|
unequal_allocator< std::pair< const int, int> >>>();
|
||||||
|
test_stats<
|
||||||
|
boost::concurrent_node_map<
|
||||||
|
int, int, boost::hash<int>, std::equal_to<int>,
|
||||||
|
unequal_allocator< std::pair< const int, int> >>>();
|
||||||
test_stats<
|
test_stats<
|
||||||
boost::concurrent_flat_set<
|
boost::concurrent_flat_set<
|
||||||
int, boost::hash<int>, std::equal_to<int>, unequal_allocator<int>>>();
|
int, boost::hash<int>, std::equal_to<int>, unequal_allocator<int>>>();
|
||||||
|
test_stats<
|
||||||
|
boost::concurrent_node_set<
|
||||||
|
int, boost::hash<int>, std::equal_to<int>, unequal_allocator<int>>>();
|
||||||
test_stats_concurrent_unordered_interop<
|
test_stats_concurrent_unordered_interop<
|
||||||
boost::unordered_flat_map<int, int>,
|
boost::unordered_flat_map<int, int>,
|
||||||
boost::concurrent_flat_map<int, int>>();
|
boost::concurrent_flat_map<int, int>>();
|
||||||
|
test_stats_concurrent_unordered_interop<
|
||||||
|
boost::unordered_node_map<int, int>,
|
||||||
|
boost::concurrent_node_map<int, int>>();
|
||||||
test_stats_concurrent_unordered_interop<
|
test_stats_concurrent_unordered_interop<
|
||||||
boost::unordered_flat_set<int>,
|
boost::unordered_flat_set<int>,
|
||||||
boost::concurrent_flat_set<int>>();
|
boost::concurrent_flat_set<int>>();
|
||||||
|
test_stats_concurrent_unordered_interop<
|
||||||
|
boost::unordered_node_set<int>,
|
||||||
|
boost::concurrent_node_set<int>>();
|
||||||
#elif defined(BOOST_UNORDERED_FOA_TESTS)
|
#elif defined(BOOST_UNORDERED_FOA_TESTS)
|
||||||
test_stats<
|
test_stats<
|
||||||
boost::unordered_flat_map<
|
boost::unordered_flat_map<
|
||||||
|
Loading…
x
Reference in New Issue
Block a user