forked from boostorg/unordered
Compare commits
196 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0c93fbc330 | |||
| b8ff76f4ab | |||
| 5df80086ed | |||
| f9c32e7f8c | |||
| 21e673c697 | |||
| b96dd2184f | |||
| 9636875596 | |||
| bd6829220c | |||
| 71bf336c9d | |||
| b7c1e6a184 | |||
| 77edd24b4e | |||
| b7032baaf4 | |||
| 6580dc8d80 | |||
| 5384edd568 | |||
| 2a7a8f55e1 | |||
| 18a664c4a6 | |||
| e1b394d5b2 | |||
| dc548a1a9e | |||
| 2787717d78 | |||
| d6ba04ca4b | |||
| 43add11970 | |||
| 8e45197d4d | |||
| a46220986f | |||
| 16099478db | |||
| e5320df017 | |||
| b9fcfeb24e | |||
| f1aeb3b099 | |||
| 5b706bb7b5 | |||
| fd7d888832 | |||
| 827c69eb1a | |||
| 9973b3f8a8 | |||
| e6f911e815 | |||
| 53e4531295 | |||
| 8da44f4f46 | |||
| dddfbf8aa8 | |||
| a66eedef58 | |||
| 202049ddc0 | |||
| 000833d647 | |||
| d84e6f7be2 | |||
| 8acfccdf6e | |||
| c85dd289f9 | |||
| 8ac6019d30 | |||
| 9602799710 | |||
| 217a171b33 | |||
| b372ab6641 | |||
| 140cb56e2b | |||
| 8b842c4640 | |||
| 9b2ecd6ec5 | |||
| 351e5ae41a | |||
| 1c5733ed15 | |||
| cd44e0ba08 | |||
| 3363261ad8 | |||
| 58b8b00233 | |||
| 6474f3c8d3 | |||
| 63269d2115 | |||
| 0925a99d98 | |||
| 1b23d08941 | |||
| 28142b6251 | |||
| b60f2ce22c | |||
| 473ed9b88b | |||
| c554c5b1c9 | |||
| e244b35d23 | |||
| f7bfb85d84 | |||
| 5e0257cb08 | |||
| 64721fa1ef | |||
| 5bfc77c3e4 | |||
| aaf0e40247 | |||
| 8e86a263fc | |||
| a5a5b75dcc | |||
| b57b51b036 | |||
| 91b3863c77 | |||
| b4a23a875c | |||
| f0afa5aaef | |||
| 7ce7ef5050 | |||
| a3d4a078de | |||
| 1e61423eac | |||
| 904e806b1e | |||
| 3201a014c4 | |||
| 1a87580c58 | |||
| ab58b613c9 | |||
| bb57d91675 | |||
| 7d1e64a3c6 | |||
| ff956ad080 | |||
| d9bf1e435c | |||
| eb6d0d1f66 | |||
| bce898165c | |||
| e3c66a5e82 | |||
| b167ab7d84 | |||
| 71fd0c07ed | |||
| 130b483123 | |||
| 03ee5d135b | |||
| 72841102f6 | |||
| cc6748e2b1 | |||
| f99decc0ca | |||
| ae10a1e0df | |||
| b1e497cd1d | |||
| cbe19722a3 | |||
| dcff2ac5b5 | |||
| cb4e636d78 | |||
| 6e41418744 | |||
| 1d8d065113 | |||
| a858517c49 | |||
| 2cdcbd24f5 | |||
| 721d8713cd | |||
| 62e1d3eafb | |||
| 3744bafa55 | |||
| f034e43b74 | |||
| a74962bc3c | |||
| cafa1f2278 | |||
| 40d5097d99 | |||
| 958aea3a61 | |||
| 6846eb53fd | |||
| 3b3ba7d6f7 | |||
| 22135bd845 | |||
| 141550f585 | |||
| d750b39e1e | |||
| 055587acf4 | |||
| 0f8dd003a3 | |||
| 9bc471310e | |||
| e56aac2e98 | |||
| 09a3275357 | |||
| a3c1e643dc | |||
| 955f94350b | |||
| 1955e4f36a | |||
| 644295db3a | |||
| 0391b6dafc | |||
| c646f3e3ca | |||
| 0e9523a0a4 | |||
| 24d8449831 | |||
| 59d0accce0 | |||
| 61aedca940 | |||
| 3fb516367f | |||
| 7d77f1d478 | |||
| 7572de875c | |||
| 63d907cde7 | |||
| f0037d336d | |||
| 8b14b7cddc | |||
| 6c60524fb7 | |||
| 8b1dcd3da3 | |||
| 0e980577b0 | |||
| 1f4244ec27 | |||
| dfbff823a9 | |||
| b85e17085f | |||
| 0a879c1063 | |||
| 01d508b6af | |||
| 7709950111 | |||
| 1ede59e662 | |||
| bf2b521789 | |||
| ee1515189b | |||
| eb33ad3e3f | |||
| 0ad6ccb0b9 | |||
| 0ab4e12502 | |||
| c8910e8007 | |||
| 2043f98593 | |||
| 260b573d8d | |||
| 4ac3dcc90c | |||
| 75ea43823e | |||
| b1d43d3ca5 | |||
| 534170a942 | |||
| 7befee3bd6 | |||
| 01deb2fd61 | |||
| 91eddbabe8 | |||
| 47e205487d | |||
| 2c1c99407e | |||
| 6be2bf89b6 | |||
| 5eda445db0 | |||
| 63f07daa88 | |||
| 7040c57750 | |||
| 9716731864 | |||
| 0bcd46a485 | |||
| 46a2cd109f | |||
| 808f8e659a | |||
| 8ed05de91c | |||
| 1a02fca5c4 | |||
| d036994237 | |||
| 8d4816eac7 | |||
| 46fc4f9f4d | |||
| 725993ab95 | |||
| ffa5e6f805 | |||
| 84206ebf8f | |||
| 0398afae9b | |||
| 79dc3bb6d4 | |||
| 879de5fab8 | |||
| 89ccb49165 | |||
| 70a980a980 | |||
| c895dd7192 | |||
| ea71597053 | |||
| 324fa793fd | |||
| 39d53a0bfc | |||
| 20ea4a77a7 | |||
| 53a897008a | |||
| ee8f2b991f | |||
| 5aff5b943f | |||
| 1d99854979 | |||
| 5a4071d4f0 | |||
| c30e93544d |
+1
-1
@@ -359,7 +359,7 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
macos_pipeline(
|
||||
"MacOS 12.4 Xcode 13.4.1 ASAN",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + asan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey",
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
|
||||
@@ -72,7 +72,8 @@ jobs:
|
||||
compiler: clang-14, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
|
||||
|
||||
# OSX, clang
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, sanitize: yes }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-12, sanitize: yes }
|
||||
|
||||
timeout-minutes: 120
|
||||
runs-on: ${{matrix.os}}
|
||||
@@ -217,11 +218,13 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { toolset: msvc-14.0, cxxstd: '14,latest', addrmd: '32,64', os: windows-2019 }
|
||||
- { toolset: msvc-14.2, cxxstd: '14,17,20,latest', addrmd: '32,64', os: windows-2019 }
|
||||
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest', addrmd: '32,64', os: windows-2022 }
|
||||
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: windows-2022 }
|
||||
- { toolset: gcc, cxxstd: '03,11,14,17,2a', addrmd: '64', os: windows-2019 }
|
||||
- { toolset: msvc-14.0, cxxstd: '14,latest', addrmd: '32,64', os: windows-2019, variant: 'debug,release' }
|
||||
- { toolset: msvc-14.2, cxxstd: '14,17,20,latest', addrmd: '32,64', os: windows-2019, variant: 'debug,release' }
|
||||
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest', addrmd: '32,64', os: windows-2022, variant: 'debug,release' }
|
||||
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '64', os: windows-2022, variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '/RTCc' }
|
||||
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '32', os: windows-2022, variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '"/RTCc /arch:IA32"' }
|
||||
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: windows-2022, variant: 'debug,release' }
|
||||
- { toolset: gcc, cxxstd: '03,11,14,17,2a', addrmd: '64', os: windows-2019, variant: 'debug,release' }
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
|
||||
@@ -250,6 +253,9 @@ jobs:
|
||||
B2_TOOLSET: ${{matrix.toolset}}
|
||||
B2_CXXSTD: ${{matrix.cxxstd}}
|
||||
B2_ADDRESS_MODEL: ${{matrix.addrmd}}
|
||||
B2_DEFINES: ${{matrix.defines}}
|
||||
B2_VARIANT: ${{matrix.variant}}
|
||||
B2_CXXFLAGS: ${{matrix.cxxflags}}
|
||||
|
||||
- name: Collect coverage
|
||||
shell: powershell
|
||||
|
||||
@@ -1 +1,2 @@
|
||||
/doc/html/
|
||||
/doc/pdf/
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
enwik8
|
||||
enwik9
|
||||
*.exe
|
||||
+22
-101
@@ -3,23 +3,18 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
# include "tsl/hopscotch_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
# include "tsl/robin_map.h"
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -267,24 +262,6 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// multi_index emulation of unordered_map
|
||||
|
||||
template<class K, class V> struct pair
|
||||
{
|
||||
K first;
|
||||
mutable V second;
|
||||
};
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<class K, class V> using multi_index_map = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
@@ -308,23 +285,10 @@ template<class K, class V> using absl_flat_hash_map =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_map =
|
||||
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_pg_map =
|
||||
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
template<class K, class V> using tsl_robin_map =
|
||||
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_robin_pg_map =
|
||||
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -384,14 +348,6 @@ template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first>, fnv1a_hash >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||
@@ -402,23 +358,10 @@ template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_map_fnv1a =
|
||||
tsl::hopscotch_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_pg_map_fnv1a =
|
||||
tsl::hopscotch_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
template<class K, class V> using tsl_robin_map_fnv1a =
|
||||
tsl::robin_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_robin_pg_map_fnv1a =
|
||||
tsl::robin_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -428,67 +371,45 @@ int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
#if 1
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
|
||||
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
|
||||
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
test<tsl_robin_map>( "tsl::robin_map" );
|
||||
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
|
||||
test<tsl_hopscotch_map_fnv1a>( "tsl::hopscotch_map, FNV-1a" );
|
||||
test<tsl_hopscotch_pg_map_fnv1a>( "tsl::hopscotch_pg_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
test<tsl_robin_map_fnv1a>( "tsl::robin_map, FNV-1a" );
|
||||
test<tsl_robin_pg_map_fnv1a>( "tsl::robin_pg_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 35 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+22
-101
@@ -3,23 +3,18 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
# include "tsl/hopscotch_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
# include "tsl/robin_map.h"
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <string_view>
|
||||
@@ -268,24 +263,6 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// multi_index emulation of unordered_map
|
||||
|
||||
template<class K, class V> struct pair
|
||||
{
|
||||
K first;
|
||||
mutable V second;
|
||||
};
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<class K, class V> using multi_index_map = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
@@ -309,23 +286,10 @@ template<class K, class V> using absl_flat_hash_map =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_map =
|
||||
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_pg_map =
|
||||
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
template<class K, class V> using tsl_robin_map =
|
||||
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_robin_pg_map =
|
||||
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -385,14 +349,6 @@ template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first>, fnv1a_hash >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||
@@ -403,23 +359,10 @@ template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_map_fnv1a =
|
||||
tsl::hopscotch_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_pg_map_fnv1a =
|
||||
tsl::hopscotch_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
template<class K, class V> using tsl_robin_map_fnv1a =
|
||||
tsl::robin_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_robin_pg_map_fnv1a =
|
||||
tsl::robin_pg_map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -429,67 +372,45 @@ int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
#if 1
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
|
||||
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
|
||||
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
test<tsl_robin_map>( "tsl::robin_map" );
|
||||
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
|
||||
test<tsl_hopscotch_map_fnv1a>( "tsl::hopscotch_map, FNV-1a" );
|
||||
test<tsl_hopscotch_pg_map_fnv1a>( "tsl::hopscotch_pg_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
test<tsl_robin_map_fnv1a>( "tsl::robin_map, FNV-1a" );
|
||||
test<tsl_robin_pg_map_fnv1a>( "tsl::robin_pg_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 35 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+13
-58
@@ -3,12 +3,10 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
@@ -16,11 +14,8 @@
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
# include "tsl/hopscotch_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
# include "tsl/robin_map.h"
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -284,24 +279,6 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// multi_index emulation of unordered_map
|
||||
|
||||
template<class K, class V> struct pair
|
||||
{
|
||||
K first;
|
||||
mutable V second;
|
||||
};
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<class K, class V> using multi_index_map = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
@@ -325,23 +302,10 @@ template<class K, class V> using absl_flat_hash_map =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_map =
|
||||
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_pg_map =
|
||||
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
template<class K, class V> using tsl_robin_map =
|
||||
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_robin_pg_map =
|
||||
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -352,34 +316,25 @@ int main()
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
|
||||
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
|
||||
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
test<tsl_robin_map>( "tsl::robin_map" );
|
||||
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 27 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+23
-58
@@ -3,12 +3,10 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
@@ -16,11 +14,8 @@
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
# include "tsl/hopscotch_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
# include "tsl/robin_map.h"
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
@@ -284,24 +279,6 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// multi_index emulation of unordered_map
|
||||
|
||||
template<class K, class V> struct pair
|
||||
{
|
||||
K first;
|
||||
mutable V second;
|
||||
};
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<class K, class V> using multi_index_map = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
@@ -325,23 +302,10 @@ template<class K, class V> using absl_flat_hash_map =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_map =
|
||||
tsl::hopscotch_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_hopscotch_pg_map =
|
||||
tsl::hopscotch_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
template<class K, class V> using tsl_robin_map =
|
||||
tsl::robin_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
template<class K, class V> using tsl_robin_pg_map =
|
||||
tsl::robin_pg_map<K, V, std::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -349,37 +313,38 @@ int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
#if defined(BOOST_LIBSTDCXX_VERSION) && __SIZE_WIDTH__ == 32
|
||||
|
||||
// Pathological behavior:
|
||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104945
|
||||
|
||||
#else
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
|
||||
#endif
|
||||
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_HOPSCOTCH
|
||||
|
||||
test<tsl_hopscotch_map>( "tsl::hopscotch_map" );
|
||||
test<tsl_hopscotch_pg_map>( "tsl::hopscotch_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_TSL_ROBIN
|
||||
|
||||
test<tsl_robin_map>( "tsl::robin_map" );
|
||||
test<tsl_robin_pg_map>( "tsl::robin_pg_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 27 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+18
-23
@@ -3,12 +3,10 @@
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
@@ -17,6 +15,9 @@
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
@@ -329,24 +330,6 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// multi_index emulation of unordered_map
|
||||
|
||||
template<class K, class V> struct pair
|
||||
{
|
||||
K first;
|
||||
mutable V second;
|
||||
};
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<class K, class V> using multi_index_map = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
@@ -370,6 +353,13 @@ template<class K, class V> using absl_flat_hash_map =
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
@@ -377,7 +367,12 @@ int main()
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
@@ -390,7 +385,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 27 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,376 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
#include <string_view>
|
||||
#include <string>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::size_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
static std::vector<std::string> words;
|
||||
|
||||
static void init_words()
|
||||
{
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
||||
|
||||
#else
|
||||
|
||||
char const* fn = "enwik8"; // ditto
|
||||
|
||||
#endif
|
||||
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::ifstream is( fn );
|
||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
||||
|
||||
boost::regex re( "[a-zA-Z]+");
|
||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
||||
|
||||
words.assign( it, end );
|
||||
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_word_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
++map[ word ];
|
||||
++s;
|
||||
}
|
||||
|
||||
print_time( t1, "Word count", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_contains( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
std::string_view w2( word );
|
||||
w2.remove_prefix( 1 );
|
||||
|
||||
s += map.contains( w2 );
|
||||
}
|
||||
|
||||
print_time( t1, "Contains", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& word: words )
|
||||
{
|
||||
std::string_view w2( word );
|
||||
w2.remove_prefix( 1 );
|
||||
|
||||
s += map.count( w2 );
|
||||
}
|
||||
|
||||
print_time( t1, "Count", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t max = 0;
|
||||
std::string_view word;
|
||||
|
||||
for( auto const& x: map )
|
||||
{
|
||||
if( x.second > max )
|
||||
{
|
||||
word = x.first;
|
||||
max = x.second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and find max element", max, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::string_view, std::size_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_word_count( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_contains( map, t1 );
|
||||
test_count( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
// fnv1a_hash
|
||||
|
||||
template<int Bits> struct fnv1a_hash_impl;
|
||||
|
||||
template<> struct fnv1a_hash_impl<32>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0x811C9DC5u;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x01000193ul;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template<> struct fnv1a_hash_impl<64>
|
||||
{
|
||||
std::size_t operator()( std::string_view const& s ) const
|
||||
{
|
||||
std::size_t h = 0xCBF29CE484222325ull;
|
||||
|
||||
char const * first = s.data();
|
||||
char const * last = first + s.size();
|
||||
|
||||
for( ; first != last; ++first )
|
||||
{
|
||||
h ^= static_cast<unsigned char>( *first );
|
||||
h *= 0x00000100000001B3ull;
|
||||
}
|
||||
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
template<class K, class V> using std_unordered_map_fnv1a =
|
||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
||||
absl::node_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
||||
absl::flat_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
//
|
||||
|
||||
int main()
|
||||
{
|
||||
init_words();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
@@ -0,0 +1,238 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/regex.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
# include "ankerl/unordered_dense.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <fstream>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::size_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
static std::vector<std::string> words;
|
||||
|
||||
static void init_words()
|
||||
{
|
||||
#if SIZE_MAX > UINT32_MAX
|
||||
|
||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
||||
|
||||
#else
|
||||
|
||||
char const* fn = "enwik8"; // ditto
|
||||
|
||||
#endif
|
||||
|
||||
auto t1 = std::chrono::steady_clock::now();
|
||||
|
||||
std::ifstream is( fn );
|
||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
||||
|
||||
boost::regex re( "[a-zA-Z]+");
|
||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
||||
|
||||
words.assign( it, end );
|
||||
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_word_size( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( auto const& word: words )
|
||||
{
|
||||
++map[ word.size() ];
|
||||
}
|
||||
|
||||
print_time( t1, "Word size count", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::size_t s = 0;
|
||||
|
||||
for( auto const& x: map )
|
||||
{
|
||||
s += x.second;
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and sum counts", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<std::size_t, std::size_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_word_size( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_iteration( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
template<class K, class V> using ankerl_unordered_dense_map =
|
||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_words();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
|
||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
||||
|
||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 24 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 5.8 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
@@ -244,4 +244,69 @@ image::fca.png[align=center]
|
||||
|
||||
Thus container-wide iteration is turned into traversing the non-empty bucket groups (an operation with constant time complexity) which reduces the time complexity back to `O(size())`. In total, a bucket group is only 4 words in size and it views `sizeof(std::size_t) * CHAR_BIT` buckets meaning that for all common implementations, there's only 4 bits of space overhead per bucket introduced by the bucket groups.
|
||||
|
||||
For more information on implementation rationale, read the <<Implementation Rationale, corresponding section>>.
|
||||
A more detailed description of Boost.Unordered's closed-addressing implementation is
|
||||
given in an
|
||||
https://bannalia.blogspot.com/2022/06/advancing-state-of-art-for.html[external article].
|
||||
For more information on implementation rationale, read the
|
||||
xref:#rationale_boostunordered_multiset_and_boostunordered_multimap[corresponding section].
|
||||
|
||||
== Open Addressing Implementation
|
||||
|
||||
The diagram shows the basic internal layout of `boost::unordered_flat_map` and
|
||||
`boost:unordered_flat_set`.
|
||||
|
||||
|
||||
[#img-foa-layout]
|
||||
.Open-addressing layout used by Boost.Unordered.
|
||||
image::foa.png[align=center]
|
||||
|
||||
As with all open-addressing containers, elements are stored directly in the bucket array.
|
||||
This array is logically divided into 2^_n_^ _groups_ of 15 elements each.
|
||||
In addition to the bucket array, there is an associated _metadata array_ with 2^_n_^
|
||||
16-byte words.
|
||||
|
||||
[#img-foa-metadata]
|
||||
.Breakdown of a metadata word.
|
||||
image::foa-metadata.png[align=center]
|
||||
|
||||
A metadata word is divided into 15 _h_~_i_~ bytes (one for each associated
|
||||
bucket), and an _overflow byte_ (_ofw_ in the diagram). The value of _h_~_i_~ is:
|
||||
|
||||
- 0 if the corresponding bucket is empty.
|
||||
- 1 to encode a special empty bucket called a _sentinel_, which is used internally to
|
||||
stop iteration when the container has been fully traversed.
|
||||
- If the bucket is occupied, a _reduced hash value_ obtained from the hash value of
|
||||
the element.
|
||||
|
||||
When looking for an element with hash value _h_, SIMD technologies such as
|
||||
https://en.wikipedia.org/wiki/SSE2[SSE2] and
|
||||
https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(Neon)[Neon] allow us
|
||||
to very quickly inspect the full metadata word and look for the reduced value of _h_ among all the
|
||||
15 buckets with just a handful of CPU instructions: non-matching buckets can be
|
||||
readily discarded, and those whose reduced hash value matches need be inspected via full
|
||||
comparison with the corresponding element. If the looked-for element is not present,
|
||||
the overflow byte is inspected:
|
||||
|
||||
- If the bit in the position _h_ mod 8 is zero, lookup terminates (and the
|
||||
element is not present).
|
||||
- If the bit is set to 1 (the group has been _overflowed_), further groups are
|
||||
checked using https://en.wikipedia.org/wiki/Quadratic_probing[_quadratic probing_], and
|
||||
the process is repeated.
|
||||
|
||||
Insertion is algorithmically similar: empty buckets are located using SIMD,
|
||||
and when going past a full group its corresponding overflow bit is set to 1.
|
||||
|
||||
In architectures without SIMD support, the logical layout stays the same, but the metadata
|
||||
word is codified using a technique we call _bit interleaving_: this layout allows us
|
||||
to emulate SIMD with reasonably good performance using only standard arithmetic and
|
||||
logical operations.
|
||||
|
||||
[#img-foa-metadata-interleaving]
|
||||
.Bit-interleaved metadata word.
|
||||
image::foa-metadata-interleaving.png[align=center]
|
||||
|
||||
A more detailed description of Boost.Unordered's open-addressing implementation is
|
||||
given in an
|
||||
https://bannalia.blogspot.com/2022/11/inside-boostunorderedflatmap.html[external article].
|
||||
For more information on implementation rationale, read the
|
||||
xref:#rationale_boostunordered_flat_set_and_boostunordered_flat_map[corresponding section].
|
||||
|
||||
@@ -6,10 +6,17 @@
|
||||
:github-pr-url: https://github.com/boostorg/unordered/pull
|
||||
:cpp: C++
|
||||
|
||||
== Release 1.82.0
|
||||
|
||||
* Extended heterogeneous lookup to more member functions as specified in
|
||||
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2363r3.html[P2363].
|
||||
|
||||
== Release 1.81.0 - Major update
|
||||
|
||||
* Added fast containers `boost::unordered_flat_map` and `boost::unordered_flat_set`
|
||||
based on open addressing.
|
||||
* Added CTAD deduction guides for all containers.
|
||||
* Added missing constructors as specified in https://cplusplus.github.io/LWG/issue2713[LWG issue 2713].
|
||||
|
||||
== Release 1.80.0 - Major update
|
||||
|
||||
|
||||
@@ -98,9 +98,8 @@ namespace boost {
|
||||
xref:#unordered_flat_map_destructor[~unordered_flat_map]();
|
||||
unordered_flat_map& xref:#unordered_flat_map_copy_assignment[operator++=++](const unordered_flat_map& other);
|
||||
unordered_flat_map& xref:#unordered_flat_map_move_assignment[operator++=++](unordered_flat_map&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_move_assignable_v<Hash> &&
|
||||
boost::is_nothrow_move_assignable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
unordered_flat_map& xref:#unordered_flat_map_initializer_list_assignment[operator++=++](std::initializer_list<value_type>);
|
||||
allocator_type xref:#unordered_flat_map_get_allocator[get_allocator]() const noexcept;
|
||||
|
||||
@@ -135,28 +134,35 @@ namespace boost {
|
||||
std::pair<iterator, bool> xref:#unordered_flat_map_try_emplace[try_emplace](const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
std::pair<iterator, bool> xref:#unordered_flat_map_try_emplace[try_emplace](key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
std::pair<iterator, bool> xref:#unordered_flat_map_try_emplace[try_emplace](K&& k, Args&&... args);
|
||||
template<class... Args>
|
||||
iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args);
|
||||
template<class M>
|
||||
std::pair<iterator, bool> xref:#unordered_flat_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
std::pair<iterator, bool> xref:#unordered_flat_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
std::pair<iterator, bool> xref:#unordered_flat_map_insert_or_assign[insert_or_assign](K&& k, M&& obj);
|
||||
template<class M>
|
||||
iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj);
|
||||
|
||||
void xref:#unordered_flat_map_erase_by_position[erase](iterator position);
|
||||
void xref:#unordered_flat_map_erase_by_position[erase](const_iterator position);
|
||||
size_type xref:#unordered_flat_map_erase_by_key[erase](const key_type& k);
|
||||
template<class K> size_type xref:#unordered_flat_map_transparent_erase_by_key[erase](K&& k);
|
||||
template<class K> size_type xref:#unordered_flat_map_erase_by_key[erase](K&& k);
|
||||
iterator xref:#unordered_flat_map_erase_range[erase](const_iterator first, const_iterator last);
|
||||
void xref:#unordered_flat_map_swap[swap](unordered_flat_map& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_swappable_v<Hash> &&
|
||||
boost::is_nothrow_swappable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_swap::value);
|
||||
void xref:#unordered_flat_map_clear[clear]() noexcept;
|
||||
|
||||
template<class H2, class P2>
|
||||
@@ -191,8 +197,11 @@ namespace boost {
|
||||
// element access
|
||||
mapped_type& xref:#unordered_flat_map_operator[operator[+]+](const key_type& k);
|
||||
mapped_type& xref:#unordered_flat_map_operator[operator[+]+](key_type&& k);
|
||||
template<class K> mapped_type& xref:#unordered_flat_map_operator[operator[+]+](K&& k);
|
||||
mapped_type& xref:#unordered_flat_map_at[at](const key_type& k);
|
||||
const mapped_type& xref:#unordered_flat_map_at[at](const key_type& k) const;
|
||||
template<class K> mapped_type& xref:#unordered_flat_map_at[at](const K& k);
|
||||
template<class K> const mapped_type& xref:#unordered_flat_map_at[at](const K& k) const;
|
||||
|
||||
// bucket interface
|
||||
size_type xref:#unordered_flat_map_bucket_count[bucket_count]() const noexcept;
|
||||
@@ -205,26 +214,76 @@ namespace boost {
|
||||
void xref:#unordered_flat_map_rehash[rehash](size_type n);
|
||||
void xref:#unordered_flat_map_reserve[reserve](size_type n);
|
||||
};
|
||||
|
||||
// Deduction Guides
|
||||
template<class InputIterator,
|
||||
class Hash = boost::hash<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
class Pred = std::equal_to<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
class Allocator = std::allocator<xref:#unordered_flat_map_iter_to_alloc_type[__iter-to-alloc-type__]<InputIterator>>>
|
||||
unordered_flat_map(InputIterator, InputIterator, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type = xref:#unordered_flat_map_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
|
||||
Pred, Allocator>;
|
||||
|
||||
template<class Key, class T, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<const Key, T>>>
|
||||
unordered_flat_map(std::initializer_list<std::pair<Key, T>>,
|
||||
typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type = xref:#unordered_flat_map_deduction_guides[__see below__], Hash = Hash(),
|
||||
Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_flat_map<Key, T, Hash, Pred, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_flat_map(InputIterator, InputIterator, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_flat_map(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_flat_map(InputIterator, InputIterator, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_flat_map<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
|
||||
std::equal_to<xref:#unordered_flat_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Allocator>
|
||||
unordered_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type,
|
||||
Allocator)
|
||||
-> unordered_flat_map<Key, T, boost::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Allocator>
|
||||
unordered_flat_map(std::initializer_list<std::pair<Key, T>>, Allocator)
|
||||
-> unordered_flat_map<Key, T, boost::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Hash, class Allocator>
|
||||
unordered_flat_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type,
|
||||
Hash, Allocator)
|
||||
-> unordered_flat_map<Key, T, Hash, std::equal_to<Key>, Allocator>;
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_map_operator_2[operator==](const unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_map_operator_3[operator!=](const unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_flat_map_swap_2[swap](unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_flat_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 unordered_flat_map<K, T, H, P, A>::size_type
|
||||
xref:#unordered_flat_map_erase_if[erase_if](unordered_flat_map<K, T, H, P, A>& c, Predicate pred);
|
||||
}
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_map_operator_2[operator==](const unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_map_operator_3[operator!=](const unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_flat_map_swap_2[swap](unordered_flat_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_flat_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 unordered_flat_map<K, T, H, P, A>::size_type
|
||||
xref:#unordered_flat_map_erase_if[erase_if](unordered_flat_map<K, T, H, P, A>& c, Predicate pred);
|
||||
-----
|
||||
|
||||
---
|
||||
@@ -556,11 +615,10 @@ Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInse
|
||||
==== Move Assignment
|
||||
```c++
|
||||
unordered_flat_map& operator=(unordered_flat_map&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_move_assignable_v<Hash> &&
|
||||
boost::is_nothrow_move_assignable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
```
|
||||
The move assignment operator. Destroys previously existing elements, move-assigns the hash function and predicate from `other`,
|
||||
The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`,
|
||||
and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`.
|
||||
If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to the new container;
|
||||
otherwise, inserts move-constructed copies of the elements of `other`.
|
||||
@@ -813,6 +871,8 @@ template<class... Args>
|
||||
std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
std::pair<iterator, bool> try_emplace(K&& k, Args&&... args);
|
||||
```
|
||||
|
||||
Inserts a new node into the container if there is no existing element with key `k` contained within it.
|
||||
@@ -829,15 +889,23 @@ if there is an element with an equivalent key; otherwise, the construction is of
|
||||
+
|
||||
--
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#unordered_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
|
||||
Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load.
|
||||
|
||||
The `template <class K, class... Args>` 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.
|
||||
|
||||
--
|
||||
|
||||
---
|
||||
@@ -848,6 +916,8 @@ template<class... Args>
|
||||
iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
|
||||
```
|
||||
|
||||
Inserts a new node into the container if there is no existing element with key `k` contained within it.
|
||||
@@ -864,15 +934,23 @@ if there is an element with an equivalent key; otherwise, the construction is of
|
||||
+
|
||||
--
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#unordered_flat_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
|
||||
Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load.
|
||||
|
||||
The `template <class K, class... Args>` 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.
|
||||
|
||||
--
|
||||
|
||||
---
|
||||
@@ -883,6 +961,8 @@ template<class M>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
std::pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
|
||||
```
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
@@ -891,9 +971,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for
|
||||
|
||||
If there is no such element, it is added to the container as:
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -901,7 +987,9 @@ Returns:;; The `bool` component of the return type is `true` if an insert took p
|
||||
+
|
||||
If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. +
|
||||
Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. +
|
||||
+
|
||||
The `template<class K, class M>` 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -911,6 +999,8 @@ template<class M>
|
||||
iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
|
||||
```
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
@@ -919,9 +1009,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for
|
||||
|
||||
If there is no such element, it is added to the container as:
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
```
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted. This implementation ignores it.
|
||||
@@ -929,7 +1025,9 @@ value_type(std::piecewise_construct,
|
||||
[horizontal]
|
||||
Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load.
|
||||
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +
|
||||
+
|
||||
The `template<class K, class M>` 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -951,28 +1049,15 @@ Throws:;; Nothing.
|
||||
==== Erase by Key
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Erase by Key
|
||||
```c++
|
||||
template<class K> size_type erase(K&& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -993,9 +1078,8 @@ Throws:;; Nothing in this implementation (neither the `hasher` nor the `key_equa
|
||||
==== swap
|
||||
```c++
|
||||
void swap(unordered_flat_map& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_swappable_v<Hash> &&
|
||||
boost::is_nothrow_swappable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_swap::value);
|
||||
```
|
||||
|
||||
Swaps the contents of the container with the parameter.
|
||||
@@ -1126,13 +1210,16 @@ Notes:;; The `template <typename K>` overloads only participate in overload reso
|
||||
```c++
|
||||
mapped_type& operator[](const key_type& k);
|
||||
mapped_type& operator[](key_type&& k);
|
||||
template<class K> mapped_type& operator[](K&& k);
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Effects:;; If the container does not already contain an element with a key equivalent to `k`, inserts the value `std::pair<key_type const, mapped_type>(k, mapped_type())`.
|
||||
Returns:;; A reference to `x.second` where `x` is the element already in the container, or the newly inserted element with a key equivalent to `k`.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load.
|
||||
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +
|
||||
+
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1140,11 +1227,14 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse
|
||||
```c++
|
||||
mapped_type& at(const key_type& k);
|
||||
const mapped_type& at(const key_type& k) const;
|
||||
template<class K> mapped_type& at(const K& k);
|
||||
template<class K> const mapped_type& at(const K& k) const;
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`.
|
||||
Throws:;; An exception object of type `std::out_of_range` if no such element is present.
|
||||
Notes:;; The `template<class K>` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
|
||||
|
||||
---
|
||||
|
||||
@@ -1237,6 +1327,51 @@ Invalidates iterators, pointers and references, and changes the order of element
|
||||
[horizontal]
|
||||
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
|
||||
|
||||
=== Deduction Guides
|
||||
A deduction guide will not participate in overload resolution if any of the following are true:
|
||||
|
||||
- It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
|
||||
- It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter.
|
||||
- It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter.
|
||||
- It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter.
|
||||
|
||||
A `size_type` parameter type in a deduction guide refers to the `size_type` member type of the
|
||||
container type deduced by the deduction guide. Its default value coincides with the default value
|
||||
of the constructor selected.
|
||||
|
||||
==== __iter-value-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-value-type__ =
|
||||
typename std::iterator_traits<InputIterator>::value_type; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-key-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-key-type__ = std::remove_const_t<
|
||||
std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-mapped-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-mapped-type__ =
|
||||
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-to-alloc-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-to-alloc-type__ = std::pair<
|
||||
std::add_const_t<std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>,
|
||||
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
|
||||
-----
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
||||
@@ -93,9 +93,8 @@ namespace boost {
|
||||
xref:#unordered_flat_set_destructor[~unordered_flat_set]();
|
||||
unordered_flat_set& xref:#unordered_flat_set_copy_assignment[operator++=++](const unordered_flat_set& other);
|
||||
unordered_flat_set& xref:#unordered_flat_set_move_assignment[operator++=++](unordered_flat_set&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_move_assignable_v<Hash> &&
|
||||
boost::is_nothrow_move_assignable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
unordered_flat_set& xref:#unordered_flat_set_initializer_list_assignment[operator++=++](std::initializer_list<value_type>);
|
||||
allocator_type xref:#unordered_flat_set_get_allocator[get_allocator]() const noexcept;
|
||||
|
||||
@@ -117,20 +116,21 @@ namespace boost {
|
||||
template<class... Args> iterator xref:#unordered_flat_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args);
|
||||
std::pair<iterator, bool> xref:#unordered_flat_set_copy_insert[insert](const value_type& obj);
|
||||
std::pair<iterator, bool> xref:#unordered_flat_set_move_insert[insert](value_type&& obj);
|
||||
iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj);
|
||||
iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
|
||||
template<class K> std::pair<iterator, bool> xref:#unordered_flat_set_transparent_insert[insert](K&& k);
|
||||
iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj);
|
||||
iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
|
||||
template<class K> iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k);
|
||||
template<class InputIterator> void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
|
||||
void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list<value_type>);
|
||||
|
||||
void xref:#unordered_flat_set_erase_by_position[erase](iterator position);
|
||||
void xref:#unordered_flat_set_erase_by_position[erase](const_iterator position);
|
||||
size_type xref:#unordered_flat_set_erase_by_key[erase](const key_type& k);
|
||||
template<class K> size_type xref:#unordered_flat_set_transparent_erase_by_key[erase](K&& k);
|
||||
template<class K> size_type xref:#unordered_flat_set_erase_by_key[erase](K&& k);
|
||||
iterator xref:#unordered_flat_set_erase_range[erase](const_iterator first, const_iterator last);
|
||||
void xref:#unordered_flat_set_swap[swap](unordered_flat_set& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_swappable_v<Hash> &&
|
||||
boost::is_nothrow_swappable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_swap::value);
|
||||
void xref:#unordered_flat_set_clear[clear]() noexcept;
|
||||
|
||||
template<class H2, class P2>
|
||||
@@ -173,26 +173,71 @@ namespace boost {
|
||||
void xref:#unordered_flat_set_rehash[rehash](size_type n);
|
||||
void xref:#unordered_flat_set_reserve[reserve](size_type n);
|
||||
};
|
||||
|
||||
// Deduction Guides
|
||||
template<class InputIterator,
|
||||
class Hash = boost::hash<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
class Pred = std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
class Allocator = std::allocator<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>>
|
||||
unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
|
||||
|
||||
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
|
||||
class Allocator = std::allocator<T>>
|
||||
unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_flat_set<T, Hash, Pred, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_flat_set(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_flat_set<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
|
||||
std::equal_to<xref:#unordered_flat_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class T, class Allocator>
|
||||
unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template<class T, class Allocator>
|
||||
unordered_flat_set(std::initializer_list<T>, Allocator)
|
||||
-> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template<class T, class Hash, class Allocator>
|
||||
unordered_flat_set(std::initializer_list<T>, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash, Allocator)
|
||||
-> unordered_flat_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_set_operator_2[operator==](const unordered_flat_set<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_set<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_set_operator_3[operator!=](const unordered_flat_set<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_set<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_flat_set_swap_2[swap](unordered_flat_set<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_flat_set<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 unordered_flat_set<K, T, H, P, A>::size_type
|
||||
xref:#unordered_flat_set_erase_if[erase_if](unordered_flat_set<K, T, H, P, A>& c, Predicate pred);
|
||||
}
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_set_operator_2[operator==](const unordered_flat_set<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_set<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_flat_set_operator_3[operator!=](const unordered_flat_set<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_flat_set<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_flat_set_swap_2[swap](unordered_flat_set<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_flat_set<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 unordered_flat_set<K, T, H, P, A>::size_type
|
||||
xref:#unordered_flat_set_erase_if[erase_if](unordered_flat_set<K, T, H, P, A>& c, Predicate pred);
|
||||
-----
|
||||
|
||||
---
|
||||
@@ -520,11 +565,10 @@ Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInse
|
||||
==== Move Assignment
|
||||
```c++
|
||||
unordered_flat_set& operator=(unordered_flat_set&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_move_assignable_v<Hash> &&
|
||||
boost::is_nothrow_move_assignable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
```
|
||||
The move assignment operator. Destroys previously existing elements, move-assigns the hash function and predicate from `other`,
|
||||
The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`,
|
||||
and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`.
|
||||
If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to the new container;
|
||||
otherwise, inserts move-constructed copies of the elements of `other`.
|
||||
@@ -694,6 +738,25 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Insert
|
||||
```c++
|
||||
template<class K> std::pair<iterator, bool> insert(K&& k);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `std::forward<K>(k)` in the container if and only if there is no element in the container with an equivalent key.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`.
|
||||
Returns:;; The bool component of the return type is true if an insert took place. +
|
||||
+
|
||||
If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +
|
||||
+
|
||||
This 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.
|
||||
|
||||
---
|
||||
|
||||
==== Copy Insert with Hint
|
||||
```c++
|
||||
iterator insert(const_iterator hint, const value_type& obj);
|
||||
@@ -731,6 +794,27 @@ Notes:;; Can invalidate iterators, pointers and references, but only if the inse
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Insert with Hint
|
||||
```c++
|
||||
template<class K> std::pair<iterator, bool> insert(const_iterator hint, K&& k);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `std::forward<K>(k)` in the container if and only if there is no element in the container with an equivalent key.
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted. This implementation ignores it.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`.
|
||||
Returns:;; The bool component of the return type is true if an insert took place. +
|
||||
+
|
||||
If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. +
|
||||
+
|
||||
This 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.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Iterator Range
|
||||
```c++
|
||||
template<class InputIterator> void insert(InputIterator first, InputIterator last);
|
||||
@@ -776,28 +860,15 @@ Throws:;; Nothing.
|
||||
==== Erase by Key
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Erase by Key
|
||||
```c++
|
||||
template<class K> size_type erase(K&& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -818,9 +889,8 @@ Throws:;; Nothing in this implementation (neither the `hasher` nor the `key_equa
|
||||
==== swap
|
||||
```c++
|
||||
void swap(unordered_flat_set& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value &&
|
||||
boost::is_nothrow_swappable_v<Hash> &&
|
||||
boost::is_nothrow_swappable_v<Pred>);
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_swap::value);
|
||||
```
|
||||
|
||||
Swaps the contents of the container with the parameter.
|
||||
@@ -1036,6 +1106,26 @@ Invalidates iterators, pointers and references, and changes the order of element
|
||||
[horizontal]
|
||||
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
|
||||
|
||||
=== Deduction Guides
|
||||
A deduction guide will not participate in overload resolution if any of the following are true:
|
||||
|
||||
- It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
|
||||
- It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter.
|
||||
- It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter.
|
||||
- It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter.
|
||||
|
||||
A `size_type` parameter type in a deduction guide refers to the `size_type` member type of the
|
||||
container type deduced by the deduction guide. Its default value coincides with the default value
|
||||
of the constructor selected.
|
||||
|
||||
==== __iter-value-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-value-type__ =
|
||||
typename std::iterator_traits<InputIterator>::value_type; // exposition only
|
||||
-----
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
||||
@@ -113,29 +113,37 @@ namespace boost {
|
||||
std::pair<iterator, bool> xref:#unordered_map_try_emplace[try_emplace](const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
std::pair<iterator, bool> xref:#unordered_map_try_emplace[try_emplace](key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
std::pair<iterator, bool> xref:#unordered_map_try_emplace[try_emplace](K&& k, Args&&... args);
|
||||
template<class... Args>
|
||||
iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args);
|
||||
template<class M>
|
||||
std::pair<iterator, bool> xref:#unordered_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
std::pair<iterator, bool> xref:#unordered_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
std::pair<iterator, bool> xref:#unordered_map_insert_or_assign[insert_or_assign](K&& k, M&& obj);
|
||||
template<class M>
|
||||
iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj);
|
||||
|
||||
node_type xref:#unordered_map_extract_by_iterator[extract](const_iterator position);
|
||||
node_type xref:#unordered_map_extract_by_key[extract](const key_type& k);
|
||||
template<class K> node_type xref:#unordered_map_transparent_extract_by_key[extract](K&& k);
|
||||
template<class K> node_type xref:#unordered_map_extract_by_key[extract](K&& k);
|
||||
insert_return_type xref:#unordered_map_insert_with_node_handle[insert](node_type&& nh);
|
||||
iterator xref:#unordered_map_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh);
|
||||
|
||||
iterator xref:#unordered_map_erase_by_position[erase](iterator position);
|
||||
iterator xref:#unordered_map_erase_by_position[erase](const_iterator position);
|
||||
size_type xref:#unordered_map_erase_by_key[erase](const key_type& k);
|
||||
template<class K> size_type xref:#unordered_map_transparent_erase_by_key[erase](K&& k);
|
||||
template<class K> size_type xref:#unordered_map_erase_by_key[erase](K&& k);
|
||||
iterator xref:#unordered_map_erase_range[erase](const_iterator first, const_iterator last);
|
||||
void xref:#unordered_map_quick_erase[quick_erase](const_iterator position);
|
||||
void xref:#unordered_map_erase_return_void[erase_return_void](const_iterator position);
|
||||
@@ -187,14 +195,18 @@ namespace boost {
|
||||
// element access
|
||||
mapped_type& xref:#unordered_map_operator[operator[+]+](const key_type& k);
|
||||
mapped_type& xref:#unordered_map_operator[operator[+]+](key_type&& k);
|
||||
template<class K> mapped_type& xref:#unordered_map_operator[operator[+]+](K&& k);
|
||||
mapped_type& xref:#unordered_map_at[at](const key_type& k);
|
||||
const mapped_type& xref:#unordered_map_at[at](const key_type& k) const;
|
||||
template<class K> mapped_type& xref:#unordered_map_at[at](const K& k);
|
||||
template<class K> const mapped_type& xref:#unordered_map_at[at](const K& k) const;
|
||||
|
||||
// bucket interface
|
||||
size_type xref:#unordered_map_bucket_count[bucket_count]() const noexcept;
|
||||
size_type xref:#unordered_map_max_bucket_count[max_bucket_count]() const noexcept;
|
||||
size_type xref:#unordered_map_bucket_size[bucket_size](size_type n) const;
|
||||
size_type xref:#unordered_map_bucket[bucket](const key_type& k) const;
|
||||
template<class K> size_type xref:#unordered_map_bucket[bucket](const K& k) const;
|
||||
local_iterator xref:#unordered_map_begin_2[begin](size_type n);
|
||||
const_local_iterator xref:#unordered_map_begin_2[begin](size_type n) const;
|
||||
local_iterator xref:#unordered_map_end_2[end](size_type n);
|
||||
@@ -209,26 +221,75 @@ namespace boost {
|
||||
void xref:#unordered_map_rehash[rehash](size_type n);
|
||||
void xref:#unordered_map_reserve[reserve](size_type n);
|
||||
};
|
||||
|
||||
// Deduction Guides
|
||||
template<class InputIterator,
|
||||
class Hash = boost::hash<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
class Pred = std::equal_to<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
class Allocator = std::allocator<xref:#unordered_map_iter_to_alloc_type[__iter-to-alloc-type__]<InputIterator>>>
|
||||
unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash, Pred,
|
||||
Allocator>;
|
||||
|
||||
template<class Key, class T, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<const Key, T>>>
|
||||
unordered_map(std::initializer_list<std::pair<Key, T>>,
|
||||
typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__], Hash = Hash(),
|
||||
Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_map<Key, T, Hash, Pred, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Hash, Allocator)
|
||||
-> unordered_map<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
|
||||
std::equal_to<xref:#unordered_map_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Allocator>
|
||||
unordered_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type,
|
||||
Allocator)
|
||||
-> unordered_map<Key, T, boost::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Allocator>
|
||||
unordered_map(std::initializer_list<std::pair<Key, T>>, Allocator)
|
||||
-> unordered_map<Key, T, boost::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Hash, class Allocator>
|
||||
unordered_map(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_map<Key, T, Hash, std::equal_to<Key>, Allocator>;
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_map_operator_2[operator==](const unordered_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_map_operator_3[operator!=](const unordered_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_map_swap_2[swap](unordered_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_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 unordered_map<K, T, H, P, A>::size_type
|
||||
xref:#unordered_map_erase_if[erase_if](unordered_map<K, T, H, P, A>& c, Predicate pred);
|
||||
}
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_map_operator_2[operator==](const unordered_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_map_operator_3[operator!=](const unordered_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_map<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_map_swap_2[swap](unordered_map<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_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 unordered_map<K, T, H, P, A>::size_type
|
||||
xref:#unordered_map_erase_if[erase_if](unordered_map<K, T, H, P, A>& c, Predicate pred);
|
||||
-----
|
||||
|
||||
---
|
||||
@@ -948,6 +1009,8 @@ template<class... Args>
|
||||
std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
|
||||
template <class K, class... Args>
|
||||
std::pair<iterator, bool> try_emplace(K&& k, Args&&... args)
|
||||
```
|
||||
|
||||
Inserts a new node into the container if there is no existing element with key `k` contained within it.
|
||||
@@ -963,9 +1026,15 @@ Notes:;; This function is similiar to xref:#unordered_map_emplace[emplace] excep
|
||||
+
|
||||
--
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -974,6 +1043,8 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr
|
||||
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
The `template <class K, class... Args>` 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.
|
||||
|
||||
If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics.
|
||||
|
||||
Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`.
|
||||
@@ -987,6 +1058,8 @@ template<class... Args>
|
||||
iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args);
|
||||
template<class... Args>
|
||||
iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args);
|
||||
template<class K, class... Args>
|
||||
iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
|
||||
```
|
||||
|
||||
Inserts a new node into the container if there is no existing element with key `k` contained within it.
|
||||
@@ -1002,9 +1075,15 @@ Notes:;; This function is similiar to xref:#unordered_map_emplace_hint[emplace_h
|
||||
+
|
||||
--
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -1015,6 +1094,8 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr
|
||||
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
The `template <class K, class... Args>` 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.
|
||||
|
||||
If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics.
|
||||
|
||||
Since existing `std::pair` implementations don't support `std::piecewise_construct` this emulates it, but using `boost::unordered::piecewise_construct`.
|
||||
@@ -1028,6 +1109,8 @@ template<class M>
|
||||
std::pair<iterator, bool> insert_or_assign(const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
std::pair<iterator, bool> insert_or_assign(K&& k, M&& obj);
|
||||
```
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
@@ -1036,9 +1119,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for
|
||||
|
||||
If there is no such element, it is added to the container as:
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -1048,7 +1137,9 @@ If an insert took place, then the iterator points to the newly inserted element.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
|
||||
+
|
||||
Pointers and references to elements are never invalidated.
|
||||
Pointers and references to elements are never invalidated. +
|
||||
+
|
||||
The `template<class K, class M>` 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1058,6 +1149,8 @@ template<class M>
|
||||
iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj);
|
||||
template<class M>
|
||||
iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj);
|
||||
template<class K, class M>
|
||||
iterator insert_or_assign(const_iterator hint, K&& k, M&& obj);
|
||||
```
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
@@ -1066,9 +1159,15 @@ If there is an element with key `k`, then it is updated by assigning `boost::for
|
||||
|
||||
If there is no such element, it is added to the container as:
|
||||
```c++
|
||||
// first two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
|
||||
// third overload
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<M>(obj)))
|
||||
```
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted.
|
||||
@@ -1080,7 +1179,9 @@ Notes:;; The standard is fairly vague on the meaning of the hint. But the only p
|
||||
+
|
||||
Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
|
||||
+
|
||||
Pointers and references to elements are never invalidated.
|
||||
Pointers and references to elements are never invalidated. +
|
||||
+
|
||||
The `template<class K, class M>` 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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1100,30 +1201,17 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u
|
||||
==== Extract by Key
|
||||
```c++
|
||||
node_type extract(const key_type& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Extract by Key
|
||||
```c++
|
||||
template<class K> node_type extract(K&& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. +
|
||||
+
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1202,28 +1290,15 @@ Notes:;; In older versions this could be inefficient because it had to search th
|
||||
==== Erase by Key
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Erase by Key
|
||||
```c++
|
||||
template<class K> size_type erase(K&& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1441,6 +1516,7 @@ Notes:;; The `template <typename K>` overloads only participate in overload reso
|
||||
```c++
|
||||
mapped_type& operator[](const key_type& k);
|
||||
mapped_type& operator[](key_type&& k);
|
||||
template<class K> mapped_type& operator[](K&& k);
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -1449,7 +1525,9 @@ Returns:;; A reference to `x.second` where `x` is the element already in the con
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
|
||||
+
|
||||
Pointers and references to elements are never invalidated.
|
||||
Pointers and references to elements are never invalidated. +
|
||||
+
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1457,11 +1535,14 @@ Pointers and references to elements are never invalidated.
|
||||
```c++
|
||||
mapped_type& at(const key_type& k);
|
||||
const mapped_type& at(const key_type& k) const;
|
||||
template<class K> mapped_type& at(const K& k);
|
||||
template<class K> const mapped_type& at(const K& k) const;
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`.
|
||||
Throws:;; An exception object of type `std::out_of_range` if no such element is present.
|
||||
Notes:;; The `template<class K>` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
|
||||
|
||||
---
|
||||
|
||||
@@ -1501,11 +1582,13 @@ Returns:;; The number of elements in bucket `n`.
|
||||
==== bucket
|
||||
```c++
|
||||
size_type bucket(const key_type& k) const;
|
||||
template<class K> size_type bucket(const K& k) const;
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The index of the bucket which would contain an element with key `k`.
|
||||
Postconditions:;; The return value is less than `bucket_count()`.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1620,6 +1703,51 @@ Invalidates iterators, and changes the order of elements. Pointers and reference
|
||||
[horizontal]
|
||||
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
|
||||
|
||||
=== Deduction Guides
|
||||
A deduction guide will not participate in overload resolution if any of the following are true:
|
||||
|
||||
- It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
|
||||
- It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter.
|
||||
- It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter.
|
||||
- It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter.
|
||||
|
||||
A `size_type` parameter type in a deduction guide refers to the `size_type` member type of the
|
||||
container type deduced by the deduction guide. Its default value coincides with the default value
|
||||
of the constructor selected.
|
||||
|
||||
==== __iter-value-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-value-type__ =
|
||||
typename std::iterator_traits<InputIterator>::value_type; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-key-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-key-type__ = std::remove_const_t<
|
||||
std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-mapped-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-mapped-type__ =
|
||||
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-to-alloc-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-to-alloc-type__ = std::pair<
|
||||
std::add_const_t<std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>,
|
||||
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
|
||||
-----
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
||||
@@ -111,14 +111,14 @@ namespace boost {
|
||||
|
||||
node_type xref:#unordered_multimap_extract_by_iterator[extract](const_iterator position);
|
||||
node_type xref:#unordered_multimap_extract_by_key[extract](const key_type& k);
|
||||
template<class K> node_type xref:#unordered_multimap_transparent_extract_by_key[extract](K&& k);
|
||||
template<class K> node_type xref:#unordered_multimap_extract_by_key[extract](K&& k);
|
||||
iterator xref:#unordered_multimap_insert_with_node_handle[insert](node_type&& nh);
|
||||
iterator xref:#unordered_multimap_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh);
|
||||
|
||||
iterator xref:#unordered_multimap_erase_by_position[erase](iterator position);
|
||||
iterator xref:#unordered_multimap_erase_by_position[erase](const_iterator position);
|
||||
size_type xref:#unordered_multimap_erase_by_key[erase](const key_type& k);
|
||||
template<class K> size_type xref:#unordered_multimap_transparent_erase_by_key[erase](K&& k);
|
||||
template<class K> size_type xref:#unordered_multimap_erase_by_key[erase](K&& k);
|
||||
iterator xref:#unordered_multimap_erase_range[erase](const_iterator first, const_iterator last);
|
||||
void xref:#unordered_multimap_quick_erase[quick_erase](const_iterator position);
|
||||
void xref:#unordered_multimap_erase_return_void[erase_return_void](const_iterator position);
|
||||
@@ -172,6 +172,7 @@ namespace boost {
|
||||
size_type xref:#unordered_multimap_max_bucket_count[max_bucket_count]() const noexcept;
|
||||
size_type xref:#unordered_multimap_bucket_size[bucket_size](size_type n) const;
|
||||
size_type xref:#unordered_multimap_bucket[bucket](const key_type& k) const;
|
||||
template<class K> size_type xref:#unordered_multimap_bucket[bucket](const K& k) const;
|
||||
local_iterator xref:#unordered_multimap_begin_2[begin](size_type n);
|
||||
const_local_iterator xref:#unordered_multimap_begin_2[begin](size_type n) const;
|
||||
local_iterator xref:#unordered_multimap_end_2[end](size_type n);
|
||||
@@ -186,27 +187,76 @@ namespace boost {
|
||||
void xref:#unordered_multimap_rehash[rehash](size_type n);
|
||||
void xref:#unordered_multimap_reserve[reserve](size_type n);
|
||||
};
|
||||
|
||||
// Deduction Guides
|
||||
template<class InputIterator,
|
||||
class Hash = boost::hash<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
class Pred = std::equal_to<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
class Allocator = std::allocator<xref:#unordered_multimap_iter_to_alloc_type[__iter-to-alloc-type__]<InputIterator>>>
|
||||
unordered_multimap(InputIterator, InputIterator, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type = xref:#unordered_multimap_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
|
||||
Pred, Allocator>;
|
||||
|
||||
template<class Key, class T, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<const Key, T>>>
|
||||
unordered_multimap(std::initializer_list<std::pair<Key, T>>,
|
||||
typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type = xref:#unordered_multimap_deduction_guides[__see below__], Hash = Hash(),
|
||||
Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_multimap<Key, T, Hash, Pred, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_multimap(InputIterator, InputIterator, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_multimap(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_multimap(InputIterator, InputIterator, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_multimap<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__]<InputIterator>, Hash,
|
||||
std::equal_to<xref:#unordered_multimap_iter_key_type[__iter-key-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Allocator>
|
||||
unordered_multimap(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type,
|
||||
Allocator)
|
||||
-> unordered_multimap<Key, T, boost::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Allocator>
|
||||
unordered_multimap(std::initializer_list<std::pair<Key, T>>, Allocator)
|
||||
-> unordered_multimap<Key, T, boost::hash<Key>, std::equal_to<Key>, Allocator>;
|
||||
|
||||
template<class Key, class T, class Hash, class Allocator>
|
||||
unordered_multimap(std::initializer_list<std::pair<Key, T>>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type,
|
||||
Hash, Allocator)
|
||||
-> unordered_multimap<Key, T, Hash, std::equal_to<Key>, Allocator>;
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multimap_operator[operator++==++](const unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_multimap<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multimap_operator_2[operator!=](const unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_multimap<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_multimap_swap_2[swap](unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_multimap<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 unordered_multimap<K, T, H, P, A>::size_type
|
||||
xref:#unordered_multimap_erase_if[erase_if](unordered_multimap<K, T, H, P, A>& c, Predicate pred);
|
||||
}
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multimap_operator[operator++==++](const unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_multimap<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multimap_operator_2[operator!=](const unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
|
||||
const unordered_multimap<Key, T, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_multimap_swap_2[swap](unordered_multimap<Key, T, Hash, Pred, Alloc>& x,
|
||||
unordered_multimap<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 unordered_multimap<K, T, H, P, A>::size_type
|
||||
xref:#unordered_multimap_erase_if[erase_if](unordered_multimap<K, T, H, P, A>& c, Predicate pred);
|
||||
|
||||
-----
|
||||
|
||||
---
|
||||
@@ -915,30 +965,17 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u
|
||||
==== Extract by Key
|
||||
```c++
|
||||
node_type extract(const key_type& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Extract by Key
|
||||
```c++
|
||||
template<class K> node_type extract(K&& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. +
|
||||
+
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1011,28 +1048,15 @@ Notes:;; In older versions this could be inefficient because it had to search th
|
||||
==== Erase by Key
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Erase by Key
|
||||
```c++
|
||||
template<class K> size_type erase(K&& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1281,11 +1305,13 @@ Returns:;; The number of elements in bucket `n`.
|
||||
==== bucket
|
||||
```c++
|
||||
size_type bucket(const key_type& k) const;
|
||||
template<class K> size_type bucket(const K& k) const;
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The index of the bucket which would contain an element with key `k`.
|
||||
Postconditions:;; The return value is less than `bucket_count()`.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1402,6 +1428,51 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
|
||||
|
||||
---
|
||||
|
||||
=== Deduction Guides
|
||||
A deduction guide will not participate in overload resolution if any of the following are true:
|
||||
|
||||
- It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
|
||||
- It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter.
|
||||
- It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter.
|
||||
- It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter.
|
||||
|
||||
A `size_type` parameter type in a deduction guide refers to the `size_type` member type of the
|
||||
container type deduced by the deduction guide. Its default value coincides with the default value
|
||||
of the constructor selected.
|
||||
|
||||
==== __iter-value-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-value-type__ =
|
||||
typename std::iterator_traits<InputIterator>::value_type; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-key-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-key-type__ = std::remove_const_t<
|
||||
std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-mapped-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-mapped-type__ =
|
||||
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>; // exposition only
|
||||
-----
|
||||
|
||||
==== __iter-to-alloc-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-to-alloc-type__ = std::pair<
|
||||
std::add_const_t<std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>,
|
||||
std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]<InputIterator>>>; // exposition only
|
||||
-----
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
||||
@@ -107,14 +107,14 @@ namespace boost {
|
||||
|
||||
node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position);
|
||||
node_type xref:#unordered_multiset_extract_by_value[extract](const key_type& k);
|
||||
template<class K> node_type xref:#unordered_multiset_transparent_extract_by_value[extract](K&& k);
|
||||
template<class K> node_type xref:#unordered_multiset_extract_by_value[extract](K&& k);
|
||||
iterator xref:#unordered_multiset_insert_with_node_handle[insert](node_type&& nh);
|
||||
iterator xref:#unordered_multiset_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh);
|
||||
|
||||
iterator xref:#unordered_multiset_erase_by_position[erase](iterator position);
|
||||
iterator xref:#unordered_multiset_erase_by_position[erase](const_iterator position);
|
||||
size_type xref:#unordered_multiset_erase_by_value[erase](const key_type& k);
|
||||
template<class K> size_type xref:#unordered_multiset_transparent_erase_by_value[erase](K&& x);
|
||||
template<class K> size_type xref:#unordered_multiset_erase_by_value[erase](K&& x);
|
||||
iterator xref:#unordered_multiset_erase_range[erase](const_iterator first, const_iterator last);
|
||||
void xref:#unordered_multiset_quick_erase[quick_erase](const_iterator position);
|
||||
void xref:#unordered_multiset_erase_return_void[erase_return_void](const_iterator position);
|
||||
@@ -168,6 +168,7 @@ namespace boost {
|
||||
size_type xref:#unordered_multiset_max_bucket_count[max_bucket_count]() const noexcept;
|
||||
size_type xref:#unordered_multiset_bucket_size[bucket_size](size_type n) const;
|
||||
size_type xref:#unordered_multiset_bucket[bucket](const key_type& k) const;
|
||||
template<class K> size_type xref:#unordered_multiset_bucket[bucket](const K& k) const;
|
||||
local_iterator xref:#unordered_multiset_begin_2[begin](size_type n);
|
||||
const_local_iterator xref:#unordered_multiset_begin_2[begin](size_type n) const;
|
||||
local_iterator xref:#unordered_multiset_end_2[end](size_type n);
|
||||
@@ -182,26 +183,71 @@ namespace boost {
|
||||
void xref:#unordered_multiset_rehash[rehash](size_type n);
|
||||
void xref:#unordered_multiset_reserve[reserve](size_type n);
|
||||
};
|
||||
|
||||
// Deduction Guides
|
||||
template<class InputIterator,
|
||||
class Hash = boost::hash<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
class Pred = std::equal_to<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
class Allocator = std::allocator<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>>
|
||||
unordered_multiset(InputIterator, InputIterator, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
|
||||
|
||||
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
|
||||
class Allocator = std::allocator<T>>
|
||||
unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_multiset<T, Hash, Pred, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_multiset(InputIterator, InputIterator, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_multiset(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_multiset(InputIterator, InputIterator, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Hash,
|
||||
Allocator)
|
||||
-> unordered_multiset<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
|
||||
std::equal_to<xref:#unordered_multiset_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class T, class Allocator>
|
||||
unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_multiset<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template<class T, class Allocator>
|
||||
unordered_multiset(std::initializer_list<T>, Allocator)
|
||||
-> unordered_multiset<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template<class T, class Hash, class Allocator>
|
||||
unordered_multiset(std::initializer_list<T>, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Hash, Allocator)
|
||||
-> unordered_multiset<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multiset_operator[operator++==++](const unordered_multiset<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_multiset<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multiset_operator_2[operator!=](const unordered_multiset<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_multiset<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_multiset_swap_2[swap](unordered_multiset<Key, Hash, Pred, Alloc>& x,
|
||||
unordered_multiset<Key, Hash, Pred, Alloc>& y)
|
||||
noexcept(noexcept(x.swap(y)));
|
||||
|
||||
template<class K, class H, class P, class A, class Predicate>
|
||||
typename unordered_multiset<K, H, P, A>::size_type
|
||||
xref:#unordered_multiset_erase_if[erase_if](unordered_multiset<K, H, P, A>& c, Predicate pred);
|
||||
}
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multiset_operator[operator++==++](const unordered_multiset<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_multiset<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_multiset_operator_2[operator!=](const unordered_multiset<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_multiset<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_multiset_swap_2[swap](unordered_multiset<Key, Hash, Pred, Alloc>& x,
|
||||
unordered_multiset<Key, Hash, Pred, Alloc>& y)
|
||||
noexcept(noexcept(x.swap(y)));
|
||||
|
||||
template<class K, class H, class P, class A, class Predicate>
|
||||
typename unordered_multiset<K, H, P, A>::size_type
|
||||
xref:#unordered_multiset_erase_if[erase_if](unordered_multiset<K, H, P, A>& c, Predicate pred);
|
||||
-----
|
||||
|
||||
---
|
||||
@@ -877,6 +923,7 @@ Notes:;; A node extracted using this method can be inserted into a compatible `u
|
||||
==== Extract by Value
|
||||
```c++
|
||||
node_type extract(const key_type& k);
|
||||
template<class K> node_type extract(K&& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
@@ -884,23 +931,9 @@ Removes an element with key equivalent to `k`.
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Extract by Value
|
||||
```c++
|
||||
template<class K> node_type extract(K&& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.[horizontal]
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`.
|
||||
Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. +
|
||||
+
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -973,28 +1006,15 @@ Notes:;; In older versions this could be inefficient because it had to search th
|
||||
==== Erase by Value
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Erase by Value
|
||||
```c++
|
||||
template<class K> size_type erase(K&& x);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1243,11 +1263,13 @@ Returns:;; The number of elements in bucket `n`.
|
||||
==== bucket
|
||||
```c++
|
||||
size_type bucket(const key_type& k) const;
|
||||
template<class K> size_type bucket(const K& k) const;
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The index of the bucket which would contain an element with key `k`.
|
||||
Postconditions:;; The return value is less than `bucket_count()`.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1364,6 +1386,26 @@ Throws:;; The function has no effect if an exception is thrown, unless it is thr
|
||||
|
||||
---
|
||||
|
||||
=== Deduction Guides
|
||||
A deduction guide will not participate in overload resolution if any of the following are true:
|
||||
|
||||
- It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
|
||||
- It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter.
|
||||
- It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter.
|
||||
- It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter.
|
||||
|
||||
A `size_type` parameter type in a deduction guide refers to the `size_type` member type of the
|
||||
container type deduced by the deduction guide. Its default value coincides with the default value
|
||||
of the constructor selected.
|
||||
|
||||
==== __iter-value-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-value-type__ =
|
||||
typename std::iterator_traits<InputIterator>::value_type; // exposition only
|
||||
-----
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
||||
@@ -100,21 +100,23 @@ namespace boost {
|
||||
template<class... Args> iterator xref:#unordered_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args);
|
||||
std::pair<iterator, bool> xref:#unordered_set_copy_insert[insert](const value_type& obj);
|
||||
std::pair<iterator, bool> xref:#unordered_set_move_insert[insert](value_type&& obj);
|
||||
template<class K> std::pair<iterator, bool> xref:#unordered_set_transparent_insert[insert](K&& k);
|
||||
iterator xref:#unordered_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj);
|
||||
iterator xref:#unordered_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj);
|
||||
template<class K> iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k);
|
||||
template<class InputIterator> void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last);
|
||||
void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list<value_type>);
|
||||
|
||||
node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position);
|
||||
node_type xref:#unordered_set_extract_by_value[extract](const key_type& k);
|
||||
template<class K> node_type xref:#unordered_set_transparent_extract_by_value[extract](K&& k);
|
||||
template<class K> node_type xref:#unordered_set_extract_by_value[extract](K&& k);
|
||||
insert_return_type xref:#unordered_set_insert_with_node_handle[insert](node_type&& nh);
|
||||
iterator xref:#unordered_set_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh);
|
||||
|
||||
iterator xref:#unordered_set_erase_by_position[erase](iterator position);
|
||||
iterator xref:#unordered_set_erase_by_position[erase](const_iterator position);
|
||||
size_type xref:#unordered_set_erase_by_value[erase](const key_type& k);
|
||||
template<class K> size_type xref:#unordered_set_transparent_erase_by_value[erase](K&& k);
|
||||
template<class K> size_type xref:#unordered_set_erase_by_value[erase](K&& k);
|
||||
iterator xref:#unordered_set_erase_range[erase](const_iterator first, const_iterator last);
|
||||
void xref:#unordered_set_quick_erase[quick_erase](const_iterator position);
|
||||
void xref:#unordered_set_erase_return_void[erase_return_void](const_iterator position);
|
||||
@@ -168,6 +170,7 @@ namespace boost {
|
||||
size_type xref:#unordered_set_max_bucket_count[max_bucket_count]() const noexcept;
|
||||
size_type xref:#unordered_set_bucket_size[bucket_size](size_type n) const;
|
||||
size_type xref:#unordered_set_bucket[bucket](const key_type& k) const;
|
||||
template<class K> size_type xref:#unordered_set_bucket[bucket](const K& k) const;
|
||||
local_iterator xref:#unordered_set_begin_2[begin](size_type n);
|
||||
const_local_iterator xref:#unordered_set_begin_2[begin](size_type n) const;
|
||||
local_iterator xref:#unordered_set_end_2[end](size_type n);
|
||||
@@ -182,26 +185,70 @@ namespace boost {
|
||||
void xref:#unordered_set_rehash[rehash](size_type n);
|
||||
void xref:#unordered_set_reserve[reserve](size_type n);
|
||||
};
|
||||
|
||||
// Deduction Guides
|
||||
template<class InputIterator,
|
||||
class Hash = boost::hash<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
class Pred = std::equal_to<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
class Allocator = std::allocator<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>>
|
||||
unordered_set(InputIterator, InputIterator, typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash, Pred, Allocator>;
|
||||
|
||||
template<class T, class Hash = boost::hash<T>, class Pred = std::equal_to<T>,
|
||||
class Allocator = std::allocator<T>>
|
||||
unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__],
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_set<T, Hash, Pred, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_set(InputIterator, InputIterator, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_set(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>,
|
||||
boost::hash<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>,
|
||||
std::equal_to<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class InputIterator, class Hash, class Allocator>
|
||||
unordered_set(InputIterator, InputIterator, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Hash, Allocator)
|
||||
-> unordered_set<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>, Hash,
|
||||
std::equal_to<xref:#unordered_set_iter_value_type[__iter-value-type__]<InputIterator>>, Allocator>;
|
||||
|
||||
template<class T, class Allocator>
|
||||
unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator)
|
||||
-> unordered_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template<class T, class Allocator>
|
||||
unordered_set(std::initializer_list<T>, Allocator)
|
||||
-> unordered_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template<class T, class Hash, class Allocator>
|
||||
unordered_set(std::initializer_list<T>, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Hash, Allocator)
|
||||
-> unordered_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_set_operator[operator++==++](const unordered_set<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_set<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_set_operator_2[operator!=](const unordered_set<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_set<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_set_swap_2[swap](unordered_set<Key, Hash, Pred, Alloc>& x,
|
||||
unordered_set<Key, Hash, Pred, Alloc>& y)
|
||||
noexcept(noexcept(x.swap(y)));
|
||||
|
||||
template<class K, class H, class P, class A, class Predicate>
|
||||
typename unordered_set<K, H, P, A>::size_type
|
||||
xref:#unordered_set_erase_if[erase_if](unordered_set<K, H, P, A>& c, Predicate pred);
|
||||
}
|
||||
|
||||
// Equality Comparisons
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_set_operator[operator++==++](const unordered_set<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_set<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
bool xref:#unordered_set_operator_2[operator!=](const unordered_set<Key, Hash, Pred, Alloc>& x,
|
||||
const unordered_set<Key, Hash, Pred, Alloc>& y);
|
||||
|
||||
// swap
|
||||
template<class Key, class Hash, class Pred, class Alloc>
|
||||
void xref:#unordered_set_swap_2[swap](unordered_set<Key, Hash, Pred, Alloc>& x,
|
||||
unordered_set<Key, Hash, Pred, Alloc>& y)
|
||||
noexcept(noexcept(x.swap(y)));
|
||||
|
||||
template<class K, class H, class P, class A, class Predicate>
|
||||
typename unordered_set<K, H, P, A>::size_type
|
||||
xref:#unordered_set_erase_if[erase_if](unordered_set<K, H, P, A>& c, Predicate pred);
|
||||
-----
|
||||
|
||||
---
|
||||
@@ -803,6 +850,27 @@ Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Insert
|
||||
```c++
|
||||
template<class K> std::pair<iterator, bool> insert(K&& k);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `std::forward<K>(k)` in the container if and only if there is no element in the container with an equivalent key.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`.
|
||||
Returns:;; The bool component of the return type is true if an insert took place. +
|
||||
+
|
||||
If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
|
||||
+
|
||||
Pointers and references to elements are never invalidated. +
|
||||
+
|
||||
This 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.
|
||||
|
||||
---
|
||||
|
||||
==== Copy Insert with Hint
|
||||
```c++
|
||||
iterator insert(const_iterator hint, const value_type& obj);
|
||||
@@ -844,6 +912,29 @@ Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Insert with Hint
|
||||
```c++
|
||||
template<class K> iterator insert(const_iterator hint, K&& k);
|
||||
```
|
||||
|
||||
Inserts an element constructed from `std::forward<K>(k)` in the container if and only if there is no element in the container with an equivalent key.
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`.
|
||||
Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key.
|
||||
Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect.
|
||||
Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. +
|
||||
+
|
||||
Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
|
||||
+
|
||||
Pointers and references to elements are never invalidated. +
|
||||
+
|
||||
This 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.
|
||||
|
||||
---
|
||||
|
||||
==== Insert Iterator Range
|
||||
```c++
|
||||
template<class InputIterator> void insert(InputIterator first, InputIterator last);
|
||||
@@ -892,30 +983,17 @@ Notes:;; In C++17 a node extracted using this method can be inserted into a comp
|
||||
==== Extract by Value
|
||||
```c++
|
||||
node_type extract(const key_type& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Extract by Value
|
||||
```c++
|
||||
template<class K> node_type extract(K&& k);
|
||||
```
|
||||
|
||||
Removes an element with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet.
|
||||
Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. +
|
||||
+
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -994,28 +1072,15 @@ Notes:;; In older versions this could be inefficient because it had to search th
|
||||
==== Erase by Value
|
||||
```c++
|
||||
size_type erase(const key_type& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`.
|
||||
|
||||
---
|
||||
|
||||
==== Transparent Erase by Value
|
||||
```c++
|
||||
template<class K> size_type erase(K&& k);
|
||||
```
|
||||
|
||||
Erase all elements with key equivalent to `k`.
|
||||
|
||||
This 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.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The number of elements erased.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1265,11 +1330,13 @@ Returns:;; The number of elements in bucket `n`.
|
||||
==== bucket
|
||||
```c++
|
||||
size_type bucket(const key_type& k) const;
|
||||
template<class K> size_type bucket(const K& k) const;
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
Returns:;; The index of the bucket which would contain an element with key `k`.
|
||||
Postconditions:;; The return value is less than `bucket_count()`.
|
||||
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.
|
||||
|
||||
---
|
||||
|
||||
@@ -1384,6 +1451,26 @@ Invalidates iterators, and changes the order of elements. Pointers and reference
|
||||
Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function.
|
||||
|
||||
|
||||
=== Deduction Guides
|
||||
A deduction guide will not participate in overload resolution if any of the following are true:
|
||||
|
||||
- It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter.
|
||||
- It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter.
|
||||
- It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter.
|
||||
- It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter.
|
||||
|
||||
A `size_type` parameter type in a deduction guide refers to the `size_type` member type of the
|
||||
container type deduced by the deduction guide. Its default value coincides with the default value
|
||||
of the constructor selected.
|
||||
|
||||
==== __iter-value-type__
|
||||
[listings,subs="+macros,+quotes"]
|
||||
-----
|
||||
template<class InputIterator>
|
||||
using __iter-value-type__ =
|
||||
typename std::iterator_traits<InputIterator>::value_type; // exposition only
|
||||
-----
|
||||
|
||||
=== Equality Comparisons
|
||||
|
||||
==== operator==
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* Fast open-addressing hash table.
|
||||
*
|
||||
* Copyright 2022 Joaquin M Lopez Munoz.
|
||||
* Copyright 2022-2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_FOA_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_HPP
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/config/workaround.hpp>
|
||||
@@ -21,8 +23,11 @@
|
||||
#include <boost/core/pointer_traits.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <boost/predef.h>
|
||||
#include <boost/type_traits/has_trivial_copy.hpp>
|
||||
#include <boost/type_traits/is_nothrow_swappable.hpp>
|
||||
#include <boost/unordered/detail/narrow_cast.hpp>
|
||||
#include <boost/unordered/detail/xmx.hpp>
|
||||
#include <boost/unordered/detail/mulx.hpp>
|
||||
#include <boost/unordered/hash_traits.hpp>
|
||||
#include <climits>
|
||||
#include <cmath>
|
||||
@@ -30,6 +35,7 @@
|
||||
#include <cstring>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
@@ -67,6 +73,12 @@
|
||||
}while(0)
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred) \
|
||||
static_assert(boost::is_nothrow_swappable<Hash>::value, \
|
||||
"Template parameter Hash is required to be nothrow Swappable."); \
|
||||
static_assert(boost::is_nothrow_swappable<Pred>::value, \
|
||||
"Template parameter Pred is required to be nothrow Swappable");
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
@@ -261,12 +273,12 @@ private:
|
||||
0xF8F8F8F8u,0xF9F9F9F9u,0xFAFAFAFAu,0xFBFBFBFBu,0xFCFCFCFCu,0xFDFDFDFDu,0xFEFEFEFEu,0xFFFFFFFFu,
|
||||
};
|
||||
|
||||
return (int)word[(unsigned char)hash];
|
||||
return (int)word[narrow_cast<unsigned char>(hash)];
|
||||
}
|
||||
|
||||
inline static unsigned char reduced_hash(std::size_t hash)
|
||||
{
|
||||
return (unsigned char)match_word(hash);
|
||||
return narrow_cast<unsigned char>(match_word(hash));
|
||||
}
|
||||
|
||||
inline unsigned char& at(std::size_t pos)
|
||||
@@ -335,8 +347,8 @@ struct group15
|
||||
|
||||
inline int match(std::size_t hash)const
|
||||
{
|
||||
return simde_mm_movemask_epi8(
|
||||
vceqq_s8(m,vdupq_n_s8(reduced_hash(hash))))&0x7FFF;
|
||||
return simde_mm_movemask_epi8(vceqq_s8(
|
||||
m,vdupq_n_s8(static_cast<signed char>(reduced_hash(hash)))))&0x7FFF;
|
||||
}
|
||||
|
||||
inline bool is_not_overflowed(std::size_t hash)const
|
||||
@@ -517,7 +529,7 @@ struct group15
|
||||
std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
|
||||
group15 *pg=reinterpret_cast<group15*>(pc-pos);
|
||||
boost::uint64_t x=((pg->m[0])>>pos)&0x000100010001ull;
|
||||
boost::uint32_t y=static_cast<boost::uint32_t>(x|(x>>15)|(x>>30));
|
||||
boost::uint32_t y=narrow_cast<boost::uint32_t>(x|(x>>15)|(x>>30));
|
||||
return !pg->is_not_overflowed(y);
|
||||
};
|
||||
|
||||
@@ -532,7 +544,7 @@ struct group15
|
||||
inline int match_occupied()const
|
||||
{
|
||||
boost::uint64_t x=m[0]|m[1];
|
||||
boost::uint32_t y=static_cast<boost::uint32_t>(x|(x>>32));
|
||||
boost::uint32_t y=narrow_cast<boost::uint32_t>(x|(x>>32));
|
||||
y|=y>>16;
|
||||
return y&0x7FFF;
|
||||
}
|
||||
@@ -567,7 +579,7 @@ private:
|
||||
240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
|
||||
};
|
||||
|
||||
return table[(unsigned char)hash];
|
||||
return table[narrow_cast<unsigned char>(hash)];
|
||||
}
|
||||
|
||||
inline void set_impl(std::size_t pos,std::size_t n)
|
||||
@@ -716,9 +728,11 @@ private:
|
||||
std::size_t pos,step=0;
|
||||
};
|
||||
|
||||
/* Mixing policies: no_mix is the identity function and xmx_mix uses the
|
||||
* xmx function defined in <boost/unordered/detail/xmx.hpp>.
|
||||
* foa::table mixes hash results with xmx_mix unless the hash is marked as
|
||||
/* Mixing policies: no_mix is the identity function, xmx_mix uses the
|
||||
* xmx function defined in <boost/unordered/detail/xmx.hpp>, and mulx_mix
|
||||
* uses the mulx function from <boost/unordered/detail/mulx.hpp>.
|
||||
*
|
||||
* foa::table mixes hash results with mulx_mix unless the hash is marked as
|
||||
* avalanching, i.e. of good quality (see <boost/unordered/hash_traits.hpp>).
|
||||
*/
|
||||
|
||||
@@ -740,6 +754,15 @@ struct xmx_mix
|
||||
}
|
||||
};
|
||||
|
||||
struct mulx_mix
|
||||
{
|
||||
template<typename Hash,typename T>
|
||||
static inline std::size_t mix(const Hash& h,const T& x)
|
||||
{
|
||||
return mulx(h(x));
|
||||
}
|
||||
};
|
||||
|
||||
/* boost::core::countr_zero has a potentially costly check for
|
||||
* the case x==0.
|
||||
*/
|
||||
@@ -784,12 +807,15 @@ class table;
|
||||
/* internal conversion from const_iterator to iterator */
|
||||
class const_iterator_cast_tag {};
|
||||
|
||||
template<typename Value,typename Group,bool Const>
|
||||
template<typename TypePolicy,typename Group,bool Const>
|
||||
class table_iterator
|
||||
{
|
||||
using type_policy=TypePolicy;
|
||||
using table_element_type=typename type_policy::element_type;
|
||||
|
||||
public:
|
||||
using difference_type=std::ptrdiff_t;
|
||||
using value_type=Value;
|
||||
using value_type=typename type_policy::value_type;
|
||||
using pointer=
|
||||
typename std::conditional<Const,value_type const*,value_type*>::type;
|
||||
using reference=
|
||||
@@ -800,14 +826,15 @@ public:
|
||||
|
||||
table_iterator()=default;
|
||||
template<bool Const2,typename std::enable_if<!Const2>::type* =nullptr>
|
||||
table_iterator(const table_iterator<Value,Group,Const2>& x):
|
||||
table_iterator(const table_iterator<TypePolicy,Group,Const2>& x):
|
||||
pc{x.pc},p{x.p}{}
|
||||
table_iterator(
|
||||
const_iterator_cast_tag, const table_iterator<Value,Group,true>& x):
|
||||
const_iterator_cast_tag, const table_iterator<TypePolicy,Group,true>& x):
|
||||
pc{x.pc},p{x.p}{}
|
||||
|
||||
inline reference operator*()const noexcept{return *p;}
|
||||
inline pointer operator->()const noexcept{return p;}
|
||||
inline reference operator*()const noexcept{return type_policy::value_from(*p);}
|
||||
inline pointer operator->()const noexcept
|
||||
{return std::addressof(type_policy::value_from(*p));}
|
||||
inline table_iterator& operator++()noexcept{increment();return *this;}
|
||||
inline table_iterator operator++(int)noexcept
|
||||
{auto x=*this;increment();return x;}
|
||||
@@ -822,9 +849,9 @@ private:
|
||||
template<typename,typename,bool> friend class table_iterator;
|
||||
template<typename,typename,typename,typename> friend class table;
|
||||
|
||||
table_iterator(Group* pg,std::size_t n,const Value* p_):
|
||||
table_iterator(Group* pg,std::size_t n,const table_element_type* p_):
|
||||
pc{reinterpret_cast<unsigned char*>(const_cast<Group*>(pg))+n},
|
||||
p{const_cast<Value*>(p_)}
|
||||
p{const_cast<table_element_type*>(p_)}
|
||||
{}
|
||||
|
||||
inline std::size_t rebase() noexcept
|
||||
@@ -858,8 +885,8 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *pc=nullptr;
|
||||
Value *p=nullptr;
|
||||
unsigned char *pc=nullptr;
|
||||
table_element_type *p=nullptr;
|
||||
};
|
||||
|
||||
/* table_arrays controls allocation, initialization and deallocation of
|
||||
@@ -900,7 +927,10 @@ struct table_arrays
|
||||
template<typename Allocator>
|
||||
static table_arrays new_(Allocator& al,std::size_t n)
|
||||
{
|
||||
using alloc_traits=boost::allocator_traits<Allocator>;
|
||||
// using alloc_traits=boost::allocator_traits<Allocator>;
|
||||
using storage_allocator=
|
||||
typename boost::allocator_rebind<Allocator, Value>::type;
|
||||
using storage_traits=boost::allocator_traits<storage_allocator>;
|
||||
|
||||
auto groups_size_index=size_index_for<group_type,size_policy>(n);
|
||||
auto groups_size=size_policy::size(groups_size_index);
|
||||
@@ -910,8 +940,9 @@ struct table_arrays
|
||||
arrays.groups=dummy_groups<group_type,size_policy::min_size()>();
|
||||
}
|
||||
else{
|
||||
arrays.elements=
|
||||
boost::to_address(alloc_traits::allocate(al,buffer_size(groups_size)));
|
||||
auto sal=storage_allocator(al);
|
||||
arrays.elements=boost::to_address(
|
||||
storage_traits::allocate(sal,buffer_size(groups_size)));
|
||||
|
||||
/* Align arrays.groups to sizeof(group_type). table_iterator critically
|
||||
* depends on such alignment for its increment operation.
|
||||
@@ -935,13 +966,15 @@ struct table_arrays
|
||||
template<typename Allocator>
|
||||
static void delete_(Allocator& al,table_arrays& arrays)noexcept
|
||||
{
|
||||
using alloc_traits=boost::allocator_traits<Allocator>;
|
||||
using storage_alloc=typename boost::allocator_rebind<Allocator,Value>::type;
|
||||
using alloc_traits=boost::allocator_traits<storage_alloc>;
|
||||
using pointer=typename alloc_traits::pointer;
|
||||
using pointer_traits=boost::pointer_traits<pointer>;
|
||||
|
||||
auto sal=storage_alloc(al);
|
||||
if(arrays.elements){
|
||||
alloc_traits::deallocate(
|
||||
al,pointer_traits::pointer_to(*arrays.elements),
|
||||
sal,pointer_traits::pointer_to(*arrays.elements),
|
||||
buffer_size(arrays.groups_size_mask+1));
|
||||
}
|
||||
}
|
||||
@@ -994,6 +1027,7 @@ void swap_if(T&,T&){}
|
||||
|
||||
inline void prefetch(const void* p)
|
||||
{
|
||||
(void) p;
|
||||
#if defined(BOOST_GCC)||defined(BOOST_CLANG)
|
||||
__builtin_prefetch((const char*)p);
|
||||
#elif defined(BOOST_UNORDERED_SSE2)
|
||||
@@ -1001,6 +1035,49 @@ inline void prefetch(const void* p)
|
||||
#endif
|
||||
}
|
||||
|
||||
struct try_emplace_args_t{};
|
||||
|
||||
template<typename Allocator>
|
||||
struct is_std_allocator:std::false_type{};
|
||||
|
||||
template<typename T>
|
||||
struct is_std_allocator<std::allocator<T>>:std::true_type{};
|
||||
|
||||
/* std::allocator::construct marked as deprecated */
|
||||
#if defined(_LIBCPP_SUPPRESS_DEPRECATED_PUSH)
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_PUSH
|
||||
#elif defined(_STL_DISABLE_DEPRECATED_WARNING)
|
||||
_STL_DISABLE_DEPRECATED_WARNING
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable:4996)
|
||||
#endif
|
||||
|
||||
template<typename Allocator,typename Ptr,typename... Args>
|
||||
struct alloc_has_construct
|
||||
{
|
||||
private:
|
||||
template<typename Allocator2>
|
||||
static decltype(
|
||||
std::declval<Allocator2&>().construct(
|
||||
std::declval<Ptr>(),std::declval<Args&&>()...),
|
||||
std::true_type{}
|
||||
) check(int);
|
||||
|
||||
template<typename> static std::false_type check(...);
|
||||
|
||||
public:
|
||||
static constexpr bool value=decltype(check<Allocator>(0))::value;
|
||||
};
|
||||
|
||||
#if defined(_LIBCPP_SUPPRESS_DEPRECATED_POP)
|
||||
_LIBCPP_SUPPRESS_DEPRECATED_POP
|
||||
#elif defined(_STL_RESTORE_DEPRECATED_WARNING)
|
||||
_STL_RESTORE_DEPRECATED_WARNING
|
||||
#elif defined(_MSC_VER)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_GCC)
|
||||
/* GCC's -Wshadow triggers at scenarios like this:
|
||||
*
|
||||
@@ -1101,7 +1178,7 @@ table:empty_value<Hash,0>,empty_value<Pred,1>,empty_value<Allocator,2>
|
||||
using mix_policy=typename std::conditional<
|
||||
hash_is_avalanching<Hash>::value,
|
||||
no_mix,
|
||||
xmx_mix
|
||||
mulx_mix
|
||||
>::type;
|
||||
using alloc_traits=boost::allocator_traits<Allocator>;
|
||||
|
||||
@@ -1109,6 +1186,7 @@ public:
|
||||
using key_type=typename type_policy::key_type;
|
||||
using init_type=typename type_policy::init_type;
|
||||
using value_type=typename type_policy::value_type;
|
||||
using element_type=typename type_policy::element_type;
|
||||
|
||||
private:
|
||||
static constexpr bool has_mutable_iterator=
|
||||
@@ -1124,10 +1202,10 @@ public:
|
||||
using const_reference=const value_type&;
|
||||
using size_type=std::size_t;
|
||||
using difference_type=std::ptrdiff_t;
|
||||
using const_iterator=table_iterator<value_type,group_type,true>;
|
||||
using const_iterator=table_iterator<type_policy,group_type,true>;
|
||||
using iterator=typename std::conditional<
|
||||
has_mutable_iterator,
|
||||
table_iterator<value_type,group_type,false>,
|
||||
table_iterator<type_policy,group_type,false>,
|
||||
const_iterator>::type;
|
||||
|
||||
table(
|
||||
@@ -1159,9 +1237,7 @@ public:
|
||||
table(const table& x,const Allocator& al_):
|
||||
table{std::size_t(std::ceil(float(x.size())/mlf)),x.h(),x.pred(),al_}
|
||||
{
|
||||
x.for_all_elements([this](value_type* p){
|
||||
unchecked_insert(*p);
|
||||
});
|
||||
copy_elements_from(x);
|
||||
}
|
||||
|
||||
table(table&& x,const Allocator& al_):
|
||||
@@ -1180,15 +1256,15 @@ public:
|
||||
/* This works because subsequent x.clear() does not depend on the
|
||||
* elements' values.
|
||||
*/
|
||||
x.for_all_elements([this](value_type* p){
|
||||
unchecked_insert(type_policy::move(*p));
|
||||
x.for_all_elements([this](element_type* p){
|
||||
unchecked_insert(type_policy::move(type_policy::value_from(*p)));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
~table()noexcept
|
||||
{
|
||||
for_all_elements([this](value_type* p){
|
||||
for_all_elements([this](element_type* p){
|
||||
destroy_element(p);
|
||||
});
|
||||
delete_arrays(arrays);
|
||||
@@ -1196,22 +1272,35 @@ public:
|
||||
|
||||
table& operator=(const table& x)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred)
|
||||
|
||||
static constexpr auto pocca=
|
||||
alloc_traits::propagate_on_container_copy_assignment::value;
|
||||
|
||||
if(this!=std::addressof(x)){
|
||||
clear();
|
||||
h()=x.h();
|
||||
pred()=x.pred();
|
||||
// if copy construction here winds up throwing, the container is still
|
||||
// left intact so we perform these operations first
|
||||
hasher tmp_h=x.h();
|
||||
key_equal tmp_p=x.pred();
|
||||
|
||||
// already noexcept, clear() before we swap the Hash, Pred just in case
|
||||
// the clear() impl relies on them at some point in the future
|
||||
clear();
|
||||
|
||||
// because we've asserted at compile-time that Hash and Pred are nothrow
|
||||
// swappable, we can safely mutate our source container and maintain
|
||||
// consistency between the Hash, Pred compatibility
|
||||
using std::swap;
|
||||
swap(h(),tmp_h);
|
||||
swap(pred(),tmp_p);
|
||||
|
||||
if_constexpr<pocca>([&,this]{
|
||||
if(al()!=x.al())reserve(0);
|
||||
copy_assign_if<pocca>(al(),x.al());
|
||||
});
|
||||
/* noshrink: favor memory reuse over tightness */
|
||||
noshrink_reserve(x.size());
|
||||
x.for_all_elements([this](value_type* p){
|
||||
unchecked_insert(*p);
|
||||
});
|
||||
noshrink_reserve(x.size());
|
||||
copy_elements_from(x);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
@@ -1223,19 +1312,32 @@ public:
|
||||
|
||||
table& operator=(table&& x)
|
||||
noexcept(
|
||||
alloc_traits::is_always_equal::value&&
|
||||
std::is_nothrow_move_assignable<Hash>::value&&
|
||||
std::is_nothrow_move_assignable<Pred>::value)
|
||||
alloc_traits::propagate_on_container_move_assignment::value||
|
||||
alloc_traits::is_always_equal::value)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred)
|
||||
|
||||
static constexpr auto pocma=
|
||||
alloc_traits::propagate_on_container_move_assignment::value;
|
||||
|
||||
if(this!=std::addressof(x)){
|
||||
/* Given ambiguity in implementation strategies briefly discussed here:
|
||||
* https://www.open-std.org/jtc1/sc22/wg21/docs/lwg-active.html#2227
|
||||
*
|
||||
* we opt into requiring nothrow swappability and eschew the move
|
||||
* operations associated with Hash, Pred.
|
||||
*
|
||||
* To this end, we ensure that the user never has to consider the
|
||||
* moved-from state of their Hash, Pred objects
|
||||
*/
|
||||
|
||||
using std::swap;
|
||||
|
||||
clear();
|
||||
h()=std::move(x.h());
|
||||
pred()=std::move(x.pred());
|
||||
swap(h(),x.h());
|
||||
swap(pred(),x.pred());
|
||||
|
||||
if(pocma||al()==x.al()){
|
||||
using std::swap;
|
||||
reserve(0);
|
||||
move_assign_if<pocma>(al(),x.al());
|
||||
swap(size_,x.size_);
|
||||
@@ -1251,8 +1353,8 @@ public:
|
||||
/* This works because subsequent x.clear() does not depend on the
|
||||
* elements' values.
|
||||
*/
|
||||
x.for_all_elements([this](value_type* p){
|
||||
unchecked_insert(type_policy::move(*p));
|
||||
x.for_all_elements([this](element_type* p){
|
||||
unchecked_insert(type_policy::move(type_policy::value_from(*p)));
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1286,24 +1388,26 @@ public:
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace(Args&&... args)
|
||||
{
|
||||
using emplace_type = typename std::conditional<
|
||||
/* We dispatch based on whether or not the value_type is constructible from
|
||||
* an rvalue refernce to the deduced emplace_type. We do this specifically
|
||||
* for the csae of the node-based containers. To this end, we're able to
|
||||
* avoid allocating a node when a duplicate element is attempted to be
|
||||
* inserted. For immovable types, we instead dispatch to the routine that
|
||||
* unconditionally allocates via `type_policy::construct()`.
|
||||
*/
|
||||
return emplace_dispatch(
|
||||
std::is_constructible<
|
||||
init_type, Args...
|
||||
>::value,
|
||||
init_type,
|
||||
value_type
|
||||
>::type;
|
||||
return emplace_impl(emplace_type(std::forward<Args>(args)...));
|
||||
value_type,
|
||||
emplace_type<Args...>&&>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Key,typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> try_emplace(
|
||||
Key&& k,Args&&... args)
|
||||
Key&& x,Args&&... args)
|
||||
{
|
||||
return emplace_impl(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
try_emplace_args_t{},std::forward<Key>(x),std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool>
|
||||
@@ -1322,6 +1426,14 @@ public:
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool>
|
||||
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,
|
||||
std::pair<iterator,bool>
|
||||
>::type
|
||||
insert(element_type&& x){return emplace_impl(std::move(x));}
|
||||
|
||||
template<
|
||||
bool dependent_value=false,
|
||||
typename std::enable_if<
|
||||
@@ -1352,16 +1464,15 @@ public:
|
||||
|
||||
void swap(table& x)
|
||||
noexcept(
|
||||
alloc_traits::is_always_equal::value&&
|
||||
boost::is_nothrow_swappable<Hash>::value&&
|
||||
boost::is_nothrow_swappable<Pred>::value)
|
||||
alloc_traits::propagate_on_container_swap::value||
|
||||
alloc_traits::is_always_equal::value)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred)
|
||||
|
||||
static constexpr auto pocs=
|
||||
alloc_traits::propagate_on_container_swap::value;
|
||||
|
||||
using std::swap;
|
||||
swap(h(),x.h());
|
||||
swap(pred(),x.pred());
|
||||
if_constexpr<pocs>([&,this]{
|
||||
swap_if<pocs>(al(),x.al());
|
||||
},
|
||||
@@ -1369,6 +1480,9 @@ public:
|
||||
BOOST_ASSERT(al()==x.al());
|
||||
(void)this; /* makes sure captured this is used */
|
||||
});
|
||||
|
||||
swap(h(),x.h());
|
||||
swap(pred(),x.pred());
|
||||
swap(size_,x.size_);
|
||||
swap(arrays,x.arrays);
|
||||
swap(ml,x.ml);
|
||||
@@ -1394,14 +1508,21 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
element_type extract(const_iterator pos)
|
||||
{
|
||||
BOOST_ASSERT(pos!=end());
|
||||
erase_on_exit e{*this,iterator{const_iterator_cast_tag{},pos}};
|
||||
(void)e;
|
||||
return std::move(*pos.p);
|
||||
}
|
||||
|
||||
// TODO: should we accept different allocator too?
|
||||
template<typename Hash2,typename Pred2>
|
||||
void merge(table<TypePolicy,Hash2,Pred2,Allocator>& x)
|
||||
{
|
||||
x.for_all_elements([&,this](group_type* pg,unsigned int n,value_type* p){
|
||||
if(emplace_impl(type_policy::move(*p)).second){
|
||||
x.erase(iterator{pg,n,p});
|
||||
}
|
||||
x.for_all_elements([&,this](group_type* pg,unsigned int n,element_type* p){
|
||||
erase_on_exit e{x,{pg,n,p}};
|
||||
if(!emplace_impl(type_policy::move(*p)).second)e.rollback();
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1461,7 +1582,16 @@ public:
|
||||
|
||||
private:
|
||||
template<typename,typename,typename,typename> friend class table;
|
||||
using arrays_type=table_arrays<value_type,group_type,size_policy>;
|
||||
using arrays_type=table_arrays<element_type,group_type,size_policy>;
|
||||
|
||||
template<typename... Args>
|
||||
using emplace_type = typename std::conditional<
|
||||
std::is_constructible<
|
||||
init_type,Args...
|
||||
>::value,
|
||||
init_type,
|
||||
value_type
|
||||
>::type;
|
||||
|
||||
struct clear_on_exit
|
||||
{
|
||||
@@ -1469,6 +1599,18 @@ private:
|
||||
table& x;
|
||||
};
|
||||
|
||||
struct erase_on_exit
|
||||
{
|
||||
erase_on_exit(table& x_,iterator it_):x{x_},it{it_}{}
|
||||
~erase_on_exit(){if(!rollback_)x.erase(it);}
|
||||
|
||||
void rollback(){rollback_=true;}
|
||||
|
||||
table& x;
|
||||
iterator it;
|
||||
bool rollback_=false;
|
||||
};
|
||||
|
||||
Hash& h(){return hash_base::get();}
|
||||
const Hash& h()const{return hash_base::get();}
|
||||
Pred& pred(){return pred_base::get();}
|
||||
@@ -1487,23 +1629,130 @@ private:
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
void construct_element(value_type* p,Args&&... args)
|
||||
void construct_element(element_type* p,Args&&... args)
|
||||
{
|
||||
alloc_traits::construct(al(),p,std::forward<Args>(args)...);
|
||||
type_policy::construct(al(),p,std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
void destroy_element(value_type* p)noexcept
|
||||
template<typename... Args>
|
||||
void construct_element(element_type* p,try_emplace_args_t,Args&&... args)
|
||||
{
|
||||
alloc_traits::destroy(al(),p);
|
||||
construct_element_from_try_emplace_args(
|
||||
p,
|
||||
std::integral_constant<bool,std::is_same<key_type,value_type>::value>{},
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template<typename Key,typename... Args>
|
||||
void construct_element_from_try_emplace_args(
|
||||
element_type* p,std::false_type,Key&& x,Args&&... args)
|
||||
{
|
||||
type_policy::construct(
|
||||
al(),p,
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(std::forward<Key>(x)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
/* This overload allows boost::unordered_flat_set to internally use
|
||||
* try_emplace to implement heterogeneous insert (P2363).
|
||||
*/
|
||||
|
||||
template<typename Key>
|
||||
void construct_element_from_try_emplace_args(
|
||||
element_type* p,std::true_type,Key&& x)
|
||||
{
|
||||
type_policy::construct(al(),p,std::forward<Key>(x));
|
||||
}
|
||||
|
||||
void destroy_element(element_type* p)noexcept
|
||||
{
|
||||
type_policy::destroy(al(),p);
|
||||
}
|
||||
|
||||
struct destroy_element_on_exit
|
||||
{
|
||||
~destroy_element_on_exit(){this_->destroy_element(p);}
|
||||
table *this_;
|
||||
value_type *p;
|
||||
table *this_;
|
||||
element_type *p;
|
||||
};
|
||||
|
||||
void copy_elements_from(const table& x)
|
||||
{
|
||||
BOOST_ASSERT(empty());
|
||||
BOOST_ASSERT(this!=std::addressof(x));
|
||||
if(arrays.groups_size_mask==x.arrays.groups_size_mask){
|
||||
fast_copy_elements_from(x);
|
||||
}
|
||||
else{
|
||||
x.for_all_elements([this](const element_type* p){
|
||||
unchecked_insert(*p);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
void fast_copy_elements_from(const table& x)
|
||||
{
|
||||
if(arrays.elements){
|
||||
copy_elements_array_from(x);
|
||||
std::memcpy(
|
||||
arrays.groups,x.arrays.groups,
|
||||
(arrays.groups_size_mask+1)*sizeof(group_type));
|
||||
size_=x.size();
|
||||
}
|
||||
}
|
||||
|
||||
void copy_elements_array_from(const table& x)
|
||||
{
|
||||
copy_elements_array_from(
|
||||
x,
|
||||
std::integral_constant<
|
||||
bool,
|
||||
#if BOOST_WORKAROUND(BOOST_LIBSTDCXX_VERSION,<50000)
|
||||
/* std::is_trivially_copy_constructible not provided */
|
||||
boost::has_trivial_copy<element_type>::value
|
||||
#else
|
||||
std::is_trivially_copy_constructible<element_type>::value
|
||||
#endif
|
||||
&&(
|
||||
is_std_allocator<Allocator>::value||
|
||||
!alloc_has_construct<Allocator,value_type*,const value_type&>::value)
|
||||
>{}
|
||||
);
|
||||
}
|
||||
|
||||
void copy_elements_array_from(const table& x,std::true_type /* -> memcpy */)
|
||||
{
|
||||
/* reinterpret_cast: GCC may complain about value_type not being trivially
|
||||
* copy-assignable when we're relying on trivial copy constructibility.
|
||||
*/
|
||||
std::memcpy(
|
||||
reinterpret_cast<unsigned char*>(arrays.elements),
|
||||
reinterpret_cast<unsigned char*>(x.arrays.elements),
|
||||
x.capacity()*sizeof(value_type));
|
||||
}
|
||||
|
||||
void copy_elements_array_from(const table& x,std::false_type /* -> manual */)
|
||||
{
|
||||
std::size_t num_constructed=0;
|
||||
BOOST_TRY{
|
||||
x.for_all_elements([&,this](const element_type* p){
|
||||
construct_element(arrays.elements+(p-x.arrays.elements),*p);
|
||||
++num_constructed;
|
||||
});
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
if(num_constructed){
|
||||
x.for_all_elements_while([&,this](const element_type* p){
|
||||
destroy_element(arrays.elements+(p-x.arrays.elements));
|
||||
return --num_constructed!=0;
|
||||
});
|
||||
}
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
void recover_slot(unsigned char* pc)
|
||||
{
|
||||
/* If this slot potentially caused overflow, we decrease the maximum load so
|
||||
@@ -1540,12 +1789,11 @@ private:
|
||||
return type_policy::extract(x);
|
||||
}
|
||||
|
||||
template<typename Arg1,typename Arg2>
|
||||
static inline auto key_from(
|
||||
std::piecewise_construct_t,const Arg1& k,const Arg2&)
|
||||
->decltype(std::get<0>(k))
|
||||
template<typename Key,typename... Args>
|
||||
static inline const Key& key_from(
|
||||
try_emplace_args_t,const Key& x,const Args&...)
|
||||
{
|
||||
return std::get<0>(k);
|
||||
return x;
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
@@ -1565,7 +1813,7 @@ private:
|
||||
return size_policy::position(hash,arrays_.groups_size_index);
|
||||
}
|
||||
|
||||
static inline void prefetch_elements(const value_type* p)
|
||||
static inline void prefetch_elements(const element_type* p)
|
||||
{
|
||||
/* We have experimentally confirmed that ARM architectures get a higher
|
||||
* speedup when around the first half of the element slots in a group are
|
||||
@@ -1603,6 +1851,7 @@ private:
|
||||
auto pg=arrays.groups+pos;
|
||||
auto mask=pg->match(hash);
|
||||
if(mask){
|
||||
BOOST_UNORDERED_ASSUME(arrays.elements != nullptr);
|
||||
auto p=arrays.elements+pos*N;
|
||||
prefetch_elements(p);
|
||||
do{
|
||||
@@ -1625,6 +1874,29 @@ private:
|
||||
#pragma warning(pop) /* C4800 */
|
||||
#endif
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_dispatch(
|
||||
std::true_type,Args&&... args
|
||||
) {
|
||||
using emplace_type_t = emplace_type<Args...>;
|
||||
return emplace_impl(emplace_type_t(std::forward<Args>(args)...));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_dispatch(
|
||||
std::false_type,Args&&... args
|
||||
) {
|
||||
alignas(element_type)
|
||||
unsigned char buf[sizeof(element_type)];
|
||||
element_type* p = reinterpret_cast<element_type*>(buf);
|
||||
|
||||
type_policy::construct(al(),p,std::forward<Args>(args)...);
|
||||
destroy_element_on_exit d{this,p};
|
||||
(void)d;
|
||||
|
||||
return emplace_impl(type_policy::move(*p));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator,bool> emplace_impl(Args&&... args)
|
||||
{
|
||||
@@ -1700,24 +1972,20 @@ private:
|
||||
{
|
||||
std::size_t num_destroyed=0;
|
||||
BOOST_TRY{
|
||||
for_all_elements([&,this](value_type* p){
|
||||
for_all_elements([&,this](element_type* p){
|
||||
nosize_transfer_element(p,new_arrays_,num_destroyed);
|
||||
});
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
if(num_destroyed){
|
||||
for(auto pg=arrays.groups;;++pg){
|
||||
auto mask=pg->match_occupied();
|
||||
while(mask){
|
||||
auto nz=unchecked_countr_zero(mask);
|
||||
recover_slot(pg,nz);
|
||||
if(!(--num_destroyed))goto continue_;
|
||||
mask&=mask-1;
|
||||
for_all_elements_while(
|
||||
[&,this](group_type* pg,unsigned int n,element_type*){
|
||||
recover_slot(pg,n);
|
||||
return --num_destroyed!=0;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
continue_:
|
||||
for_all_elements(new_arrays_,[this](value_type* p){
|
||||
for_all_elements(new_arrays_,[this](element_type* p){
|
||||
destroy_element(p);
|
||||
});
|
||||
delete_arrays(new_arrays_);
|
||||
@@ -1728,7 +1996,7 @@ private:
|
||||
/* either all moved and destroyed or all copied */
|
||||
BOOST_ASSERT(num_destroyed==size()||num_destroyed==0);
|
||||
if(num_destroyed!=size()){
|
||||
for_all_elements([this](value_type* p){
|
||||
for_all_elements([this](element_type* p){
|
||||
destroy_element(p);
|
||||
});
|
||||
}
|
||||
@@ -1763,18 +2031,19 @@ private:
|
||||
}
|
||||
|
||||
void nosize_transfer_element(
|
||||
value_type* p,const arrays_type& arrays_,std::size_t& num_destroyed)
|
||||
element_type* p,const arrays_type& arrays_,std::size_t& num_destroyed)
|
||||
{
|
||||
nosize_transfer_element(
|
||||
p,hash_for(key_from(*p)),arrays_,num_destroyed,
|
||||
std::integral_constant< /* std::move_if_noexcept semantics */
|
||||
bool,
|
||||
std::is_nothrow_move_constructible<init_type>::value||
|
||||
!std::is_copy_constructible<init_type>::value>{});
|
||||
!std::is_same<element_type,value_type>::value||
|
||||
!std::is_copy_constructible<element_type>::value>{});
|
||||
}
|
||||
|
||||
void nosize_transfer_element(
|
||||
value_type* p,std::size_t hash,const arrays_type& arrays_,
|
||||
element_type* p,std::size_t hash,const arrays_type& arrays_,
|
||||
std::size_t& num_destroyed,std::true_type /* ->move */)
|
||||
{
|
||||
/* Destroy p even if an an exception is thrown in the middle of move
|
||||
@@ -1788,12 +2057,12 @@ private:
|
||||
}
|
||||
|
||||
void nosize_transfer_element(
|
||||
value_type* p,std::size_t hash,const arrays_type& arrays_,
|
||||
element_type* p,std::size_t hash,const arrays_type& arrays_,
|
||||
std::size_t& /*num_destroyed*/,std::false_type /* ->copy */)
|
||||
{
|
||||
nosize_unchecked_emplace_at(
|
||||
arrays_,position_for(hash,arrays_),hash,
|
||||
const_cast<const value_type&>(*p));
|
||||
const_cast<const element_type&>(*p));
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
@@ -1830,8 +2099,8 @@ private:
|
||||
std::size_t erase_if_impl(Predicate pr)
|
||||
{
|
||||
std::size_t s=size();
|
||||
for_all_elements([&,this](group_type* pg,unsigned int n,value_type* p){
|
||||
if(pr(*p)) erase(iterator{pg,n,p});
|
||||
for_all_elements([&,this](group_type* pg,unsigned int n,element_type* p){
|
||||
if(pr(type_policy::value_from(*p))) erase(iterator{pg,n,p});
|
||||
});
|
||||
return std::size_t(s-size());
|
||||
}
|
||||
@@ -1846,13 +2115,35 @@ private:
|
||||
static auto for_all_elements(const arrays_type& arrays_,F f)
|
||||
->decltype(f(nullptr),void())
|
||||
{
|
||||
for_all_elements(
|
||||
arrays_,[&](group_type*,unsigned int,value_type* p){return f(p);});
|
||||
for_all_elements_while(arrays_,[&](element_type* p){f(p);return true;});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static auto for_all_elements(const arrays_type& arrays_,F f)
|
||||
->decltype(f(nullptr,0,nullptr),void())
|
||||
{
|
||||
for_all_elements_while(
|
||||
arrays_,[&](group_type* pg,unsigned int n,element_type* p)
|
||||
{f(pg,n,p);return true;});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
void for_all_elements_while(F f)const
|
||||
{
|
||||
for_all_elements_while(arrays,f);
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static auto for_all_elements_while(const arrays_type& arrays_,F f)
|
||||
->decltype(f(nullptr),void())
|
||||
{
|
||||
for_all_elements_while(
|
||||
arrays_,[&](group_type*,unsigned int,element_type* p){return f(p);});
|
||||
}
|
||||
|
||||
template<typename F>
|
||||
static auto for_all_elements_while(const arrays_type& arrays_,F f)
|
||||
->decltype(f(nullptr,0,nullptr),void())
|
||||
{
|
||||
auto p=arrays_.elements;
|
||||
if(!p){return;}
|
||||
@@ -1861,7 +2152,7 @@ private:
|
||||
auto mask=pg->match_really_occupied();
|
||||
while(mask){
|
||||
auto n=unchecked_countr_zero(mask);
|
||||
f(pg,n,p+n);
|
||||
if(!f(pg,n,p+n))return;
|
||||
mask&=mask-1;
|
||||
}
|
||||
}
|
||||
@@ -1891,6 +2182,7 @@ private:
|
||||
|
||||
#undef BOOST_UNORDERED_ASSUME
|
||||
#undef BOOST_UNORDERED_HAS_BUILTIN
|
||||
#undef BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED
|
||||
#ifdef BOOST_UNORDERED_LITTLE_ENDIAN_NEON
|
||||
#undef BOOST_UNORDERED_LITTLE_ENDIAN_NEON
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,196 @@
|
||||
/* Copyright 2023 Christian Mazakas.
|
||||
* 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_HANDLE_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
namespace foa{
|
||||
|
||||
template <class Iterator,class NodeType>
|
||||
struct insert_return_type
|
||||
{
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
union opt_storage {
|
||||
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS T t_;
|
||||
|
||||
opt_storage(){}
|
||||
~opt_storage(){}
|
||||
};
|
||||
|
||||
template <class TypePolicy,class Allocator>
|
||||
struct node_handle_base
|
||||
{
|
||||
protected:
|
||||
using type_policy=TypePolicy;
|
||||
using element_type=typename type_policy::element_type;
|
||||
|
||||
public:
|
||||
using allocator_type = Allocator;
|
||||
|
||||
private:
|
||||
using node_value_type=typename type_policy::value_type;
|
||||
node_value_type* p_=nullptr;
|
||||
BOOST_ATTRIBUTE_NO_UNIQUE_ADDRESS opt_storage<Allocator> a_;
|
||||
|
||||
protected:
|
||||
node_value_type& element()noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *p_;
|
||||
}
|
||||
|
||||
node_value_type const& element()const noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return *p_;
|
||||
}
|
||||
|
||||
Allocator& al()noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return a_.t_;
|
||||
}
|
||||
|
||||
Allocator const& al()const noexcept
|
||||
{
|
||||
BOOST_ASSERT(!empty());
|
||||
return a_.t_;
|
||||
}
|
||||
|
||||
void emplace(node_value_type* p,Allocator a)
|
||||
{
|
||||
BOOST_ASSERT(empty());
|
||||
p_=p;
|
||||
new(&a_.t_)Allocator(a);
|
||||
}
|
||||
|
||||
void emplace(element_type&& x,Allocator a)
|
||||
{
|
||||
emplace(x.p,a);
|
||||
x.p=nullptr;
|
||||
}
|
||||
|
||||
void clear()
|
||||
{
|
||||
al().~Allocator();
|
||||
p_=nullptr;
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr node_handle_base()noexcept{}
|
||||
|
||||
node_handle_base(node_handle_base&& nh) noexcept
|
||||
{
|
||||
if (!nh.empty()){
|
||||
emplace(nh.p_,nh.al());
|
||||
nh.clear();
|
||||
}
|
||||
}
|
||||
|
||||
node_handle_base& operator=(node_handle_base&& nh)noexcept
|
||||
{
|
||||
bool const pocma=
|
||||
boost::allocator_propagate_on_container_move_assignment<
|
||||
Allocator>::type::value;
|
||||
|
||||
BOOST_ASSERT(
|
||||
pocma
|
||||
||empty()
|
||||
||nh.empty()
|
||||
||(al()==nh.al()));
|
||||
|
||||
if(!empty()){
|
||||
type_policy::destroy(al(),p_);
|
||||
if (pocma&&!nh.empty()){al()=std::move(nh.al());}
|
||||
}
|
||||
|
||||
if(!nh.empty()){
|
||||
if(empty()){new(&a_.t_)Allocator(std::move(nh.al()));}
|
||||
p_=nh.p_;
|
||||
|
||||
nh.p_=nullptr;
|
||||
nh.a_.t_.~Allocator();
|
||||
}else if (!empty()){
|
||||
a_.t_.~Allocator();
|
||||
p_=nullptr;
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
~node_handle_base()
|
||||
{
|
||||
if(!empty()){
|
||||
type_policy::destroy(al(),p_);
|
||||
a_.t_.~Allocator();
|
||||
}
|
||||
}
|
||||
|
||||
allocator_type get_allocator()const noexcept{return al();}
|
||||
explicit operator bool()const noexcept{ return !empty();}
|
||||
BOOST_ATTRIBUTE_NODISCARD bool empty()const noexcept{return p_==nullptr;}
|
||||
|
||||
void swap(node_handle_base& nh) noexcept(
|
||||
boost::allocator_is_always_equal<Allocator>::type::value||
|
||||
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
|
||||
{
|
||||
using std::swap;
|
||||
|
||||
bool const pocs=
|
||||
boost::allocator_propagate_on_container_swap<Allocator>::type::value;
|
||||
|
||||
if (!empty()&&!nh.empty()){
|
||||
BOOST_ASSERT(pocs || al()==nh.al());
|
||||
|
||||
node_value_type *p=p_;
|
||||
p_=nh.p_;
|
||||
nh.p_=p;
|
||||
|
||||
if(pocs){
|
||||
swap(al(),nh.al());
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (empty()&&nh.empty()){return;}
|
||||
|
||||
if (empty()){
|
||||
emplace(nh.p_,nh.al());
|
||||
nh.clear();
|
||||
}else{
|
||||
nh.emplace(p_,al());
|
||||
clear();
|
||||
}
|
||||
}
|
||||
|
||||
friend
|
||||
void swap(node_handle_base& lhs,node_handle_base& rhs)
|
||||
noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
return lhs.swap(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_FOA_NODE_HANDLE_HPP
|
||||
@@ -1477,7 +1477,22 @@ namespace boost {
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
template <typename T, typename Alloc, typename Key>
|
||||
inline typename boost::allocator_pointer<Alloc>::type
|
||||
construct_node_from_key(T*, Alloc& alloc, BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return construct_node(alloc, boost::forward<Key>(k));
|
||||
}
|
||||
|
||||
template <typename T, typename V, typename Alloc, typename Key>
|
||||
inline typename boost::allocator_pointer<Alloc>::type
|
||||
construct_node_from_key(
|
||||
std::pair<T const, V>*, Alloc& alloc, BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return construct_node_pair(alloc, boost::forward<Key>(k));
|
||||
}
|
||||
} // namespace func
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2640,8 +2655,10 @@ namespace boost {
|
||||
} else {
|
||||
node_allocator_type alloc = node_alloc();
|
||||
|
||||
node_tmp tmp(
|
||||
detail::func::construct_node_pair(alloc, boost::forward<Key>(k)),
|
||||
value_type* dispatch = BOOST_NULLPTR;
|
||||
|
||||
node_tmp tmp(detail::func::construct_node_from_key(
|
||||
dispatch, alloc, boost::forward<Key>(k)),
|
||||
alloc);
|
||||
|
||||
if (size_ + 1 > max_load_) {
|
||||
@@ -2660,7 +2677,7 @@ namespace boost {
|
||||
template <typename Key>
|
||||
iterator try_emplace_hint_unique(c_iterator hint, BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
if (hint.p && this->key_eq()(hint->first, k)) {
|
||||
if (hint.p && this->key_eq()(extractor::extract(*hint), k)) {
|
||||
return iterator(hint.p, hint.itb);
|
||||
} else {
|
||||
return try_emplace_unique(k).first;
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#ifndef BOOST_UNORDERED_DETAIL_MULX_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_MULX_HPP
|
||||
|
||||
// Copyright 2022 Peter Dimov.
|
||||
// Copyright 2022 Joaquin M Lopez Munoz.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include <boost/cstdint.hpp>
|
||||
#include <climits>
|
||||
#include <cstddef>
|
||||
|
||||
#if defined(_MSC_VER) && !defined(__clang__)
|
||||
# include <intrin.h>
|
||||
#endif
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
|
||||
// Bit mixer based on the mulx primitive
|
||||
|
||||
#if defined(_MSC_VER) && defined(_M_X64) && !defined(__clang__)
|
||||
|
||||
__forceinline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t r2;
|
||||
boost::uint64_t r = _umul128( x, y, &r2 );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(_MSC_VER) && defined(_M_ARM64) && !defined(__clang__)
|
||||
|
||||
__forceinline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t r = x * y;
|
||||
boost::uint64_t r2 = __umulh( x, y );
|
||||
return r ^ r2;
|
||||
}
|
||||
|
||||
#elif defined(__SIZEOF_INT128__)
|
||||
|
||||
inline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
__uint128_t r = (__uint128_t)x * y;
|
||||
return (boost::uint64_t)r ^ (boost::uint64_t)( r >> 64 );
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
inline boost::uint64_t mulx64( boost::uint64_t x, boost::uint64_t y )
|
||||
{
|
||||
boost::uint64_t x1 = (boost::uint32_t)x;
|
||||
boost::uint64_t x2 = x >> 32;
|
||||
|
||||
boost::uint64_t y1 = (boost::uint32_t)y;
|
||||
boost::uint64_t y2 = y >> 32;
|
||||
|
||||
boost::uint64_t r3 = x2 * y2;
|
||||
|
||||
boost::uint64_t r2a = x1 * y2;
|
||||
|
||||
r3 += r2a >> 32;
|
||||
|
||||
boost::uint64_t r2b = x2 * y1;
|
||||
|
||||
r3 += r2b >> 32;
|
||||
|
||||
boost::uint64_t r1 = x1 * y1;
|
||||
|
||||
boost::uint64_t r2 = (r1 >> 32) + (boost::uint32_t)r2a + (boost::uint32_t)r2b;
|
||||
|
||||
r1 = (r2 << 32) + (boost::uint32_t)r1;
|
||||
r3 += r2 >> 32;
|
||||
|
||||
return r1 ^ r3;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
inline boost::uint32_t mulx32( boost::uint32_t x, boost::uint32_t y )
|
||||
{
|
||||
boost::uint64_t r = (boost::uint64_t)x * y;
|
||||
|
||||
#if defined(__MSVC_RUNTIME_CHECKS)
|
||||
|
||||
return (boost::uint32_t)(r & UINT32_MAX) ^ (boost::uint32_t)(r >> 32);
|
||||
|
||||
#else
|
||||
|
||||
return (boost::uint32_t)r ^ (boost::uint32_t)(r >> 32);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#if defined(SIZE_MAX)
|
||||
#if ((((SIZE_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_64B_ARCHITECTURE /* >64 bits assumed as 64 bits */
|
||||
#endif
|
||||
#elif defined(UINTPTR_MAX) /* used as proxy for std::size_t */
|
||||
#if ((((UINTPTR_MAX >> 16) >> 16) >> 16) >> 15) != 0
|
||||
#define BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#endif
|
||||
#endif
|
||||
|
||||
inline std::size_t mulx( std::size_t x ) noexcept
|
||||
{
|
||||
#if defined(BOOST_UNORDERED_64B_ARCHITECTURE)
|
||||
|
||||
// multiplier is phi
|
||||
return (std::size_t)mulx64( (boost::uint64_t)x, 0x9E3779B97F4A7C15ull );
|
||||
|
||||
#else /* 32 bits assumed */
|
||||
|
||||
// multiplier from https://arxiv.org/abs/2001.05304
|
||||
return mulx32( x, 0xE817FB2Du );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#undef BOOST_UNORDERED_64B_ARCHITECTURE
|
||||
#endif
|
||||
|
||||
} // namespace detail
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif // #ifndef BOOST_UNORDERED_DETAIL_MULX_HPP
|
||||
@@ -0,0 +1,44 @@
|
||||
/* Copyright 2022 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_NARROW_CAST_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_NARROW_CAST_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/static_assert.hpp>
|
||||
#include <boost/type_traits/is_integral.hpp>
|
||||
#include <boost/type_traits/make_unsigned.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
|
||||
template<typename To,typename From>
|
||||
BOOST_CONSTEXPR To narrow_cast(From x) BOOST_NOEXCEPT
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::is_integral<From>::value);
|
||||
BOOST_STATIC_ASSERT(boost::is_integral<To>::value);
|
||||
BOOST_STATIC_ASSERT(sizeof(From)>=sizeof(To));
|
||||
|
||||
return static_cast<To>(
|
||||
x
|
||||
|
||||
#if defined(__MSVC_RUNTIME_CHECKS)
|
||||
/* Avoids VS's "Run-Time Check Failure #1 - A cast to a smaller data type
|
||||
* has caused a loss of data."
|
||||
*/
|
||||
&static_cast<typename boost::make_unsigned<To>::type>(~static_cast<To>(0))
|
||||
#endif
|
||||
);
|
||||
}
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <boost/preprocessor/seq/enum.hpp>
|
||||
#include <boost/preprocessor/seq/for_each.hpp>
|
||||
#include <boost/preprocessor/seq/size.hpp>
|
||||
#include <boost/unordered/detail/narrow_cast.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
|
||||
@@ -118,7 +119,7 @@ namespace boost {
|
||||
std::size_t sizes_under_32bit = inv_sizes32_len;
|
||||
if (BOOST_LIKELY(size_index < sizes_under_32bit)) {
|
||||
return fast_modulo(
|
||||
boost::uint32_t(hash) + boost::uint32_t(hash >> 32),
|
||||
narrow_cast<boost::uint32_t>(hash) + narrow_cast<boost::uint32_t>(hash >> 32),
|
||||
inv_sizes32[size_index], boost::uint32_t(sizes[size_index]));
|
||||
} else {
|
||||
return positions[size_index - sizes_under_32bit](hash);
|
||||
|
||||
@@ -53,10 +53,10 @@ namespace boost {
|
||||
{
|
||||
};
|
||||
|
||||
template <class, class A, class B> struct are_transparent
|
||||
template <class, class Hash, class KeyEqual> struct are_transparent
|
||||
{
|
||||
static bool const value =
|
||||
is_transparent<A>::value && is_transparent<B>::value;
|
||||
is_transparent<Hash>::value && is_transparent<KeyEqual>::value;
|
||||
};
|
||||
|
||||
template <class Key, class UnorderedMap> struct transparent_non_iterable
|
||||
|
||||
@@ -32,10 +32,8 @@ namespace boost {
|
||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_flat_map
|
||||
{
|
||||
struct map_types
|
||||
namespace detail {
|
||||
template <class Key, class T> struct flat_map_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using raw_key_type = typename std::remove_const<Key>::type;
|
||||
@@ -45,19 +43,46 @@ namespace boost {
|
||||
using moved_type = std::pair<raw_key_type&&, raw_mapped_type&&>;
|
||||
using value_type = std::pair<Key const, T>;
|
||||
|
||||
using element_type = value_type;
|
||||
|
||||
static value_type& value_from(element_type& x) { return x; }
|
||||
|
||||
template <class K, class V>
|
||||
static raw_key_type const& extract(std::pair<K, V> const& kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
|
||||
static moved_type move(value_type& x)
|
||||
static moved_type move(element_type& x)
|
||||
{
|
||||
// TODO: we probably need to launder here
|
||||
return {std::move(const_cast<raw_key_type&>(x.first)),
|
||||
std::move(const_cast<raw_mapped_type&>(x.second))};
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void construct(A& al, element_type* p, moved_type&& x)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::move(x));
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_flat_map
|
||||
{
|
||||
using map_types = detail::flat_map_types<Key, T>;
|
||||
|
||||
using table_type = detail::foa::table<map_types, Hash, KeyEqual,
|
||||
typename boost::allocator_rebind<Allocator,
|
||||
@@ -278,24 +303,37 @@ namespace boost {
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj)
|
||||
{
|
||||
auto iter_bool_pair = table_.try_emplace(key, std::forward<M>(obj));
|
||||
if (iter_bool_pair.second) {
|
||||
return iter_bool_pair;
|
||||
auto ibp = table_.try_emplace(key, std::forward<M>(obj));
|
||||
if (ibp.second) {
|
||||
return ibp;
|
||||
}
|
||||
iter_bool_pair.first->second = std::forward<M>(obj);
|
||||
return iter_bool_pair;
|
||||
ibp.first->second = std::forward<M>(obj);
|
||||
return ibp;
|
||||
}
|
||||
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj)
|
||||
{
|
||||
auto iter_bool_pair =
|
||||
table_.try_emplace(std::move(key), std::forward<M>(obj));
|
||||
if (iter_bool_pair.second) {
|
||||
return iter_bool_pair;
|
||||
auto ibp = table_.try_emplace(std::move(key), std::forward<M>(obj));
|
||||
if (ibp.second) {
|
||||
return ibp;
|
||||
}
|
||||
iter_bool_pair.first->second = std::forward<M>(obj);
|
||||
return iter_bool_pair;
|
||||
ibp.first->second = std::forward<M>(obj);
|
||||
return ibp;
|
||||
}
|
||||
|
||||
template <class K, class M>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
insert_or_assign(K&& k, M&& obj)
|
||||
{
|
||||
auto ibp = table_.try_emplace(std::forward<K>(k), std::forward<M>(obj));
|
||||
if (ibp.second) {
|
||||
return ibp;
|
||||
}
|
||||
ibp.first->second = std::forward<M>(obj);
|
||||
return ibp;
|
||||
}
|
||||
|
||||
template <class M>
|
||||
@@ -311,6 +349,16 @@ namespace boost {
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class K, class M>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
iterator>::type
|
||||
insert_or_assign(const_iterator, K&& k, M&& obj)
|
||||
{
|
||||
return this->insert_or_assign(std::forward<K>(k), std::forward<M>(obj))
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
@@ -337,6 +385,17 @@ namespace boost {
|
||||
return table_.try_emplace(std::move(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K, class... Args>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_flat_map>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
try_emplace(K&& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(
|
||||
std::forward<K>(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE iterator try_emplace(
|
||||
const_iterator, key_type const& key, Args&&... args)
|
||||
@@ -352,6 +411,18 @@ namespace boost {
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class K, class... Args>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_flat_map>::value,
|
||||
iterator>::type
|
||||
try_emplace(const_iterator, K&& key, Args&&... args)
|
||||
{
|
||||
return table_
|
||||
.try_emplace(std::forward<K>(key), std::forward<Args>(args)...)
|
||||
.first;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void erase(iterator pos) { table_.erase(pos); }
|
||||
BOOST_FORCEINLINE void erase(const_iterator pos)
|
||||
{
|
||||
@@ -427,24 +498,61 @@ namespace boost {
|
||||
std::out_of_range("key was not found in unordered_flat_map"));
|
||||
}
|
||||
|
||||
mapped_type& operator[](key_type const& key)
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
mapped_type&>::type
|
||||
at(K&& key)
|
||||
{
|
||||
auto pos = table_.find(std::forward<K>(key));
|
||||
if (pos != table_.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
boost::throw_exception(
|
||||
std::out_of_range("key was not found in unordered_flat_map"));
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
mapped_type const&>::type
|
||||
at(K&& key) const
|
||||
{
|
||||
auto pos = table_.find(std::forward<K>(key));
|
||||
if (pos != table_.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
boost::throw_exception(
|
||||
std::out_of_range("key was not found in unordered_flat_map"));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE mapped_type& operator[](key_type const& key)
|
||||
{
|
||||
return table_.try_emplace(key).first->second;
|
||||
}
|
||||
|
||||
mapped_type& operator[](key_type&& key)
|
||||
BOOST_FORCEINLINE mapped_type& operator[](key_type&& key)
|
||||
{
|
||||
return table_.try_emplace(std::move(key)).first->second;
|
||||
}
|
||||
|
||||
size_type count(key_type const& key) const
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
mapped_type&>::type
|
||||
operator[](K&& key)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(key)).first->second;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type count(key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
return pos != table_.end() ? 1 : 0;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
count(K const& key) const
|
||||
{
|
||||
@@ -480,13 +588,13 @@ namespace boost {
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
bool contains(key_type const& key) const
|
||||
BOOST_FORCEINLINE bool contains(key_type const& key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool>::type
|
||||
contains(K const& key) const
|
||||
|
||||
@@ -30,17 +30,50 @@ namespace boost {
|
||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_flat_set
|
||||
{
|
||||
struct set_types
|
||||
namespace detail {
|
||||
template <class Key> struct flat_set_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using init_type = Key;
|
||||
using value_type = Key;
|
||||
|
||||
static Key const& extract(value_type const& key) { return key; }
|
||||
static Key&& move(value_type& x) { return std::move(x); }
|
||||
|
||||
using element_type = value_type;
|
||||
|
||||
static Key& value_from(element_type& x) { return x; }
|
||||
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
|
||||
template <class A>
|
||||
static void construct(A& al, element_type* p, element_type const& copy)
|
||||
{
|
||||
boost::allocator_construct(al, p, copy);
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void construct(A& al, element_type* p, Key&& x)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::move(x));
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
boost::allocator_construct(al, p, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_flat_set
|
||||
{
|
||||
using set_types = detail::flat_set_types<Key>;
|
||||
|
||||
using table_type = detail::foa::table<set_types, Hash, KeyEqual,
|
||||
typename boost::allocator_rebind<Allocator,
|
||||
@@ -231,6 +264,15 @@ namespace boost {
|
||||
return table_.insert(std::move(value));
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_flat_set>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
insert(K&& k)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(k));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value)
|
||||
{
|
||||
return table_.insert(value).first;
|
||||
@@ -241,6 +283,15 @@ namespace boost {
|
||||
return table_.insert(std::move(value)).first;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_flat_set>::value,
|
||||
iterator>::type
|
||||
insert(const_iterator, K&& k)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(k)).first;
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
@@ -313,14 +364,14 @@ namespace boost {
|
||||
/// Lookup
|
||||
///
|
||||
|
||||
size_type count(key_type const& key) const
|
||||
BOOST_FORCEINLINE size_type count(key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
return pos != table_.end() ? 1 : 0;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
count(K const& key) const
|
||||
{
|
||||
@@ -356,13 +407,13 @@ namespace boost {
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
bool contains(key_type const& key) const
|
||||
BOOST_FORCEINLINE bool contains(key_type const& key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool>::type
|
||||
contains(K const& key) const
|
||||
@@ -563,6 +614,21 @@ namespace boost {
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_flat_set(std::initializer_list<T>, std::size_t, Hash, Allocator)
|
||||
-> unordered_flat_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_flat_set(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_flat_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 T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_flat_set(std::initializer_list<T>, Allocator)
|
||||
-> unordered_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
#endif
|
||||
|
||||
} // namespace unordered
|
||||
|
||||
@@ -486,6 +486,16 @@ namespace boost {
|
||||
boost::move(k), boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Key, class... Args>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
try_emplace(Key&& k, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace_unique(
|
||||
boost::forward<Key>(k), boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator try_emplace(
|
||||
const_iterator hint, key_type const& k, BOOST_FWD_REF(Args)... args)
|
||||
@@ -502,6 +512,16 @@ namespace boost {
|
||||
hint, boost::move(k), boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Key, class... Args>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
iterator>::type
|
||||
try_emplace(const_iterator hint, Key&& k, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace_hint_unique(
|
||||
hint, boost::forward<Key>(k), boost::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
// In order to make this a template, this handles both:
|
||||
@@ -582,6 +602,43 @@ namespace boost {
|
||||
boost::forward<A1>(a1), boost::forward<A2>(a2)));
|
||||
}
|
||||
|
||||
// try_emplace(Key&&, Args&&...)
|
||||
|
||||
template <typename Key, typename A0>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
try_emplace(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
return table_.try_emplace_unique(
|
||||
boost::forward<Key>(k), boost::unordered::detail::create_emplace_args(
|
||||
boost::forward<A0>(a0)));
|
||||
}
|
||||
|
||||
template <typename Key, typename A0, typename A1>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
try_emplace(
|
||||
BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1)
|
||||
{
|
||||
return table_.try_emplace_unique(boost::forward<Key>(k),
|
||||
boost::unordered::detail::create_emplace_args(
|
||||
boost::forward<A0>(a0), boost::forward<A1>(a1)));
|
||||
}
|
||||
|
||||
template <typename Key, typename A0, typename A1, typename A2>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
try_emplace(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0,
|
||||
BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
|
||||
{
|
||||
return table_.try_emplace_unique(boost::forward<Key>(k),
|
||||
boost::unordered::detail::create_emplace_args(boost::forward<A0>(a0),
|
||||
boost::forward<A1>(a1), boost::forward<A2>(a2)));
|
||||
}
|
||||
|
||||
// try_emplace(const_iterator hint, key const&, Args&&...)
|
||||
|
||||
template <typename A0>
|
||||
@@ -640,6 +697,44 @@ namespace boost {
|
||||
boost::forward<A1>(a1), boost::forward<A2>(a2)));
|
||||
}
|
||||
|
||||
// try_emplace(const_iterator hint, Key&&, Args&&...)
|
||||
|
||||
template <typename Key, typename A0>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
iterator>::type
|
||||
try_emplace(
|
||||
const_iterator hint, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(A0) a0)
|
||||
{
|
||||
return table_.try_emplace_hint_unique(hint, boost::forward<Key>(k),
|
||||
boost::unordered::detail::create_emplace_args(
|
||||
boost::forward<A0>(a0)));
|
||||
}
|
||||
|
||||
template <typename Key, typename A0, typename A1>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
iterator>::type
|
||||
try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k,
|
||||
BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1)
|
||||
{
|
||||
return table_.try_emplace_hint_unique(hint, boost::forward<Key>(k),
|
||||
boost::unordered::detail::create_emplace_args(
|
||||
boost::forward<A0>(a0), boost::forward<A1>(a1)));
|
||||
}
|
||||
|
||||
template <typename Key, typename A0, typename A1, typename A2>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_map>::value,
|
||||
iterator>::type
|
||||
try_emplace(const_iterator hint, BOOST_FWD_REF(Key) k,
|
||||
BOOST_FWD_REF(A0) a0, BOOST_FWD_REF(A1) a1, BOOST_FWD_REF(A2) a2)
|
||||
{
|
||||
return table_.try_emplace_hint_unique(hint, boost::forward<Key>(k),
|
||||
boost::unordered::detail::create_emplace_args(boost::forward<A0>(a0),
|
||||
boost::forward<A1>(a1), boost::forward<A2>(a2)));
|
||||
}
|
||||
|
||||
#define BOOST_UNORDERED_TRY_EMPLACE(z, n, _) \
|
||||
\
|
||||
template <BOOST_PP_ENUM_PARAMS_Z(z, n, typename A)> \
|
||||
@@ -706,6 +801,15 @@ namespace boost {
|
||||
boost::move(k), boost::forward<M>(obj));
|
||||
}
|
||||
|
||||
template <class Key, class M>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
insert_or_assign(BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj)
|
||||
{
|
||||
return table_.insert_or_assign_unique(
|
||||
boost::forward<Key>(k), boost::forward<M>(obj));
|
||||
}
|
||||
|
||||
template <class M>
|
||||
iterator insert_or_assign(
|
||||
const_iterator, key_type const& k, BOOST_FWD_REF(M) obj)
|
||||
@@ -722,6 +826,18 @@ namespace boost {
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class Key, class M>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
iterator>::type
|
||||
insert_or_assign(
|
||||
const_iterator, BOOST_FWD_REF(Key) k, BOOST_FWD_REF(M) obj)
|
||||
{
|
||||
return table_
|
||||
.insert_or_assign_unique(
|
||||
boost::forward<Key>(k), boost::forward<M>(obj))
|
||||
.first;
|
||||
}
|
||||
|
||||
iterator erase(iterator);
|
||||
iterator erase(const_iterator);
|
||||
size_type erase(const key_type&);
|
||||
@@ -856,9 +972,23 @@ namespace boost {
|
||||
|
||||
mapped_type& operator[](const key_type&);
|
||||
mapped_type& operator[](BOOST_RV_REF(key_type));
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
mapped_type&>::type
|
||||
operator[](BOOST_FWD_REF(Key) k);
|
||||
|
||||
mapped_type& at(const key_type&);
|
||||
mapped_type const& at(const key_type&) const;
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
mapped_type&>::type at(BOOST_FWD_REF(Key) k);
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
mapped_type const&>::type at(BOOST_FWD_REF(Key) k) const;
|
||||
|
||||
// bucket interface
|
||||
|
||||
size_type bucket_count() const BOOST_NOEXCEPT
|
||||
@@ -878,6 +1008,14 @@ namespace boost {
|
||||
return table_.hash_to_bucket(table_.hash(k));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
size_type>::type
|
||||
bucket(BOOST_FWD_REF(Key) k) const
|
||||
{
|
||||
return table_.hash_to_bucket(table_.hash(boost::forward<Key>(k)));
|
||||
}
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return table_.begin(n);
|
||||
@@ -1584,6 +1722,14 @@ namespace boost {
|
||||
return table_.hash_to_bucket(table_.hash(k));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
size_type>::type
|
||||
bucket(BOOST_FWD_REF(Key) k) const
|
||||
{
|
||||
return table_.hash_to_bucket(table_.hash(boost::forward<Key>(k)));
|
||||
}
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n));
|
||||
@@ -2098,6 +2244,15 @@ namespace boost {
|
||||
return table_.try_emplace_unique(boost::move(k)).first->second;
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
typename unordered_map<K, T, H, P, A>::mapped_type&>::type
|
||||
unordered_map<K, T, H, P, A>::operator[](BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return table_.try_emplace_unique(boost::forward<Key>(k)).first->second;
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_map<K, T, H, P, A>::mapped_type&
|
||||
unordered_map<K, T, H, P, A>::at(const key_type& k)
|
||||
@@ -2130,6 +2285,42 @@ namespace boost {
|
||||
std::out_of_range("Unable to find key in unordered_map."));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
typename unordered_map<K, T, H, P, A>::mapped_type&>::type
|
||||
unordered_map<K, T, H, P, A>::at(BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
|
||||
if (table_.size_) {
|
||||
node_pointer p = table_.find_node(boost::forward<Key>(k));
|
||||
if (p)
|
||||
return p->value().second;
|
||||
}
|
||||
|
||||
boost::throw_exception(
|
||||
std::out_of_range("Unable to find key in unordered_map."));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
typename unordered_map<K, T, H, P, A>::mapped_type const&>::type
|
||||
unordered_map<K, T, H, P, A>::at(BOOST_FWD_REF(Key) k) const
|
||||
{
|
||||
typedef typename table::node_pointer node_pointer;
|
||||
|
||||
if (table_.size_) {
|
||||
node_pointer p = table_.find_node(boost::forward<Key>(k));
|
||||
if (p)
|
||||
return p->value().second;
|
||||
}
|
||||
|
||||
boost::throw_exception(
|
||||
std::out_of_range("Unable to find key in unordered_map."));
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
typename unordered_map<K, T, H, P, A>::size_type
|
||||
unordered_map<K, T, H, P, A>::bucket_size(size_type n) const
|
||||
|
||||
@@ -0,0 +1,992 @@
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_UNORDERED_NODE_MAP_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_UNORDERED_NODE_MAP_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/foa.hpp>
|
||||
#include <boost/unordered/detail/foa/node_handle.hpp>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
#include <boost/unordered/unordered_node_map_fwd.hpp>
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
template <class Key, class T> struct node_map_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using raw_key_type = typename std::remove_const<Key>::type;
|
||||
using raw_mapped_type = typename std::remove_const<T>::type;
|
||||
|
||||
using init_type = std::pair<raw_key_type, raw_mapped_type>;
|
||||
using value_type = std::pair<Key const, T>;
|
||||
using moved_type = std::pair<raw_key_type&&, raw_mapped_type&&>;
|
||||
|
||||
struct element_type
|
||||
{
|
||||
value_type* p;
|
||||
|
||||
/*
|
||||
* we use a deleted copy constructor here so the type is no longer
|
||||
* trivially copy-constructible which inhibits our memcpy
|
||||
* optimizations when copying the tables
|
||||
*/
|
||||
element_type() = default;
|
||||
element_type(element_type const&) = delete;
|
||||
element_type(element_type&& rhs) noexcept
|
||||
{
|
||||
p = rhs.p;
|
||||
rhs.p = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static value_type& value_from(element_type const& x) { return *(x.p); }
|
||||
|
||||
template <class K, class V>
|
||||
static raw_key_type const& extract(std::pair<K, V> const& kv)
|
||||
{
|
||||
return kv.first;
|
||||
}
|
||||
|
||||
static raw_key_type const& extract(element_type const& kv)
|
||||
{
|
||||
return kv.p->first;
|
||||
}
|
||||
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
static moved_type move(value_type& x)
|
||||
{
|
||||
return {std::move(const_cast<raw_key_type&>(x.first)),
|
||||
std::move(const_cast<raw_mapped_type&>(x.second))};
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void construct(A&, element_type* p, element_type&& x) noexcept
|
||||
{
|
||||
p->p = x.p;
|
||||
x.p = nullptr;
|
||||
}
|
||||
|
||||
template <class A>
|
||||
static void construct(A& al, element_type* p, element_type const& copy)
|
||||
{
|
||||
construct(al, p, *copy.p);
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
p->p = boost::to_address(boost::allocator_allocate(al, 1));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::allocator_construct(al, p->p, std::forward<Args>(args)...);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p->p),
|
||||
1);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p),
|
||||
1);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
destroy(al,p->p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class NodeMapTypes, class Allocator>
|
||||
struct node_map_handle
|
||||
: public detail::foa::node_handle_base<NodeMapTypes, Allocator>
|
||||
{
|
||||
private:
|
||||
using base_type =
|
||||
detail::foa::node_handle_base<NodeMapTypes, 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 NodeMapTypes::key_type;
|
||||
using mapped_type = typename NodeMapTypes::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->element().first);
|
||||
}
|
||||
|
||||
mapped_type& mapped() const
|
||||
{
|
||||
BOOST_ASSERT(!this->empty());
|
||||
return const_cast<mapped_type&>(this->element().second);
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_node_map
|
||||
{
|
||||
using map_types = detail::node_map_types<Key, T>;
|
||||
|
||||
using table_type = detail::foa::table<map_types, Hash, KeyEqual,
|
||||
typename boost::allocator_rebind<Allocator,
|
||||
std::pair<Key const, T> >::type>;
|
||||
|
||||
table_type table_;
|
||||
|
||||
template <class K, class V, class H, class KE, class A, class Pred>
|
||||
typename unordered_node_map<K, V, H, KE, A>::size_type friend erase_if(
|
||||
unordered_node_map<K, V, H, KE, A>& set, Pred pred);
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using value_type = typename map_types::value_type;
|
||||
using init_type = typename map_types::init_type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using hasher = typename boost::type_identity<Hash>::type;
|
||||
using key_equal = typename boost::type_identity<KeyEqual>::type;
|
||||
using allocator_type = typename boost::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 iterator = typename table_type::iterator;
|
||||
using const_iterator = typename table_type::const_iterator;
|
||||
using node_type = detail::node_map_handle<map_types,
|
||||
typename boost::allocator_rebind<Allocator,
|
||||
typename map_types::value_type>::type>;
|
||||
using insert_return_type =
|
||||
detail::foa::insert_return_type<iterator, node_type>;
|
||||
|
||||
unordered_node_map() : unordered_node_map(0) {}
|
||||
|
||||
explicit unordered_node_map(size_type n, hasher const& h = hasher(),
|
||||
key_equal const& pred = key_equal(),
|
||||
allocator_type const& a = allocator_type())
|
||||
: table_(n, h, pred, a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(size_type n, allocator_type const& a)
|
||||
: unordered_node_map(n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(size_type n, hasher const& h, allocator_type const& a)
|
||||
: unordered_node_map(n, h, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_node_map(
|
||||
InputIterator f, InputIterator l, allocator_type const& a)
|
||||
: unordered_node_map(f, l, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
explicit unordered_node_map(allocator_type const& a)
|
||||
: unordered_node_map(0, a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
unordered_node_map(Iterator first, Iterator last, size_type n = 0,
|
||||
hasher const& h = hasher(), key_equal const& pred = key_equal(),
|
||||
allocator_type const& a = allocator_type())
|
||||
: unordered_node_map(n, h, pred, a)
|
||||
{
|
||||
this->insert(first, last);
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
unordered_node_map(
|
||||
Iterator first, Iterator last, size_type n, allocator_type const& a)
|
||||
: unordered_node_map(first, last, n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
unordered_node_map(Iterator first, Iterator last, size_type n,
|
||||
hasher const& h, allocator_type const& a)
|
||||
: unordered_node_map(first, last, n, h, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(unordered_node_map const& other) : table_(other.table_)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(
|
||||
unordered_node_map const& other, allocator_type const& a)
|
||||
: table_(other.table_, a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(unordered_node_map&& other)
|
||||
noexcept(std::is_nothrow_move_constructible<hasher>::value&&
|
||||
std::is_nothrow_move_constructible<key_equal>::value&&
|
||||
std::is_nothrow_move_constructible<allocator_type>::value)
|
||||
: table_(std::move(other.table_))
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(unordered_node_map&& other, allocator_type const& al)
|
||||
: table_(std::move(other.table_), al)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(std::initializer_list<value_type> ilist,
|
||||
size_type n = 0, hasher const& h = hasher(),
|
||||
key_equal const& pred = key_equal(),
|
||||
allocator_type const& a = allocator_type())
|
||||
: unordered_node_map(ilist.begin(), ilist.end(), n, h, pred, a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(
|
||||
std::initializer_list<value_type> il, allocator_type const& a)
|
||||
: unordered_node_map(il, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(std::initializer_list<value_type> init, size_type n,
|
||||
allocator_type const& a)
|
||||
: unordered_node_map(init, n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_map(std::initializer_list<value_type> init, size_type n,
|
||||
hasher const& h, allocator_type const& a)
|
||||
: unordered_node_map(init, n, h, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
~unordered_node_map() = default;
|
||||
|
||||
unordered_node_map& operator=(unordered_node_map const& other)
|
||||
{
|
||||
table_ = other.table_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
unordered_node_map& operator=(unordered_node_map&& other) noexcept(
|
||||
noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
|
||||
{
|
||||
table_ = std::move(other.table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const noexcept
|
||||
{
|
||||
return table_.get_allocator();
|
||||
}
|
||||
|
||||
/// Iterators
|
||||
///
|
||||
|
||||
iterator begin() noexcept { return table_.begin(); }
|
||||
const_iterator begin() const noexcept { return table_.begin(); }
|
||||
const_iterator cbegin() const noexcept { return table_.cbegin(); }
|
||||
|
||||
iterator end() noexcept { return table_.end(); }
|
||||
const_iterator end() const noexcept { return table_.end(); }
|
||||
const_iterator cend() const noexcept { return table_.cend(); }
|
||||
|
||||
/// Capacity
|
||||
///
|
||||
|
||||
BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
|
||||
{
|
||||
return table_.empty();
|
||||
}
|
||||
|
||||
size_type size() const noexcept { return table_.size(); }
|
||||
|
||||
size_type max_size() const noexcept { return table_.max_size(); }
|
||||
|
||||
/// Modifiers
|
||||
///
|
||||
|
||||
void clear() noexcept { table_.clear(); }
|
||||
|
||||
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 std::pair<iterator, bool> insert(init_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value));
|
||||
}
|
||||
|
||||
template <class Ty>
|
||||
BOOST_FORCEINLINE auto insert(const_iterator, Ty&& value)
|
||||
-> decltype(table_.insert(std::forward<Ty>(value)).first)
|
||||
{
|
||||
return table_.insert(std::forward<Ty>(value)).first;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, init_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value)).first;
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
BOOST_FORCEINLINE void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
for (auto pos = first; pos != last; ++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)
|
||||
{
|
||||
if (nh.empty()) {
|
||||
return {end(), false, node_type{}};
|
||||
}
|
||||
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
typename map_types::element_type x;
|
||||
x.p=std::addressof(nh.element());
|
||||
|
||||
auto itp = table_.insert(std::move(x));
|
||||
if (itp.second) {
|
||||
nh.clear();
|
||||
return {itp.first, true, node_type{}};
|
||||
} else {
|
||||
return {itp.first, false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
iterator insert(const_iterator, node_type&& nh)
|
||||
{
|
||||
if (nh.empty()) {
|
||||
return end();
|
||||
}
|
||||
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
auto itp = table_.insert(map_types::move(nh.element()));
|
||||
return itp.first;
|
||||
}
|
||||
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type const& key, M&& obj)
|
||||
{
|
||||
auto ibp = table_.try_emplace(key, std::forward<M>(obj));
|
||||
if (ibp.second) {
|
||||
return ibp;
|
||||
}
|
||||
ibp.first->second = std::forward<M>(obj);
|
||||
return ibp;
|
||||
}
|
||||
|
||||
template <class M>
|
||||
std::pair<iterator, bool> insert_or_assign(key_type&& key, M&& obj)
|
||||
{
|
||||
auto ibp = table_.try_emplace(std::move(key), std::forward<M>(obj));
|
||||
if (ibp.second) {
|
||||
return ibp;
|
||||
}
|
||||
ibp.first->second = std::forward<M>(obj);
|
||||
return ibp;
|
||||
}
|
||||
|
||||
template <class K, class M>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
insert_or_assign(K&& k, M&& obj)
|
||||
{
|
||||
auto ibp = table_.try_emplace(std::forward<K>(k), std::forward<M>(obj));
|
||||
if (ibp.second) {
|
||||
return ibp;
|
||||
}
|
||||
ibp.first->second = std::forward<M>(obj);
|
||||
return ibp;
|
||||
}
|
||||
|
||||
template <class M>
|
||||
iterator insert_or_assign(const_iterator, key_type const& key, M&& obj)
|
||||
{
|
||||
return this->insert_or_assign(key, std::forward<M>(obj)).first;
|
||||
}
|
||||
|
||||
template <class M>
|
||||
iterator insert_or_assign(const_iterator, key_type&& key, M&& obj)
|
||||
{
|
||||
return this->insert_or_assign(std::move(key), std::forward<M>(obj))
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class K, class M>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
iterator>::type
|
||||
insert_or_assign(const_iterator, K&& k, M&& obj)
|
||||
{
|
||||
return this->insert_or_assign(std::forward<K>(k), std::forward<M>(obj))
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
|
||||
key_type const& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(key, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
|
||||
key_type&& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(std::move(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class K, class... Args>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_node_map>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
try_emplace(K&& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(
|
||||
std::forward<K>(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE iterator try_emplace(
|
||||
const_iterator, key_type const& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(key, std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE iterator try_emplace(
|
||||
const_iterator, key_type&& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(std::move(key), std::forward<Args>(args)...)
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class K, class... Args>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_node_map>::value,
|
||||
iterator>::type
|
||||
try_emplace(const_iterator, K&& key, Args&&... args)
|
||||
{
|
||||
return table_
|
||||
.try_emplace(std::forward<K>(key), std::forward<Args>(args)...)
|
||||
.first;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void erase(iterator pos) { table_.erase(pos); }
|
||||
BOOST_FORCEINLINE void erase(const_iterator pos)
|
||||
{
|
||||
return table_.erase(pos);
|
||||
}
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
while (first != last) {
|
||||
this->erase(first++);
|
||||
}
|
||||
return iterator{detail::foa::const_iterator_cast_tag{}, last};
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& key)
|
||||
{
|
||||
return table_.erase(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_node_map>::value,
|
||||
size_type>::type
|
||||
erase(K const& key)
|
||||
{
|
||||
return table_.erase(key);
|
||||
}
|
||||
|
||||
void swap(unordered_node_map& rhs) noexcept(
|
||||
noexcept(std::declval<table_type&>().swap(std::declval<table_type&>())))
|
||||
{
|
||||
table_.swap(rhs.table_);
|
||||
}
|
||||
|
||||
node_type extract(const_iterator pos)
|
||||
{
|
||||
BOOST_ASSERT(pos != end());
|
||||
node_type nh;
|
||||
auto elem = table_.extract(pos);
|
||||
nh.emplace(std::move(elem), get_allocator());
|
||||
return nh;
|
||||
}
|
||||
|
||||
node_type extract(key_type const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
return pos!=end()?extract(pos):node_type();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_node_map>::value,
|
||||
node_type>::type
|
||||
extract(K const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
return pos!=end()?extract(pos):node_type();
|
||||
}
|
||||
|
||||
template <class H2, class P2>
|
||||
void merge(
|
||||
unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&
|
||||
source)
|
||||
{
|
||||
table_.merge(source.table_);
|
||||
}
|
||||
|
||||
template <class H2, class P2>
|
||||
void merge(
|
||||
unordered_node_map<key_type, mapped_type, H2, P2, allocator_type>&&
|
||||
source)
|
||||
{
|
||||
table_.merge(std::move(source.table_));
|
||||
}
|
||||
|
||||
/// Lookup
|
||||
///
|
||||
|
||||
mapped_type& at(key_type const& key)
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos != table_.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
// TODO: someday refactor this to conditionally serialize the key and
|
||||
// include it in the error message
|
||||
//
|
||||
boost::throw_exception(
|
||||
std::out_of_range("key was not found in unordered_node_map"));
|
||||
}
|
||||
|
||||
mapped_type const& at(key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos != table_.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
boost::throw_exception(
|
||||
std::out_of_range("key was not found in unordered_node_map"));
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
mapped_type&>::type
|
||||
at(K&& key)
|
||||
{
|
||||
auto pos = table_.find(std::forward<K>(key));
|
||||
if (pos != table_.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
boost::throw_exception(
|
||||
std::out_of_range("key was not found in unordered_node_map"));
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
mapped_type const&>::type
|
||||
at(K&& key) const
|
||||
{
|
||||
auto pos = table_.find(std::forward<K>(key));
|
||||
if (pos != table_.end()) {
|
||||
return pos->second;
|
||||
}
|
||||
boost::throw_exception(
|
||||
std::out_of_range("key was not found in unordered_node_map"));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE mapped_type& operator[](key_type const& key)
|
||||
{
|
||||
return table_.try_emplace(key).first->second;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE mapped_type& operator[](key_type&& key)
|
||||
{
|
||||
return table_.try_emplace(std::move(key)).first->second;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
mapped_type&>::type
|
||||
operator[](K&& key)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(key)).first->second;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type count(key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
return pos != table_.end() ? 1 : 0;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
count(K const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
return pos != table_.end() ? 1 : 0;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE iterator find(key_type const& key)
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE const_iterator find(key_type const& key) const
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
iterator>::type
|
||||
find(K const& key)
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
const_iterator>::type
|
||||
find(K const& key) const
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool contains(key_type const& key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool>::type
|
||||
contains(K const& key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(key_type const& key)
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
std::pair<iterator, iterator> >::type
|
||||
equal_range(K const& key)
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
std::pair<const_iterator, const_iterator> >::type
|
||||
equal_range(K const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
/// 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); }
|
||||
|
||||
/// Observers
|
||||
///
|
||||
|
||||
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==(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
if (&lhs == &rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (lhs.size() == rhs.size()) && ([&] {
|
||||
for (auto const& kvp : lhs) {
|
||||
auto pos = rhs.find(kvp.first);
|
||||
if ((pos == rhs.end()) || (*pos != kvp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
}
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& rhs)
|
||||
noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator,
|
||||
class Pred>
|
||||
typename unordered_node_map<Key, T, Hash, KeyEqual, Allocator>::size_type
|
||||
erase_if(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& map, Pred pred)
|
||||
{
|
||||
return erase_if(map.table_, pred);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#endif
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
using iter_key_t =
|
||||
typename std::iterator_traits<T>::value_type::first_type;
|
||||
template <typename T>
|
||||
using iter_val_t =
|
||||
typename std::iterator_traits<T>::value_type::second_type;
|
||||
template <typename T>
|
||||
using iter_to_alloc_t =
|
||||
typename std::pair<iter_key_t<T> const, iter_val_t<T> >;
|
||||
} // namespace detail
|
||||
|
||||
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 = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(InputIterator, InputIterator,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_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<boost::remove_const_t<Key> >,
|
||||
class Pred = std::equal_to<boost::remove_const_t<Key> >,
|
||||
class Allocator = std::allocator<std::pair<const Key, T> >,
|
||||
class = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_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())
|
||||
-> unordered_node_map<boost::remove_const_t<Key>, T, Hash, Pred,
|
||||
Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(InputIterator, InputIterator, std::size_t, Allocator)
|
||||
-> unordered_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 = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_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 = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(
|
||||
InputIterator, InputIterator, std::size_t, Hash, Allocator)
|
||||
-> unordered_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 = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
|
||||
Allocator) -> unordered_node_map<boost::remove_const_t<Key>, T,
|
||||
boost::hash<boost::remove_const_t<Key> >,
|
||||
std::equal_to<boost::remove_const_t<Key> >, Allocator>;
|
||||
|
||||
template <class Key, class T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(std::initializer_list<std::pair<Key, T> >, Allocator)
|
||||
-> unordered_node_map<boost::remove_const_t<Key>, T,
|
||||
boost::hash<boost::remove_const_t<Key> >,
|
||||
std::equal_to<boost::remove_const_t<Key> >, Allocator>;
|
||||
|
||||
template <class Key, class T, class Hash, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
|
||||
Hash, Allocator) -> unordered_node_map<boost::remove_const_t<Key>, T,
|
||||
Hash, std::equal_to<boost::remove_const_t<Key> >, Allocator>;
|
||||
#endif
|
||||
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_NODE_MAP_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_NODE_MAP_FWD_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class Key, class T, class Hash = boost::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<const Key, T> > >
|
||||
class unordered_node_map;
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs);
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator> const& rhs);
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& lhs,
|
||||
unordered_node_map<Key, T, Hash, KeyEqual, Allocator>& rhs)
|
||||
noexcept(noexcept(lhs.swap(rhs)));
|
||||
} // namespace unordered
|
||||
|
||||
using boost::unordered::unordered_node_map;
|
||||
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,772 @@
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_UNORDERED_NODE_SET_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_UNORDERED_NODE_SET_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/unordered/detail/foa.hpp>
|
||||
#include <boost/unordered/detail/foa/node_handle.hpp>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
#include <boost/unordered/unordered_node_set_fwd.hpp>
|
||||
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/throw_exception.hpp>
|
||||
|
||||
#include <initializer_list>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
namespace detail {
|
||||
template <class Key> struct node_set_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using init_type = Key;
|
||||
using value_type = Key;
|
||||
|
||||
static Key const& extract(value_type const& key) { return key; }
|
||||
|
||||
struct element_type
|
||||
{
|
||||
value_type* p;
|
||||
|
||||
/*
|
||||
* we use a deleted copy constructor here so the type is no longer
|
||||
* trivially copy-constructible which inhibits our memcpy
|
||||
* optimizations when copying the tables
|
||||
*/
|
||||
element_type() = default;
|
||||
element_type(element_type const&) = delete;
|
||||
element_type(element_type&& rhs) noexcept
|
||||
{
|
||||
p = rhs.p;
|
||||
rhs.p = nullptr;
|
||||
}
|
||||
};
|
||||
|
||||
static value_type& value_from(element_type const& x) { return *x.p; }
|
||||
static Key const& extract(element_type const& k) { return *k.p; }
|
||||
static element_type&& move(element_type& x) { return std::move(x); }
|
||||
static value_type&& move(value_type& x) { return std::move(x); }
|
||||
|
||||
template <class A>
|
||||
static void construct(A& al, element_type* p, element_type const& copy)
|
||||
{
|
||||
construct(al, p, *copy.p);
|
||||
}
|
||||
|
||||
template <typename Allocator>
|
||||
static void construct(
|
||||
Allocator&, element_type* p, element_type&& x) noexcept
|
||||
{
|
||||
p->p = x.p;
|
||||
x.p = nullptr;
|
||||
}
|
||||
|
||||
template <class A, class... Args>
|
||||
static void construct(A& al, element_type* p, Args&&... args)
|
||||
{
|
||||
p->p = boost::to_address(boost::allocator_allocate(al, 1));
|
||||
BOOST_TRY
|
||||
{
|
||||
boost::allocator_construct(al, p->p, std::forward<Args>(args)...);
|
||||
}
|
||||
BOOST_CATCH(...)
|
||||
{
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p->p),
|
||||
1);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, value_type* p) noexcept
|
||||
{
|
||||
boost::allocator_destroy(al, p);
|
||||
boost::allocator_deallocate(al,
|
||||
boost::pointer_traits<
|
||||
typename boost::allocator_pointer<A>::type>::pointer_to(*p),
|
||||
1);
|
||||
}
|
||||
|
||||
template <class A> static void destroy(A& al, element_type* p) noexcept
|
||||
{
|
||||
if (p->p) {
|
||||
destroy(al, p->p);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <class NodeSetTypes, class Allocator>
|
||||
struct node_set_handle
|
||||
: public detail::foa::node_handle_base<NodeSetTypes, Allocator>
|
||||
{
|
||||
private:
|
||||
using base_type =
|
||||
detail::foa::node_handle_base<NodeSetTypes, 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 NodeSetTypes::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->element());
|
||||
}
|
||||
};
|
||||
} // namespace detail
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_node_set
|
||||
{
|
||||
using set_types = detail::node_set_types<Key>;
|
||||
|
||||
using table_type = detail::foa::table<set_types, Hash, KeyEqual,
|
||||
typename boost::allocator_rebind<Allocator,
|
||||
typename set_types::value_type>::type>;
|
||||
|
||||
table_type table_;
|
||||
|
||||
template <class K, class H, class KE, class A, class Pred>
|
||||
typename unordered_node_set<K, H, KE, A>::size_type friend erase_if(
|
||||
unordered_node_set<K, H, KE, A>& set, Pred pred);
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using value_type = typename set_types::value_type;
|
||||
using init_type = typename set_types::init_type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using hasher = Hash;
|
||||
using key_equal = KeyEqual;
|
||||
using allocator_type = Allocator;
|
||||
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 iterator = typename table_type::iterator;
|
||||
using const_iterator = typename table_type::const_iterator;
|
||||
using node_type = detail::node_set_handle<set_types,
|
||||
typename boost::allocator_rebind<Allocator,
|
||||
typename set_types::value_type>::type>;
|
||||
using insert_return_type =
|
||||
detail::foa::insert_return_type<iterator, node_type>;
|
||||
|
||||
unordered_node_set() : unordered_node_set(0) {}
|
||||
|
||||
explicit unordered_node_set(size_type n, hasher const& h = hasher(),
|
||||
key_equal const& pred = key_equal(),
|
||||
allocator_type const& a = allocator_type())
|
||||
: table_(n, h, pred, a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(size_type n, allocator_type const& a)
|
||||
: unordered_node_set(n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(size_type n, hasher const& h, allocator_type const& a)
|
||||
: unordered_node_set(n, h, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_node_set(
|
||||
InputIterator f, InputIterator l, allocator_type const& a)
|
||||
: unordered_node_set(f, l, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
explicit unordered_node_set(allocator_type const& a)
|
||||
: unordered_node_set(0, a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
unordered_node_set(Iterator first, Iterator last, size_type n = 0,
|
||||
hasher const& h = hasher(), key_equal const& pred = key_equal(),
|
||||
allocator_type const& a = allocator_type())
|
||||
: unordered_node_set(n, h, pred, a)
|
||||
{
|
||||
this->insert(first, last);
|
||||
}
|
||||
|
||||
template <class InputIt>
|
||||
unordered_node_set(
|
||||
InputIt first, InputIt last, size_type n, allocator_type const& a)
|
||||
: unordered_node_set(first, last, n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class Iterator>
|
||||
unordered_node_set(Iterator first, Iterator last, size_type n,
|
||||
hasher const& h, allocator_type const& a)
|
||||
: unordered_node_set(first, last, n, h, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(unordered_node_set const& other) : table_(other.table_)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(
|
||||
unordered_node_set const& other, allocator_type const& a)
|
||||
: table_(other.table_, a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(unordered_node_set&& other)
|
||||
noexcept(std::is_nothrow_move_constructible<hasher>::value&&
|
||||
std::is_nothrow_move_constructible<key_equal>::value&&
|
||||
std::is_nothrow_move_constructible<allocator_type>::value)
|
||||
: table_(std::move(other.table_))
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(unordered_node_set&& other, allocator_type const& al)
|
||||
: table_(std::move(other.table_), al)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(std::initializer_list<value_type> ilist,
|
||||
size_type n = 0, hasher const& h = hasher(),
|
||||
key_equal const& pred = key_equal(),
|
||||
allocator_type const& a = allocator_type())
|
||||
: unordered_node_set(ilist.begin(), ilist.end(), n, h, pred, a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(
|
||||
std::initializer_list<value_type> il, allocator_type const& a)
|
||||
: unordered_node_set(il, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(std::initializer_list<value_type> init, size_type n,
|
||||
allocator_type const& a)
|
||||
: unordered_node_set(init, n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_node_set(std::initializer_list<value_type> init, size_type n,
|
||||
hasher const& h, allocator_type const& a)
|
||||
: unordered_node_set(init, n, h, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
~unordered_node_set() = default;
|
||||
|
||||
unordered_node_set& operator=(unordered_node_set const& other)
|
||||
{
|
||||
table_ = other.table_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
unordered_node_set& operator=(unordered_node_set&& other) noexcept(
|
||||
noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
|
||||
{
|
||||
table_ = std::move(other.table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
allocator_type get_allocator() const noexcept
|
||||
{
|
||||
return table_.get_allocator();
|
||||
}
|
||||
|
||||
/// Iterators
|
||||
///
|
||||
|
||||
iterator begin() noexcept { return table_.begin(); }
|
||||
const_iterator begin() const noexcept { return table_.begin(); }
|
||||
const_iterator cbegin() const noexcept { return table_.cbegin(); }
|
||||
|
||||
iterator end() noexcept { return table_.end(); }
|
||||
const_iterator end() const noexcept { return table_.end(); }
|
||||
const_iterator cend() const noexcept { return table_.cend(); }
|
||||
|
||||
/// Capacity
|
||||
///
|
||||
|
||||
BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
|
||||
{
|
||||
return table_.empty();
|
||||
}
|
||||
|
||||
size_type size() const noexcept { return table_.size(); }
|
||||
|
||||
size_type max_size() const noexcept { return table_.max_size(); }
|
||||
|
||||
/// Modifiers
|
||||
///
|
||||
|
||||
void clear() noexcept { table_.clear(); }
|
||||
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> insert(
|
||||
value_type const& value)
|
||||
{
|
||||
return table_.insert(value);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> insert(value_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value));
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_node_set>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
insert(K&& k)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(k));
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value)
|
||||
{
|
||||
return table_.insert(value).first;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, value_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value)).first;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_node_set>::value,
|
||||
iterator>::type
|
||||
insert(const_iterator, K&& k)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(k)).first;
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
for (auto pos = first; pos != last; ++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)
|
||||
{
|
||||
if (nh.empty()) {
|
||||
return {end(), false, node_type{}};
|
||||
}
|
||||
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
typename set_types::element_type x;
|
||||
x.p=std::addressof(nh.element());
|
||||
|
||||
auto itp = table_.insert(std::move(x));
|
||||
if (itp.second) {
|
||||
nh.clear();
|
||||
return {itp.first, true, node_type{}};
|
||||
} else {
|
||||
return {itp.first, false, std::move(nh)};
|
||||
}
|
||||
}
|
||||
|
||||
iterator insert(const_iterator, node_type&& nh)
|
||||
{
|
||||
if (nh.empty()) {
|
||||
return end();
|
||||
}
|
||||
|
||||
BOOST_ASSERT(get_allocator() == nh.get_allocator());
|
||||
|
||||
auto itp = table_.insert(set_types::move(nh.element()));
|
||||
return itp.first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE void erase(const_iterator pos)
|
||||
{
|
||||
return table_.erase(pos);
|
||||
}
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
while (first != last) {
|
||||
this->erase(first++);
|
||||
}
|
||||
return iterator{detail::foa::const_iterator_cast_tag{}, last};
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& key)
|
||||
{
|
||||
return table_.erase(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_node_set>::value,
|
||||
size_type>::type
|
||||
erase(K const& key)
|
||||
{
|
||||
return table_.erase(key);
|
||||
}
|
||||
|
||||
void swap(unordered_node_set& rhs) noexcept(
|
||||
noexcept(std::declval<table_type&>().swap(std::declval<table_type&>())))
|
||||
{
|
||||
table_.swap(rhs.table_);
|
||||
}
|
||||
|
||||
node_type extract(const_iterator pos)
|
||||
{
|
||||
BOOST_ASSERT(pos != end());
|
||||
node_type nh;
|
||||
auto elem = table_.extract(pos);
|
||||
nh.emplace(std::move(elem), get_allocator());
|
||||
return nh;
|
||||
}
|
||||
|
||||
node_type extract(key_type const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
return pos!=end()?extract(pos):node_type();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
boost::unordered::detail::transparent_non_iterable<K,
|
||||
unordered_node_set>::value,
|
||||
node_type>::type
|
||||
extract(K const& key)
|
||||
{
|
||||
auto pos = find(key);
|
||||
return pos!=end()?extract(pos):node_type();
|
||||
}
|
||||
|
||||
template <class H2, class P2>
|
||||
void merge(unordered_node_set<key_type, H2, P2, allocator_type>& source)
|
||||
{
|
||||
table_.merge(source.table_);
|
||||
}
|
||||
|
||||
template <class H2, class P2>
|
||||
void merge(unordered_node_set<key_type, H2, P2, allocator_type>&& source)
|
||||
{
|
||||
table_.merge(std::move(source.table_));
|
||||
}
|
||||
|
||||
/// Lookup
|
||||
///
|
||||
|
||||
BOOST_FORCEINLINE size_type count(key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
return pos != table_.end() ? 1 : 0;
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
count(K const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
return pos != table_.end() ? 1 : 0;
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE iterator find(key_type const& key)
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE const_iterator find(key_type const& key) const
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
iterator>::type
|
||||
find(K const& key)
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
const_iterator>::type
|
||||
find(K const& key) const
|
||||
{
|
||||
return table_.find(key);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool contains(key_type const& key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
boost::unordered::detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool>::type
|
||||
contains(K const& key) const
|
||||
{
|
||||
return this->find(key) != this->end();
|
||||
}
|
||||
|
||||
std::pair<iterator, iterator> equal_range(key_type const& key)
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
std::pair<const_iterator, const_iterator> equal_range(
|
||||
key_type const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
std::pair<iterator, iterator> >::type
|
||||
equal_range(K const& key)
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
std::pair<const_iterator, const_iterator> >::type
|
||||
equal_range(K const& key) const
|
||||
{
|
||||
auto pos = table_.find(key);
|
||||
if (pos == table_.end()) {
|
||||
return {pos, pos};
|
||||
}
|
||||
|
||||
auto next = pos;
|
||||
++next;
|
||||
return {pos, next};
|
||||
}
|
||||
|
||||
/// 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); }
|
||||
|
||||
/// Observers
|
||||
///
|
||||
|
||||
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==(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
if (&lhs == &rhs) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return (lhs.size() == rhs.size()) && ([&] {
|
||||
for (auto const& key : lhs) {
|
||||
auto pos = rhs.find(key);
|
||||
if ((pos == rhs.end()) || (key != *pos)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
})();
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_node_set<Key, Hash, KeyEqual, Allocator>& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator>& rhs)
|
||||
noexcept(noexcept(lhs.swap(rhs)))
|
||||
{
|
||||
lhs.swap(rhs);
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator,
|
||||
class Pred>
|
||||
typename unordered_node_set<Key, Hash, KeyEqual, Allocator>::size_type
|
||||
erase_if(unordered_node_set<Key, Hash, KeyEqual, Allocator>& set, Pred pred)
|
||||
{
|
||||
return erase_if(set.table_, pred);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#endif
|
||||
|
||||
#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 = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(InputIterator, InputIterator,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_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 = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(std::initializer_list<T>,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> unordered_node_set<T, Hash, Pred, Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(InputIterator, InputIterator, std::size_t, Allocator)
|
||||
-> unordered_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 = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(
|
||||
InputIterator, InputIterator, std::size_t, Hash, Allocator)
|
||||
-> unordered_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 = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(std::initializer_list<T>, std::size_t, Allocator)
|
||||
-> unordered_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class T, class Hash, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(std::initializer_list<T>, std::size_t, Hash, Allocator)
|
||||
-> unordered_node_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_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 T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_node_set(std::initializer_list<T>, Allocator)
|
||||
-> unordered_node_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
#endif
|
||||
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,49 @@
|
||||
|
||||
// Copyright (C) 2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
#ifndef BOOST_UNORDERED_NODE_SET_FWD_HPP_INCLUDED
|
||||
#define BOOST_UNORDERED_NODE_SET_FWD_HPP_INCLUDED
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#if defined(BOOST_HAS_PRAGMA_ONCE)
|
||||
#pragma once
|
||||
#endif
|
||||
|
||||
#include <boost/functional/hash_fwd.hpp>
|
||||
#include <boost/unordered/detail/fwd.hpp>
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class Key, class Hash = boost::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key> >
|
||||
class unordered_node_set;
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs);
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator> const& rhs);
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
void swap(unordered_node_set<Key, Hash, KeyEqual, Allocator>& lhs,
|
||||
unordered_node_set<Key, Hash, KeyEqual, Allocator>& rhs)
|
||||
noexcept(noexcept(lhs.swap(rhs)));
|
||||
} // namespace unordered
|
||||
|
||||
using boost::unordered::unordered_node_set;
|
||||
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
} // namespace boost
|
||||
|
||||
#endif
|
||||
@@ -390,6 +390,15 @@ namespace boost {
|
||||
return this->emplace(boost::move(x));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_set>::value,
|
||||
std::pair<iterator, bool> >::type
|
||||
insert(BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return table_.try_emplace_unique(boost::forward<Key>(k));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator hint, value_type const& x)
|
||||
{
|
||||
return this->emplace_hint(hint, x);
|
||||
@@ -400,6 +409,15 @@ namespace boost {
|
||||
return this->emplace_hint(hint, boost::move(x));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<
|
||||
detail::transparent_non_iterable<Key, unordered_set>::value,
|
||||
iterator>::type
|
||||
insert(const_iterator hint, BOOST_FWD_REF(Key) k)
|
||||
{
|
||||
return table_.try_emplace_hint_unique(hint, boost::forward<Key>(k));
|
||||
}
|
||||
|
||||
template <class InputIt> void insert(InputIt, InputIt);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
@@ -571,6 +589,14 @@ namespace boost {
|
||||
return table_.hash_to_bucket(table_.hash(k));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
size_type>::type
|
||||
bucket(BOOST_FWD_REF(Key) k) const
|
||||
{
|
||||
return table_.hash_to_bucket(table_.hash(boost::forward<Key>(k)));
|
||||
}
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n));
|
||||
@@ -673,6 +699,20 @@ namespace boost {
|
||||
unordered_set(std::initializer_list<T>, std::size_t, Hash, Allocator)
|
||||
-> unordered_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_set(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_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 T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_set(std::initializer_list<T>, Allocator)
|
||||
-> unordered_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
#endif
|
||||
|
||||
template <class T, class H, class P, class A> class unordered_multiset
|
||||
@@ -1198,6 +1238,14 @@ namespace boost {
|
||||
return table_.hash_to_bucket(table_.hash(k));
|
||||
}
|
||||
|
||||
template <class Key>
|
||||
typename boost::enable_if_c<detail::are_transparent<Key, H, P>::value,
|
||||
size_type>::type
|
||||
bucket(BOOST_FWD_REF(Key) k) const
|
||||
{
|
||||
return table_.hash_to_bucket(table_.hash(boost::forward<Key>(k)));
|
||||
}
|
||||
|
||||
local_iterator begin(size_type n)
|
||||
{
|
||||
return local_iterator(table_.begin(n));
|
||||
@@ -1303,6 +1351,21 @@ namespace boost {
|
||||
unordered_multiset(std::initializer_list<T>, std::size_t, Hash, Allocator)
|
||||
-> unordered_multiset<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_multiset(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_multiset<
|
||||
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 T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
unordered_multiset(std::initializer_list<T>, Allocator)
|
||||
-> unordered_multiset<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
#endif
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
+6
-1
@@ -1,6 +1,6 @@
|
||||
|
||||
# Copyright 2006-2008 Daniel James.
|
||||
# Copyright 2022 Christian Mazakas
|
||||
# Copyright 2022-2023 Christian Mazakas
|
||||
# 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)
|
||||
|
||||
@@ -26,6 +26,7 @@ project
|
||||
|
||||
<toolset>gcc-4.4:<cxxflags>-Wno-strict-aliasing
|
||||
<toolset>gcc-4.4:<cxxflags>-fno-deduce-init-list
|
||||
<toolset>clang-14:<cxxflags>-Wunused-template
|
||||
|
||||
<toolset>gcc:<warnings-as-errors>on
|
||||
<toolset>clang:<warnings-as-errors>on
|
||||
@@ -94,7 +95,9 @@ run exception/erase_exception_tests.cpp ;
|
||||
run exception/rehash_exception_tests.cpp ;
|
||||
run exception/swap_exception_tests.cpp : : : <define>BOOST_UNORDERED_SWAP_METHOD=2 ;
|
||||
run exception/merge_exception_tests.cpp ;
|
||||
run exception/less_tests.cpp ;
|
||||
|
||||
run unordered/narrow_cast_tests.cpp ;
|
||||
run quick.cpp ;
|
||||
|
||||
import ../../config/checks/config : requires ;
|
||||
@@ -139,6 +142,8 @@ build_foa erase_if ;
|
||||
build_foa scary_tests ;
|
||||
build_foa init_type_insert_tests ;
|
||||
build_foa max_load_tests ;
|
||||
build_foa extract_tests ;
|
||||
build_foa node_handle_tests ;
|
||||
|
||||
run unordered/hash_is_avalanching_test.cpp ;
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ move
|
||||
mp11
|
||||
predef
|
||||
preprocessor
|
||||
static_assert
|
||||
throw_exception
|
||||
tuple
|
||||
type_traits
|
||||
@@ -29,8 +30,6 @@ type_traits
|
||||
# Secondary dependencies
|
||||
|
||||
describe
|
||||
static_assert
|
||||
winapi
|
||||
)
|
||||
|
||||
foreach(dep IN LISTS deps)
|
||||
|
||||
@@ -60,6 +60,9 @@ template <class T> struct assign_base : public test::exception_base
|
||||
test::random_values<T> x_values, y_values;
|
||||
T x, y;
|
||||
|
||||
int t1;
|
||||
int t2;
|
||||
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
@@ -67,7 +70,10 @@ template <class T> struct assign_base : public test::exception_base
|
||||
assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: x_values(), y_values(),
|
||||
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2)),
|
||||
t1(tag1),
|
||||
t2(tag2)
|
||||
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
@@ -89,6 +95,22 @@ template <class T> struct assign_base : public test::exception_base
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
if (x1.hash_function() == hasher(t1)) {
|
||||
BOOST_TEST(x1.key_eq() == key_equal(t1));
|
||||
}
|
||||
|
||||
if (x1.hash_function() == hasher(t2)) {
|
||||
BOOST_TEST(x1.key_eq() == key_equal(t2));
|
||||
}
|
||||
|
||||
if (x1.key_eq() == key_equal(t1)) {
|
||||
BOOST_TEST(x1.hash_function() == hasher(t1));
|
||||
}
|
||||
|
||||
if (x1.key_eq() == key_equal(t2)) {
|
||||
BOOST_TEST(x1.hash_function() == hasher(t2));
|
||||
}
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it, at the cost of
|
||||
// messing up the data.
|
||||
|
||||
@@ -25,8 +25,24 @@ typedef boost::unordered_flat_set<
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_pair_set;
|
||||
|
||||
#define CONTAINER_SEQ (test_set)(test_map)
|
||||
#define CONTAINER_PAIR_SEQ (test_pair_set)(test_map)
|
||||
typedef boost::unordered_node_set<test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_node_set;
|
||||
|
||||
typedef boost::unordered_node_map<test::exception::object,
|
||||
test::exception::object, test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >
|
||||
test_node_map;
|
||||
|
||||
typedef boost::unordered_node_set<
|
||||
std::pair<test::exception::object, test::exception::object>,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >
|
||||
test_pair_node_set;
|
||||
|
||||
#define CONTAINER_SEQ (test_set)(test_map)(test_node_set)(test_node_map)
|
||||
#define CONTAINER_PAIR_SEQ (test_pair_set)(test_map)(test_pair_node_set)(test_node_map)
|
||||
#else
|
||||
typedef boost::unordered_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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 "./containers.hpp"
|
||||
@@ -229,10 +229,12 @@ using test::generate_collisions;
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test_set* test_set_;
|
||||
test_map* test_map_;
|
||||
test_node_set* test_node_set_;
|
||||
test_node_map* test_node_map_;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_set_)(test_map_))
|
||||
((test_set_)(test_map_)(test_node_set_)(test_node_map_))
|
||||
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
|
||||
(insert_lvalue_pos)(insert_single_item_range)
|
||||
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
|
||||
@@ -242,7 +244,7 @@ UNORDERED_TEST(insert_exception_test,
|
||||
)
|
||||
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_set_)(test_map_))
|
||||
((test_set_)(test_map_)(test_node_set_)(test_node_map_))
|
||||
((insert_lvalue)(insert_lvalue_begin)(insert_lvalue_end)
|
||||
(insert_lvalue_pos)(insert_single_item_range)
|
||||
(emplace_lvalue)(emplace_lvalue_begin)(emplace_lvalue_end)
|
||||
@@ -314,15 +316,16 @@ struct pair_emplace2_type : inserter_base
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test_pair_set* test_pair_set_;
|
||||
test_pair_node_set* test_pair_node_set_;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_pair_set_)(test_map_))
|
||||
((test_pair_set_)(test_map_)(test_pair_node_set_)(test_node_map_))
|
||||
((pair_emplace)(pair_emplace2))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_pair_set_)(test_map_))
|
||||
((test_pair_set_)(test_map_)(test_pair_node_set_)(test_node_map_))
|
||||
((pair_emplace)(pair_emplace2))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
@@ -399,6 +402,20 @@ struct map_insert_or_assign_type : map_inserter_base
|
||||
}
|
||||
} map_insert_or_assign;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_map_)(test_node_map_))
|
||||
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((test_map_)(test_node_map_))
|
||||
((try_emplace)(try_emplace2)(map_insert_operator)(map_insert_or_assign))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
#else
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_exception_test,
|
||||
((test_map_))
|
||||
@@ -411,6 +428,7 @@ UNORDERED_TEST(insert_rehash_exception_test,
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
// Range insert tests
|
||||
|
||||
@@ -459,12 +477,12 @@ void insert_range_rehash_exception_test(T*, test::random_generator gen)
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_range_exception_test,
|
||||
((test_set_)(test_map_))
|
||||
((test_set_)(test_map_)(test_node_set_)(test_node_map_))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
|
||||
UNORDERED_TEST(insert_range_rehash_exception_test,
|
||||
((test_set_)(test_map_))
|
||||
((test_set_)(test_map_)(test_node_set_)(test_node_map_))
|
||||
((default_generator)(limited_range)(generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
|
||||
// Copyright 2023 Christian Mazakas
|
||||
// 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 "./containers.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/strong.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
UNORDERED_AUTO_TEST (less_osx_regression) {
|
||||
DISABLE_EXCEPTIONS;
|
||||
typedef test_pair_set::value_type value_type;
|
||||
typedef test::exception::object object;
|
||||
|
||||
std::vector<value_type> v;
|
||||
v.push_back(value_type(object(12, 98), object(88, 13)));
|
||||
v.push_back(value_type(object(24, 71), object(62, 84)));
|
||||
v.push_back(value_type(object(30, 0), object(5, 73)));
|
||||
v.push_back(value_type(object(34, 64), object(79, 58)));
|
||||
v.push_back(value_type(object(36, 95), object(64, 23)));
|
||||
v.push_back(value_type(object(42, 89), object(68, 44)));
|
||||
v.push_back(value_type(object(42, 26), object(93, 64)));
|
||||
v.push_back(value_type(object(86, 86), object(16, 62)));
|
||||
v.push_back(value_type(object(86, 86), object(75, 23)));
|
||||
v.push_back(value_type(object(92, 37), object(41, 90)));
|
||||
|
||||
BOOST_TEST_EQ(v.size(), 10u);
|
||||
|
||||
std::set<value_type, test::exception::less> s;
|
||||
s.insert(v.begin(), v.end());
|
||||
BOOST_TEST_EQ(s.size(), v.size());
|
||||
|
||||
test::ordered<test_pair_set> tracker;
|
||||
test_pair_set x;
|
||||
for (std::vector<value_type>::iterator it = v.begin(); it != v.end();
|
||||
++it) {
|
||||
x.insert(*it);
|
||||
}
|
||||
|
||||
tracker.insert(v.begin(), v.end());
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2017-2018 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -64,6 +64,12 @@ boost::unordered_flat_set<test::exception::object, test::exception::hash,
|
||||
boost::unordered_flat_map<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >* test_map_;
|
||||
boost::unordered_node_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
test::exception::allocator<test::exception::object> >* test_node_set_;
|
||||
boost::unordered_node_map<test::exception::object, test::exception::object,
|
||||
test::exception::hash, test::exception::equal_to,
|
||||
test::exception::allocator2<test::exception::object> >* test_node_map_;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_MULTI_TEST(set_merge, merge_exception_test,
|
||||
@@ -99,6 +105,40 @@ UNORDERED_MULTI_TEST(map_merge_collisions, merge_exception_test,
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(node_set_merge, merge_exception_test,
|
||||
((test_node_set_))
|
||||
((test_node_set_))
|
||||
(/* (0x0000)(0x6400) */(0x0064)/* (0x0a64)(0x3232) */)
|
||||
((0x0000)(0x0001)(0x0102))
|
||||
((default_generator)(limited_range))
|
||||
((default_generator)(limited_range))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(node_map_merge, merge_exception_test,
|
||||
((test_node_map_))
|
||||
((test_node_map_))
|
||||
((0x0000)(0x6400)(0x0064)(0x0a64)(0x3232))
|
||||
((0x0101)(0x0200)(0x0201))
|
||||
((default_generator)(limited_range))
|
||||
((default_generator)(limited_range))
|
||||
)
|
||||
// Run fewer generate_collisions tests, as they're slow.
|
||||
UNORDERED_MULTI_TEST(node_set_merge_collisions, merge_exception_test,
|
||||
((test_node_set_))
|
||||
((test_node_set_))
|
||||
((0x0a0a))
|
||||
((0x0202)(0x0100)(0x0201))
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
UNORDERED_MULTI_TEST(node_map_merge_collisions, merge_exception_test,
|
||||
((test_node_map_))
|
||||
((test_node_map_))
|
||||
((0x0a0a))
|
||||
((0x0000)(0x0002)(0x0102))
|
||||
((generate_collisions))
|
||||
((generate_collisions))
|
||||
)
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<test::exception::object, test::exception::hash,
|
||||
test::exception::equal_to,
|
||||
|
||||
@@ -20,6 +20,7 @@ template <class T> struct move_assign_base : public test::exception_base
|
||||
{
|
||||
test::random_values<T> x_values, y_values;
|
||||
T x, y;
|
||||
int t1, t2;
|
||||
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
@@ -28,7 +29,9 @@ template <class T> struct move_assign_base : public test::exception_base
|
||||
move_assign_base(int tag1, int tag2, float mlf1 = 1.0, float mlf2 = 1.0)
|
||||
: x_values(), y_values(),
|
||||
x(0, hasher(tag1), key_equal(tag1), allocator_type(tag1)),
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2))
|
||||
y(0, hasher(tag2), key_equal(tag2), allocator_type(tag2)),
|
||||
t1(tag1),
|
||||
t2(tag2)
|
||||
{
|
||||
x.max_load_factor(mlf1);
|
||||
y.max_load_factor(mlf2);
|
||||
@@ -52,6 +55,22 @@ template <class T> struct move_assign_base : public test::exception_base
|
||||
{
|
||||
test::check_equivalent_keys(x1);
|
||||
|
||||
if (x1.hash_function() == hasher(t1)) {
|
||||
BOOST_TEST(x1.key_eq() == key_equal(t1));
|
||||
}
|
||||
|
||||
if (x1.hash_function() == hasher(t2)) {
|
||||
BOOST_TEST(x1.key_eq() == key_equal(t2));
|
||||
}
|
||||
|
||||
if (x1.key_eq() == key_equal(t1)) {
|
||||
BOOST_TEST(x1.hash_function() == hasher(t1));
|
||||
}
|
||||
|
||||
if (x1.key_eq() == key_equal(t2)) {
|
||||
BOOST_TEST(x1.hash_function() == hasher(t2));
|
||||
}
|
||||
|
||||
// If the container is empty at the point of the exception, the
|
||||
// internal structure is hidden, this exposes it, at the cost of
|
||||
// messing up the data.
|
||||
|
||||
@@ -4,15 +4,40 @@
|
||||
// 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 "./containers.hpp"
|
||||
#define BOOST_ENABLE_ASSERT_HANDLER
|
||||
#include <boost/assert.hpp>
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
#define BOOST_UNORDERED_FOA_WEAK_GUARANTEE_SWAP_EXCEPTIONS_TESTS
|
||||
#endif
|
||||
#include "./containers.hpp"
|
||||
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
namespace boost {
|
||||
void assertion_failed(
|
||||
char const* expr, char const* function, char const* file, long line)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << expr << "\nin " << function << " failed at : " << file << ", line "
|
||||
<< line;
|
||||
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
|
||||
void assertion_failed_msg(char const* expr, char const* msg,
|
||||
char const* function, char const* file, long line)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << expr << "\nin " << function << " failed at : " << file << ", line "
|
||||
<< line << "\n"
|
||||
<< msg;
|
||||
|
||||
throw std::runtime_error(ss.str());
|
||||
}
|
||||
} // namespace boost
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(disable : 4512) // assignment operator could not be generated
|
||||
@@ -39,15 +64,10 @@ template <class T> struct self_swap_base : public test::exception_base
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(T const& x) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
(void)x;
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(x);
|
||||
BOOST_ERROR("An exception leaked when it should not have. Allocator "
|
||||
"equality assertion must precede all other ops");
|
||||
}
|
||||
};
|
||||
|
||||
@@ -140,11 +160,139 @@ template <class T> struct swap_test4 : swap_base<T>
|
||||
swap_test4() : swap_base<T>(10, 10, 1, 2) {}
|
||||
};
|
||||
|
||||
template <class T> struct unequal_alloc_swap_base : public test::exception_base
|
||||
{
|
||||
const test::random_values<T> x_values, y_values;
|
||||
const T initial_x, initial_y;
|
||||
|
||||
typedef typename T::hasher hasher;
|
||||
typedef typename T::key_equal key_equal;
|
||||
typedef typename T::allocator_type allocator_type;
|
||||
|
||||
unequal_alloc_swap_base(unsigned int count1, unsigned int count2)
|
||||
: x_values(count1, test::limited_range),
|
||||
y_values(count2, test::limited_range),
|
||||
initial_x(x_values.begin(), x_values.end(), 0, allocator_type(1337)),
|
||||
initial_y(y_values.begin(), y_values.end(), 0, allocator_type(7331))
|
||||
{
|
||||
}
|
||||
|
||||
struct data_type
|
||||
{
|
||||
data_type(T const& x_, T const& y_) : x(x_), y(y_) {}
|
||||
|
||||
T x, y;
|
||||
};
|
||||
|
||||
data_type init() const { return data_type(initial_x, initial_y); }
|
||||
|
||||
void run(data_type& d) const
|
||||
{
|
||||
bool assert_threw = false;
|
||||
|
||||
BOOST_TEST(d.x.get_allocator() != d.y.get_allocator());
|
||||
|
||||
try {
|
||||
d.x.swap(d.y);
|
||||
} catch (std::runtime_error&) {
|
||||
assert_threw = true;
|
||||
}
|
||||
|
||||
DISABLE_EXCEPTIONS;
|
||||
BOOST_TEST(assert_threw);
|
||||
test::check_container(d.x, this->x_values);
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_container(d.y, this->y_values);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
|
||||
void check BOOST_PREVENT_MACRO_SUBSTITUTION(data_type const& d) const
|
||||
{
|
||||
std::string scope(test::scope);
|
||||
|
||||
// TODO: In C++11 exceptions are only allowed in the swap function.
|
||||
BOOST_TEST(scope == "hash::hash(hash)" ||
|
||||
scope == "hash::operator=(hash)" ||
|
||||
scope == "equal_to::equal_to(equal_to)" ||
|
||||
scope == "equal_to::operator=(equal_to)");
|
||||
|
||||
test::check_equivalent_keys(d.x);
|
||||
test::check_equivalent_keys(d.y);
|
||||
}
|
||||
};
|
||||
|
||||
template <class T> struct unequal_alloc_swap_test1 : unequal_alloc_swap_base<T>
|
||||
{
|
||||
unequal_alloc_swap_test1() : unequal_alloc_swap_base<T>(0, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct unequal_alloc_swap_test2 : unequal_alloc_swap_base<T>
|
||||
{
|
||||
unequal_alloc_swap_test2() : unequal_alloc_swap_base<T>(0, 10) {}
|
||||
};
|
||||
|
||||
template <class T> struct unequal_alloc_swap_test3 : unequal_alloc_swap_base<T>
|
||||
{
|
||||
unequal_alloc_swap_test3() : unequal_alloc_swap_base<T>(10, 0) {}
|
||||
};
|
||||
|
||||
template <class T> struct unequal_alloc_swap_test4 : unequal_alloc_swap_base<T>
|
||||
{
|
||||
unequal_alloc_swap_test4() : unequal_alloc_swap_base<T>(10, 10) {}
|
||||
};
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
|
||||
using unordered_flat_set = boost::unordered_flat_set<int, boost::hash<int>,
|
||||
std::equal_to<int>, test::allocator1<int> >;
|
||||
using unordered_flat_map = boost::unordered_flat_map<int, int, boost::hash<int>,
|
||||
std::equal_to<int>, test::allocator1<std::pair<int const, int> > >;
|
||||
using unordered_node_set = boost::unordered_node_set<int, boost::hash<int>,
|
||||
std::equal_to<int>, test::allocator1<int> >;
|
||||
using unordered_node_map = boost::unordered_node_map<int, int, boost::hash<int>,
|
||||
std::equal_to<int>, test::allocator1<std::pair<int const, int> > >;
|
||||
|
||||
#define SWAP_CONTAINER_SEQ \
|
||||
(unordered_flat_set)(unordered_flat_map) \
|
||||
(unordered_node_set)(unordered_node_map)
|
||||
|
||||
#else
|
||||
|
||||
typedef boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::allocator1<int> >
|
||||
unordered_set;
|
||||
typedef boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::allocator1<std::pair<int const, int> > >
|
||||
unordered_map;
|
||||
typedef boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::allocator1<int> >
|
||||
unordered_multiset;
|
||||
typedef boost::unordered_multimap<int, int, boost::hash<int>,
|
||||
std::equal_to<int>, test::allocator1<std::pair<int const, int> > >
|
||||
unordered_multimap;
|
||||
|
||||
#define SWAP_CONTAINER_SEQ \
|
||||
(unordered_set)(unordered_map)(unordered_multiset)(unordered_multimap)
|
||||
#endif
|
||||
|
||||
// FOA containers deliberately choose to not offer the strong exception
|
||||
// guarantee so we can't reliably test what happens if swapping one of the data
|
||||
// members throws
|
||||
//
|
||||
// clang-format off
|
||||
#if !defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
EXCEPTION_TESTS(
|
||||
(self_swap_test1)(self_swap_test2)
|
||||
(swap_test1)(swap_test2)(swap_test3)(swap_test4),
|
||||
CONTAINER_SEQ)
|
||||
#endif
|
||||
|
||||
// want to prove that when assertions are defined as throwing operations that we
|
||||
// uphold invariants
|
||||
EXCEPTION_TESTS(
|
||||
(unequal_alloc_swap_test1)(unequal_alloc_swap_test2)
|
||||
(unequal_alloc_swap_test3)(unequal_alloc_swap_test4),
|
||||
SWAP_CONTAINER_SEQ)
|
||||
// clang-format on
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -54,20 +54,10 @@ namespace test {
|
||||
if (test::has_unique_keys<X>::value && count != 1)
|
||||
BOOST_ERROR("Non-unique key.");
|
||||
|
||||
#if !defined(BOOST_UNORDERED_FOA_WEAK_GUARANTEE_SWAP_EXCEPTIONS_TESTS)
|
||||
// we conditionally compile this check because our FOA implementation only
|
||||
// exhibits the weak guarantee when swapping throws
|
||||
//
|
||||
// in this case, the hasher may be changed before the predicate and the
|
||||
// arrays are swapped in which case, we can can find an element by
|
||||
// iteration but unfortunately, it's in the wrong slot according to the
|
||||
// new hash function so count(key) can wind up returning nothing when
|
||||
// there really is something
|
||||
if (x1.count(key) != count) {
|
||||
BOOST_ERROR("Incorrect output of count.");
|
||||
std::cerr << x1.count(key) << "," << count << "\n";
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
// Check that the keys are in the correct bucket and are
|
||||
|
||||
@@ -42,9 +42,8 @@ namespace test {
|
||||
value_list values2(x2.begin(), x2.end());
|
||||
values1.sort();
|
||||
values2.sort();
|
||||
BOOST_TEST(values1.size() == values2.size() &&
|
||||
test::equal(values1.begin(), values1.end(), values2.begin(),
|
||||
test::equivalent));
|
||||
BOOST_TEST_ALL_WITH(values1.begin(), values1.end(), values2.begin(),
|
||||
values2.end(), test::equivalent);
|
||||
}
|
||||
|
||||
template <class X1, class X2, class T>
|
||||
|
||||
@@ -11,6 +11,8 @@
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#include <boost/unordered/unordered_node_set.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#else
|
||||
#include <boost/unordered_set.hpp>
|
||||
|
||||
@@ -227,8 +227,21 @@ namespace test {
|
||||
}
|
||||
return x1.tag_ != x2.tag_;
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
friend void swap(hash&, hash&) noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
void swap(hash& lhs, hash& rhs) noexcept
|
||||
{
|
||||
int tag = lhs.tag_;
|
||||
lhs.tag_ = rhs.tag_;
|
||||
rhs.tag_ = tag;
|
||||
}
|
||||
#endif
|
||||
|
||||
class less
|
||||
{
|
||||
int tag_;
|
||||
@@ -249,7 +262,7 @@ namespace test {
|
||||
if (less_impl(x1.first, x2.first)) {
|
||||
return true;
|
||||
}
|
||||
if (!less_impl(x1.first, x2.first)) {
|
||||
if (less_impl(x2.first, x1.first)) {
|
||||
return false;
|
||||
}
|
||||
return less_impl(x1.second, x2.second);
|
||||
@@ -364,8 +377,20 @@ namespace test {
|
||||
}
|
||||
|
||||
friend less create_compare(equal_to x) { return less(x.tag_); }
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
friend void swap(equal_to&, equal_to&) noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
void swap(equal_to& lhs, equal_to& rhs) noexcept
|
||||
{
|
||||
int tag = lhs.tag_;
|
||||
lhs.tag_ = rhs.tag_;
|
||||
rhs.tag_ = tag;
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T> class allocator
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -206,6 +206,11 @@ namespace test {
|
||||
hash& operator=(hash const&) { return *this; }
|
||||
~hash() {}
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
hash(hash&&) = default;
|
||||
hash& operator=(hash&&) = default;
|
||||
#endif
|
||||
|
||||
std::size_t operator()(T const&) const { return 0; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
@@ -224,6 +229,11 @@ namespace test {
|
||||
equal_to& operator=(equal_to const&) { return *this; }
|
||||
~equal_to() {}
|
||||
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
equal_to(equal_to&&) = default;
|
||||
equal_to& operator=(equal_to&&) = default;
|
||||
#endif
|
||||
|
||||
bool operator()(T const&, T const&) const { return true; }
|
||||
#if BOOST_UNORDERED_CHECK_ADDR_OPERATOR_NOT_USED
|
||||
ampersand_operator_used operator&() const
|
||||
|
||||
@@ -230,18 +230,18 @@ namespace test {
|
||||
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
int result;
|
||||
unsigned result;
|
||||
switch (type_) {
|
||||
case 1:
|
||||
result = x;
|
||||
result = static_cast<unsigned>(x);
|
||||
break;
|
||||
case 2:
|
||||
result = x * 7;
|
||||
result = static_cast<unsigned>(x) * 7;
|
||||
break;
|
||||
default:
|
||||
result = x * 256;
|
||||
result = static_cast<unsigned>(x) * 256;
|
||||
}
|
||||
return static_cast<std::size_t>(result);
|
||||
return result;
|
||||
}
|
||||
|
||||
friend bool operator==(hash const& x1, hash const& x2)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -209,40 +209,75 @@ namespace assign_tests {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_map_std_alloc;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_node_map_std_alloc;
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_node_map;
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_set_prop_assign;
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_node_set_prop_assign;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_map_prop_assign;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_assign> >*
|
||||
test_node_map_prop_assign;
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_set_no_prop_assign;
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_node_set_no_prop_assign;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_map_no_prop_assign;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_assign> >*
|
||||
test_node_map_no_prop_assign;
|
||||
|
||||
UNORDERED_AUTO_TEST (check_traits) {
|
||||
BOOST_TEST(!is_propagate(test_set));
|
||||
BOOST_TEST(is_propagate(test_set_prop_assign));
|
||||
BOOST_TEST(!is_propagate(test_set_no_prop_assign));
|
||||
|
||||
BOOST_TEST(!is_propagate(test_node_set));
|
||||
BOOST_TEST(is_propagate(test_node_set_prop_assign));
|
||||
BOOST_TEST(!is_propagate(test_node_set_no_prop_assign));
|
||||
}
|
||||
|
||||
UNORDERED_TEST(assign_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_map)(test_set_prop_assign)(test_map_prop_assign)(test_set_no_prop_assign)(test_map_no_prop_assign))(
|
||||
((test_map_std_alloc)(test_node_map_std_alloc)
|
||||
(test_set)(test_node_set)
|
||||
(test_map)(test_node_map)
|
||||
(test_set_prop_assign)(test_node_set_prop_assign)
|
||||
(test_map_prop_assign)(test_node_map_prop_assign)
|
||||
(test_set_no_prop_assign)(test_node_set_no_prop_assign)
|
||||
(test_map_no_prop_assign)(test_node_map_no_prop_assign))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(assign_tests2,
|
||||
((test_set)(test_map)(test_set_prop_assign)(test_map_prop_assign)(test_set_no_prop_assign)(test_map_no_prop_assign))(
|
||||
((test_set)(test_node_set)
|
||||
(test_map)(test_node_map)
|
||||
(test_set_prop_assign)(test_node_set_prop_assign)
|
||||
(test_map_prop_assign)(test_node_map_prop_assign)
|
||||
(test_set_no_prop_assign)(test_node_set_no_prop_assign)
|
||||
(test_map_no_prop_assign)(test_node_map_no_prop_assign))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
#else
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
@@ -315,6 +350,12 @@ namespace assign_tests {
|
||||
std::initializer_list<std::pair<int const, int> > init;
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<int, int> x1;
|
||||
boost::unordered_node_map<int, int> x2;
|
||||
x2[25] = 3;
|
||||
x2[16] = 10;
|
||||
BOOST_TEST(!x2.empty());
|
||||
x2 = init;
|
||||
BOOST_TEST(x2.empty());
|
||||
#else
|
||||
boost::unordered_map<int, int> x1;
|
||||
#endif
|
||||
@@ -333,6 +374,12 @@ namespace assign_tests {
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> x;
|
||||
boost::unordered_node_set<int> y;
|
||||
y.insert(10);
|
||||
y.insert(20);
|
||||
y = {1, 2, -10};
|
||||
BOOST_TEST(y.find(10) == y.end());
|
||||
BOOST_TEST(y.find(-10) != y.end());
|
||||
#else
|
||||
boost::unordered_set<int> x;
|
||||
#endif
|
||||
|
||||
+21
-10
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2007-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -11,16 +11,12 @@
|
||||
|
||||
namespace at_tests {
|
||||
|
||||
UNORDERED_AUTO_TEST (at_tests) {
|
||||
template <class X> static void at_tests(X*)
|
||||
{
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Create Map" << std::endl;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<std::string, int> x;
|
||||
boost::unordered_flat_map<std::string, int> const& x_const(x);
|
||||
#else
|
||||
boost::unordered_map<std::string, int> x;
|
||||
boost::unordered_map<std::string, int> const& x_const(x);
|
||||
#endif
|
||||
X x;
|
||||
X const& x_const(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Check empty container" << std::endl;
|
||||
|
||||
@@ -64,6 +60,21 @@ namespace at_tests {
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Finished" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_map<std::string, int>* test_map;
|
||||
static boost::unordered_node_map<std::string, int>* test_node_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(at_tests, ((test_map)(test_node_map)))
|
||||
// clang-format on
|
||||
#else
|
||||
static boost::unordered_map<std::string, int>* test_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(at_tests, ((test_map)))
|
||||
// clang-format on
|
||||
#endif
|
||||
} // namespace at_tests
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
+144
-136
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -35,6 +35,22 @@ template class instantiate_flat_map<test::minimal::assignable const,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
template <typename K, typename T, typename H, typename P, typename A>
|
||||
class instantiate_node_map
|
||||
{
|
||||
typedef boost::unordered_node_map<K, T, H, P, A> container;
|
||||
container x;
|
||||
};
|
||||
|
||||
template class instantiate_node_map<int, int, boost::hash<int>,
|
||||
std::equal_to<int>, test::minimal::allocator<int> >;
|
||||
|
||||
template class instantiate_node_map<test::minimal::assignable const,
|
||||
test::minimal::default_assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
#else
|
||||
#define INSTANTIATE(type) \
|
||||
template class boost::unordered::detail::instantiate_##type
|
||||
@@ -55,149 +71,101 @@ INSTANTIATE(multimap)<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::allocator<int> >;
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
template <template <class Key, class T, class H = boost::hash<Key>,
|
||||
class P = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||
class Map>
|
||||
static void test0_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
typedef std::pair<test::minimal::assignable const, test::minimal::assignable>
|
||||
value_type;
|
||||
value_type value(x, x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
Map<int, int> int_map;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<int, int> int_map;
|
||||
|
||||
boost::unordered_flat_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
Map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_flat_map<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
#else
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
|
||||
Map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
#endif
|
||||
|
||||
container_test(int_map, std::pair<int const, int>(0, 0));
|
||||
container_test(int_map2, std::pair<int const, int>(0, 0));
|
||||
container_test(map, value);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_multimap2;
|
||||
|
||||
boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multimap;
|
||||
|
||||
container_test(int_multimap, std::pair<int const, int>(0, 0));
|
||||
container_test(int_multimap2, std::pair<int const, int>(0, 0));
|
||||
container_test(multimap, value);
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test0_impl<boost::unordered_flat_map>();
|
||||
test0_impl<boost::unordered_node_map>();
|
||||
#else
|
||||
test0_impl<boost::unordered_map>();
|
||||
test0_impl<boost::unordered_multimap>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
template <template <class Key, class T, class H = boost::hash<Key>,
|
||||
class P = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||
class Map>
|
||||
static void equality_tests_impl()
|
||||
{
|
||||
typedef std::pair<test::minimal::copy_constructible_equality_comparable const,
|
||||
test::minimal::copy_constructible_equality_comparable>
|
||||
value_type;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<int, int> int_map;
|
||||
Map<int, int> int_map;
|
||||
|
||||
boost::unordered_flat_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
Map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_flat_map<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
Map<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
#else
|
||||
boost::unordered_map<int, int> int_map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_map2;
|
||||
|
||||
boost::unordered_map<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
map;
|
||||
#endif
|
||||
|
||||
equality_test(int_map);
|
||||
equality_test(int_map2);
|
||||
equality_test(map);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_multimap<int, int> int_multimap;
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
int_multimap2;
|
||||
|
||||
boost::unordered_multimap<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multimap;
|
||||
|
||||
equality_test(int_multimap);
|
||||
equality_test(int_multimap2);
|
||||
equality_test(multimap);
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
equality_tests_impl<boost::unordered_flat_map>();
|
||||
equality_tests_impl<boost::unordered_node_map>();
|
||||
#else
|
||||
equality_tests_impl<boost::unordered_map>();
|
||||
equality_tests_impl<boost::unordered_multimap>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
template <template <class Key, class T, class H = boost::hash<Key>,
|
||||
class P = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||
class Map>
|
||||
static void test1_unique_impl()
|
||||
{
|
||||
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
std::pair<int const, int> map_value(0, 0);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
Map<int, int> map;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<int, int> map;
|
||||
|
||||
boost::unordered_flat_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
Map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
map2;
|
||||
#else
|
||||
boost::unordered_map<int, int> map;
|
||||
|
||||
boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
map2;
|
||||
#endif
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, value, value);
|
||||
@@ -208,27 +176,53 @@ UNORDERED_AUTO_TEST (test1) {
|
||||
unordered_map_test(map2, value, value);
|
||||
unordered_copyable_test(map2, value, map_value, hash, equal_to);
|
||||
unordered_map_functions(map2, value, value);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
template <template <class Key, class T, class H = boost::hash<Key>,
|
||||
class P = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||
class Map>
|
||||
static void test1_equivalent_impl()
|
||||
{
|
||||
|
||||
boost::unordered_multimap<int, int> multimap;
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
std::pair<int const, int> map_value(0, 0);
|
||||
|
||||
boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
Map<int, int> map;
|
||||
|
||||
Map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<std::pair<int const, int> > >
|
||||
multimap2;
|
||||
map2;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, value, value);
|
||||
unordered_copyable_test(multimap, value, map_value, hash, equal_to);
|
||||
unordered_equivalent_test(map, map_value);
|
||||
unordered_map_test(map, value, value);
|
||||
unordered_copyable_test(map, value, map_value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multimap2, map_value);
|
||||
unordered_map_test(multimap2, value, value);
|
||||
unordered_copyable_test(multimap2, value, map_value, hash, equal_to);
|
||||
unordered_equivalent_test(map2, map_value);
|
||||
unordered_map_test(map2, value, value);
|
||||
unordered_copyable_test(map2, value, map_value, hash, equal_to);
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test1_unique_impl<boost::unordered_flat_map>();
|
||||
test1_unique_impl<boost::unordered_node_map>();
|
||||
#else
|
||||
test1_unique_impl<boost::unordered_map>();
|
||||
test1_equivalent_impl<boost::unordered_multimap>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
template <template <class Key, class T, class H = boost::hash<Key>,
|
||||
class P = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||
class Map>
|
||||
static void test2_unique_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
@@ -240,60 +234,66 @@ UNORDERED_AUTO_TEST (test2) {
|
||||
map_value_type;
|
||||
map_value_type map_value(assignable, assignable);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map;
|
||||
#else
|
||||
boost::unordered_map<test::minimal::assignable, test::minimal::assignable,
|
||||
Map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map;
|
||||
#endif
|
||||
|
||||
unordered_unique_test(map, map_value);
|
||||
unordered_map_test(map, assignable, assignable);
|
||||
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(map, map_value);
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
Map<test::minimal::assignable, test::minimal::default_assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map2;
|
||||
#else
|
||||
boost::unordered_map<test::minimal::assignable,
|
||||
test::minimal::default_assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
map2;
|
||||
#endif
|
||||
|
||||
test::minimal::default_assignable default_assignable;
|
||||
|
||||
unordered_map_functions(map2, assignable, default_assignable);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
template <template <class Key, class T, class H = boost::hash<Key>,
|
||||
class P = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T> > >
|
||||
class Map>
|
||||
static void test2_equivalent_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
boost::unordered_multimap<test::minimal::assignable,
|
||||
test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
typedef std::pair<test::minimal::assignable const, test::minimal::assignable>
|
||||
map_value_type;
|
||||
map_value_type map_value(assignable, assignable);
|
||||
|
||||
Map<test::minimal::assignable, test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<map_value_type> >
|
||||
multimap;
|
||||
map;
|
||||
|
||||
unordered_equivalent_test(multimap, map_value);
|
||||
unordered_map_test(multimap, assignable, assignable);
|
||||
unordered_copyable_test(multimap, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(multimap, map_value);
|
||||
unordered_equivalent_test(map, map_value);
|
||||
unordered_map_test(map, assignable, assignable);
|
||||
unordered_copyable_test(map, assignable, map_value, hash, equal_to);
|
||||
unordered_map_member_test(map, map_value);
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test2_unique_impl<boost::unordered_flat_map>();
|
||||
test2_unique_impl<boost::unordered_node_map>();
|
||||
#else
|
||||
test2_unique_impl<boost::unordered_map>();
|
||||
test2_equivalent_impl<boost::unordered_multimap>();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -316,9 +316,17 @@ bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
|
||||
|
||||
UNORDERED_AUTO_TEST (lwg2059) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
{
|
||||
boost::unordered_flat_map<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_map<lwg2059_key, int> x;
|
||||
x.emplace(lwg2059_key(10), 5);
|
||||
x.erase(x.begin());
|
||||
}
|
||||
#else
|
||||
{
|
||||
boost::unordered_map<lwg2059_key, int> x;
|
||||
|
||||
+187
-200
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -35,6 +35,21 @@ template class instantiate_flat_set<test::minimal::assignable const,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
template <typename T, typename H, typename P, typename A>
|
||||
class instantiate_node_set
|
||||
{
|
||||
typedef boost::unordered_node_set<T, H, P, A> container;
|
||||
container x;
|
||||
};
|
||||
|
||||
template class instantiate_node_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
template class instantiate_node_set<test::minimal::assignable const,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<int> >;
|
||||
|
||||
#else
|
||||
|
||||
#define INSTANTIATE(type) \
|
||||
@@ -56,153 +71,106 @@ INSTANTIATE(multiset)<test::minimal::assignable,
|
||||
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (type_traits) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int> set_type;
|
||||
#else
|
||||
typedef boost::unordered_set<int> set_type;
|
||||
#endif
|
||||
|
||||
typedef set_type::iterator iterator;
|
||||
|
||||
template <class X> static void type_traits_impl()
|
||||
{
|
||||
BOOST_STATIC_ASSERT(boost::is_same<int const&,
|
||||
std::iterator_traits<iterator>::reference>::value);
|
||||
typename std::iterator_traits<typename X::iterator>::reference>::value);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
UNORDERED_AUTO_TEST (type_traits) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
type_traits_impl<boost::unordered_flat_set<int> >();
|
||||
type_traits_impl<boost::unordered_node_set<int> >();
|
||||
#else
|
||||
type_traits_impl<boost::unordered_set<int> >();
|
||||
type_traits_impl<boost::unordered_multiset<int> >();
|
||||
#endif
|
||||
}
|
||||
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void test0_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
Set<int> int_set;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> int_set;
|
||||
|
||||
boost::unordered_flat_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
Set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_flat_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
Set<test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
#else
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
#endif
|
||||
|
||||
container_test(int_set, 0);
|
||||
container_test(int_set2, 0);
|
||||
container_test(set, assignable);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_multiset2;
|
||||
|
||||
boost::unordered_multiset<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
multiset;
|
||||
|
||||
container_test(int_multiset, 0);
|
||||
container_test(int_multiset2, 0);
|
||||
container_test(multiset, assignable);
|
||||
UNORDERED_AUTO_TEST (test0) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test0_impl<boost::unordered_flat_set>();
|
||||
test0_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
test0_impl<boost::unordered_set>();
|
||||
test0_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void equality_tests_impl()
|
||||
{
|
||||
typedef test::minimal::copy_constructible_equality_comparable value_type;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> int_set;
|
||||
Set<int> int_set;
|
||||
|
||||
boost::unordered_flat_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
Set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_flat_set<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
Set<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
set;
|
||||
#else
|
||||
boost::unordered_set<int> int_set;
|
||||
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_set2;
|
||||
|
||||
boost::unordered_set<test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
set;
|
||||
#endif
|
||||
|
||||
equality_test(int_set);
|
||||
equality_test(int_set2);
|
||||
equality_test(set);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
int_multiset2;
|
||||
|
||||
boost::unordered_multiset<
|
||||
test::minimal::copy_constructible_equality_comparable,
|
||||
test::minimal::hash<test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::equal_to<
|
||||
test::minimal::copy_constructible_equality_comparable>,
|
||||
test::minimal::allocator<value_type> >
|
||||
multiset;
|
||||
|
||||
equality_test(int_multiset);
|
||||
equality_test(int_multiset2);
|
||||
equality_test(multiset);
|
||||
UNORDERED_AUTO_TEST (equality_tests) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
equality_tests_impl<boost::unordered_flat_set>();
|
||||
equality_tests_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
equality_tests_impl<boost::unordered_set>();
|
||||
equality_tests_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void test1_unique_impl()
|
||||
{
|
||||
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
Set<int> set;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set." << std::endl;
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> set;
|
||||
|
||||
boost::unordered_flat_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
Set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
set2;
|
||||
#else
|
||||
boost::unordered_set<int> set;
|
||||
|
||||
boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
set2;
|
||||
#endif
|
||||
|
||||
unordered_unique_test(set, value);
|
||||
unordered_set_test(set, value);
|
||||
@@ -211,27 +179,49 @@ UNORDERED_AUTO_TEST (test1) {
|
||||
unordered_unique_test(set2, value);
|
||||
unordered_set_test(set2, value);
|
||||
unordered_copyable_test(set2, value, value, hash, equal_to);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset." << std::endl;
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void test1_equivalent_impl()
|
||||
{
|
||||
|
||||
boost::unordered_multiset<int> multiset;
|
||||
boost::hash<int> hash;
|
||||
std::equal_to<int> equal_to;
|
||||
int value = 0;
|
||||
Set<int> set;
|
||||
|
||||
boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
Set<int, boost::hash<int>, std::equal_to<int>,
|
||||
test::minimal::cxx11_allocator<int> >
|
||||
multiset2;
|
||||
set2;
|
||||
|
||||
unordered_equivalent_test(multiset, value);
|
||||
unordered_set_test(multiset, value);
|
||||
unordered_copyable_test(multiset, value, value, hash, equal_to);
|
||||
unordered_equivalent_test(set, value);
|
||||
unordered_set_test(set, value);
|
||||
unordered_copyable_test(set, value, value, hash, equal_to);
|
||||
|
||||
unordered_equivalent_test(multiset2, value);
|
||||
unordered_set_test(multiset2, value);
|
||||
unordered_copyable_test(multiset2, value, value, hash, equal_to);
|
||||
unordered_equivalent_test(set2, value);
|
||||
unordered_set_test(set2, value);
|
||||
unordered_copyable_test(set2, value, value, hash, equal_to);
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (test1) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test1_unique_impl<boost::unordered_flat_set>();
|
||||
test1_unique_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
test1_unique_impl<boost::unordered_set>();
|
||||
test1_equivalent_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void test2_unique_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::assignable assignable(x);
|
||||
@@ -239,155 +229,144 @@ UNORDERED_AUTO_TEST (test2) {
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
Set<test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
#else
|
||||
boost::unordered_set<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
set;
|
||||
#endif
|
||||
|
||||
unordered_unique_test(set, assignable);
|
||||
unordered_set_test(set, assignable);
|
||||
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(set, assignable);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void test2_equivalent_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
boost::unordered_multiset<test::minimal::assignable,
|
||||
test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::assignable assignable(x);
|
||||
test::minimal::copy_constructible copy_constructible(x);
|
||||
test::minimal::hash<test::minimal::assignable> hash(x);
|
||||
test::minimal::equal_to<test::minimal::assignable> equal_to(x);
|
||||
|
||||
Set<test::minimal::assignable, test::minimal::hash<test::minimal::assignable>,
|
||||
test::minimal::equal_to<test::minimal::assignable>,
|
||||
test::minimal::allocator<test::minimal::assignable> >
|
||||
multiset;
|
||||
set;
|
||||
|
||||
unordered_equivalent_test(multiset, assignable);
|
||||
unordered_set_test(multiset, assignable);
|
||||
unordered_copyable_test(multiset, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(multiset, assignable);
|
||||
unordered_equivalent_test(set, assignable);
|
||||
unordered_set_test(set, assignable);
|
||||
unordered_copyable_test(set, assignable, assignable, hash, equal_to);
|
||||
unordered_set_member_test(set, assignable);
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (test2) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test2_unique_impl<boost::unordered_flat_set>();
|
||||
test2_unique_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
test2_unique_impl<boost::unordered_set>();
|
||||
test2_equivalent_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (movable1_tests) {
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void movable1_tests_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::movable1 movable1(x);
|
||||
test::minimal::hash<test::minimal::movable1> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable1> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
Set<test::minimal::movable1, test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
set;
|
||||
#else
|
||||
boost::unordered_set<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
set;
|
||||
#endif
|
||||
|
||||
// TODO: find out why Daniel had this commented out and if we need it and the
|
||||
// corresponding equivalent impl
|
||||
//
|
||||
// unordered_unique_test(set, movable1);
|
||||
unordered_set_test(set, movable1);
|
||||
unordered_movable_test(set, movable1, movable1, hash, equal_to);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::movable1,
|
||||
test::minimal::hash<test::minimal::movable1>,
|
||||
test::minimal::equal_to<test::minimal::movable1>,
|
||||
test::minimal::allocator<test::minimal::movable1> >
|
||||
multiset;
|
||||
|
||||
// unordered_equivalent_test(multiset, movable1);
|
||||
unordered_set_test(multiset, movable1);
|
||||
unordered_movable_test(multiset, movable1, movable1, hash, equal_to);
|
||||
UNORDERED_AUTO_TEST (movable1_tests) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
movable1_tests_impl<boost::unordered_flat_set>();
|
||||
movable1_tests_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
movable1_tests_impl<boost::unordered_set>();
|
||||
movable1_tests_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (movable2_tests) {
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void movable2_tests_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::movable2 movable2(x);
|
||||
test::minimal::hash<test::minimal::movable2> hash(x);
|
||||
test::minimal::equal_to<test::minimal::movable2> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
Set<test::minimal::movable2, test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
set;
|
||||
#else
|
||||
boost::unordered_set<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
set;
|
||||
#endif
|
||||
|
||||
// unordered_unique_test(set, movable2);
|
||||
unordered_set_test(set, movable2);
|
||||
unordered_movable_test(set, movable2, movable2, hash, equal_to);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
UNORDERED_AUTO_TEST (movable2_tests) {
|
||||
|
||||
boost::unordered_multiset<test::minimal::movable2,
|
||||
test::minimal::hash<test::minimal::movable2>,
|
||||
test::minimal::equal_to<test::minimal::movable2>,
|
||||
test::minimal::allocator<test::minimal::movable2> >
|
||||
multiset;
|
||||
|
||||
// unordered_equivalent_test(multiset, movable2);
|
||||
unordered_set_test(multiset, movable2);
|
||||
unordered_movable_test(multiset, movable2, movable2, hash, equal_to);
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
movable2_tests_impl<boost::unordered_flat_set>();
|
||||
movable2_tests_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
movable2_tests_impl<boost::unordered_set>();
|
||||
movable2_tests_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (destructible_tests) {
|
||||
template <template <class T, class H = boost::hash<T>,
|
||||
class P = std::equal_to<T>, class A = std::allocator<T> >
|
||||
class Set>
|
||||
static void destructible_tests_impl()
|
||||
{
|
||||
test::minimal::constructor_param x;
|
||||
|
||||
test::minimal::destructible destructible(x);
|
||||
test::minimal::hash<test::minimal::destructible> hash(x);
|
||||
test::minimal::equal_to<test::minimal::destructible> equal_to(x);
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<test::minimal::destructible,
|
||||
Set<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
set;
|
||||
#else
|
||||
boost::unordered_set<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
set;
|
||||
#endif
|
||||
|
||||
unordered_destructible_test(set);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
|
||||
boost::unordered_multiset<test::minimal::destructible,
|
||||
test::minimal::hash<test::minimal::destructible>,
|
||||
test::minimal::equal_to<test::minimal::destructible> >
|
||||
multiset;
|
||||
|
||||
unordered_destructible_test(multiset);
|
||||
UNORDERED_AUTO_TEST (destructible_tests) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
destructible_tests_impl<boost::unordered_flat_set>();
|
||||
destructible_tests_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
destructible_tests_impl<boost::unordered_set>();
|
||||
destructible_tests_impl<boost::unordered_multiset>();
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -410,9 +389,17 @@ bool operator==(lwg2059_key x, lwg2059_key y) { return x.value == y.value; }
|
||||
|
||||
UNORDERED_AUTO_TEST (lwg2059) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
{
|
||||
boost::unordered_flat_set<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_set<lwg2059_key> x;
|
||||
x.emplace(lwg2059_key(10));
|
||||
x.erase(x.begin());
|
||||
}
|
||||
#else
|
||||
{
|
||||
boost::unordered_set<lwg2059_key> x;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2010 Daniel James.
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
@@ -655,23 +655,27 @@ namespace constructor_tests {
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_node_map;
|
||||
|
||||
UNORDERED_TEST(constructor_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_map))(
|
||||
((test_map_std_alloc)(test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(constructor_tests2,
|
||||
((test_set)(test_map))(
|
||||
((test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(map_constructor_test,
|
||||
((test_map_std_alloc)(test_map))(
|
||||
((test_map_std_alloc)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(no_alloc_default_construct_test,
|
||||
((test_set)(test_map))(
|
||||
((test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
#else
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
@@ -709,6 +713,8 @@ namespace constructor_tests {
|
||||
std::initializer_list<int> init;
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> x1 = init;
|
||||
boost::unordered_node_set<int> x2 = init;
|
||||
BOOST_TEST(x2.empty());
|
||||
#else
|
||||
boost::unordered_set<int> x1 = init;
|
||||
#endif
|
||||
@@ -722,6 +728,9 @@ namespace constructor_tests {
|
||||
UNORDERED_AUTO_TEST (test_initializer_list) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> x1 = {2, 10, 45, -5};
|
||||
boost::unordered_node_set<int> x2 = {2, 10, 45, -5};
|
||||
BOOST_TEST(x2.find(10) != x2.end());
|
||||
BOOST_TEST(x2.find(46) == x2.end());
|
||||
#else
|
||||
boost::unordered_set<int> x1 = {2, 10, 45, -5};
|
||||
#endif
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2022 Christian Mazakas.
|
||||
// Copyright 2021-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -137,6 +137,24 @@ void test_map()
|
||||
|
||||
typedef boost::unordered_flat_map<key, int, hasher, key_equal>
|
||||
non_transparent_map3;
|
||||
|
||||
typedef boost::unordered_node_map<key, int, transparent_hasher,
|
||||
transparent_key_equal>
|
||||
transparent_node_map;
|
||||
|
||||
typedef boost::unordered_node_map<key, int, transparent_hasher, key_equal>
|
||||
non_transparent_node_map1;
|
||||
|
||||
typedef boost::unordered_node_map<key, int, hasher, transparent_key_equal>
|
||||
non_transparent_node_map2;
|
||||
|
||||
typedef boost::unordered_node_map<key, int, hasher, key_equal>
|
||||
non_transparent_node_map3;
|
||||
|
||||
test_map_transparent_contains<transparent_node_map>();
|
||||
test_map_non_transparent_contains<non_transparent_node_map1>();
|
||||
test_map_non_transparent_contains<non_transparent_node_map2>();
|
||||
test_map_non_transparent_contains<non_transparent_node_map3>();
|
||||
#else
|
||||
typedef boost::unordered_map<key, int, transparent_hasher,
|
||||
transparent_key_equal>
|
||||
@@ -254,6 +272,22 @@ void test_set()
|
||||
non_transparent_set2;
|
||||
typedef boost::unordered_flat_set<key, hasher, key_equal>
|
||||
non_transparent_set3;
|
||||
|
||||
typedef boost::unordered_node_set<key, transparent_hasher,
|
||||
transparent_key_equal>
|
||||
transparent_node_set;
|
||||
|
||||
typedef boost::unordered_node_set<key, transparent_hasher, key_equal>
|
||||
non_transparent_node_set1;
|
||||
typedef boost::unordered_node_set<key, hasher, transparent_key_equal>
|
||||
non_transparent_node_set2;
|
||||
typedef boost::unordered_node_set<key, hasher, key_equal>
|
||||
non_transparent_node_set3;
|
||||
|
||||
test_set_transparent_contains<transparent_node_set>();
|
||||
test_set_non_transparent_contains<non_transparent_node_set1>();
|
||||
test_set_non_transparent_contains<non_transparent_node_set2>();
|
||||
test_set_non_transparent_contains<non_transparent_node_set3>();
|
||||
#else
|
||||
typedef boost::unordered_set<key, transparent_hasher, transparent_key_equal>
|
||||
transparent_set;
|
||||
|
||||
+326
-12
@@ -1,18 +1,18 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// 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/unordered.hpp"
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
#include "../objects/cxx11_allocator.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/cxx11_allocator.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
test::seed_t initialize_seed(9063);
|
||||
|
||||
@@ -225,11 +225,227 @@ namespace copy_tests {
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests_std_allocator1(
|
||||
T*, test::random_generator const& generator)
|
||||
{
|
||||
typename T::hasher hf;
|
||||
typename T::key_equal eq;
|
||||
typename T::allocator_type al;
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x;
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
|
||||
T x(v.begin(), v.end());
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
// In this test I drop the original containers max load factor, so it
|
||||
// is much lower than the load factor. The hash table is not allowed
|
||||
// to rehash, but the destination container should probably allocate
|
||||
// enough buckets to decrease the load factor appropriately.
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end());
|
||||
x.max_load_factor(x.load_factor() / 4);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
// This isn't guaranteed:
|
||||
BOOST_TEST(y.load_factor() < y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void copy_construct_tests_std_allocator2(
|
||||
T*, test::random_generator const& generator)
|
||||
{
|
||||
typename T::hasher hf(1);
|
||||
typename T::key_equal eq(1);
|
||||
typename T::allocator_type al;
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(10000, hf, eq, al);
|
||||
T y(x);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(0, hf, eq, al);
|
||||
T y(x, al);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(1000, hf, eq, al);
|
||||
T y(x, al);
|
||||
BOOST_TEST(y.empty());
|
||||
BOOST_TEST(test::equivalent(y.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(y.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(x.max_load_factor() == y.max_load_factor());
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
test::check_equivalent_keys(y);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v;
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v;
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
BOOST_TEST(test::detail::tracker.count_allocations == 0);
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(500, generator);
|
||||
|
||||
T x(v.begin(), v.end(), 0, hf, eq, al);
|
||||
T y(x, al);
|
||||
test::unordered_equivalence_tester<T> equivalent(x);
|
||||
BOOST_TEST(equivalent(y));
|
||||
test::check_equivalent_keys(y);
|
||||
BOOST_TEST(test::selected_count(y.get_allocator()) == 0);
|
||||
BOOST_TEST(test::equivalent(y.get_allocator(), al));
|
||||
}
|
||||
}
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
template <class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
allocator(allocator const&) = default;
|
||||
allocator(allocator&&) = default;
|
||||
|
||||
template <class U> allocator(allocator<U> const&) {}
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
return static_cast<T*>(::operator new(sizeof(value_type) * n));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) { ::operator delete(p); }
|
||||
|
||||
friend inline bool operator==(allocator const&, allocator const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
friend inline bool operator!=(allocator const&, allocator const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
@@ -249,13 +465,101 @@ namespace copy_tests {
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_map_no_select_copy;
|
||||
|
||||
boost::unordered_flat_set<int, test::hash, test::equal_to,
|
||||
test::allocator1<int> >* test_set_trivially_copyable;
|
||||
boost::unordered_flat_map<int, int, test::hash, test::equal_to,
|
||||
test::allocator1<std::pair<int const, int> > >* test_map_trivially_copyable;
|
||||
|
||||
boost::unordered_flat_set<int, test::hash, test::equal_to,
|
||||
std::allocator<int> >* test_set_trivially_copyable_std_allocator;
|
||||
boost::unordered_flat_map<int, int, test::hash, test::equal_to,
|
||||
std::allocator<std::pair<int const, int> > >*
|
||||
test_map_trivially_copyable_std_allocator;
|
||||
|
||||
boost::unordered_flat_set<int, test::hash, test::equal_to, allocator<int> >*
|
||||
test_set_trivially_copyable_no_construct;
|
||||
boost::unordered_flat_map<int, int, test::hash, test::equal_to,
|
||||
allocator<std::pair<int const, int> > >*
|
||||
test_map_trivially_copyable_no_construct;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_node_map;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_node_set_select_copy;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::select_copy> >*
|
||||
test_node_map_select_copy;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_node_set_no_select_copy;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_node_map_no_select_copy;
|
||||
|
||||
boost::unordered_node_set<int, test::hash, test::equal_to,
|
||||
test::allocator1<int> >* test_node_set_trivially_copyable;
|
||||
boost::unordered_node_map<int, int, test::hash, test::equal_to,
|
||||
test::allocator1<std::pair<int const, int> > >*
|
||||
test_node_map_trivially_copyable;
|
||||
|
||||
boost::unordered_node_set<int, test::hash, test::equal_to,
|
||||
std::allocator<int> >* test_node_set_trivially_copyable_std_allocator;
|
||||
boost::unordered_node_map<int, int, test::hash, test::equal_to,
|
||||
std::allocator<std::pair<int const, int> > >*
|
||||
test_node_map_trivially_copyable_std_allocator;
|
||||
|
||||
boost::unordered_node_set<int, test::hash, test::equal_to, allocator<int> >*
|
||||
test_node_set_trivially_copyable_no_construct;
|
||||
boost::unordered_node_map<int, int, test::hash, test::equal_to,
|
||||
allocator<std::pair<int const, int> > >*
|
||||
test_node_map_trivially_copyable_no_construct;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(copy_construct_tests1,
|
||||
((test_set)(test_map)(test_set_select_copy)(test_map_select_copy)(test_set_no_select_copy)(test_map_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
((test_set)(test_map)(test_set_select_copy)(test_map_select_copy)
|
||||
(test_set_no_select_copy)(test_map_no_select_copy)
|
||||
(test_set_trivially_copyable)(test_map_trivially_copyable)
|
||||
(test_node_set)(test_node_map)(test_node_set_select_copy)(test_node_map_select_copy)
|
||||
(test_node_set_no_select_copy)(test_node_map_no_select_copy)
|
||||
(test_node_set_trivially_copyable)(test_node_map_trivially_copyable))
|
||||
((default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2,
|
||||
((test_set)(test_map)(test_set_select_copy)(test_map_select_copy)(test_set_no_select_copy)(test_map_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
((test_set)(test_map)(test_set_select_copy)(test_map_select_copy)
|
||||
(test_set_no_select_copy)(test_map_no_select_copy)
|
||||
(test_set_trivially_copyable)(test_map_trivially_copyable)
|
||||
(test_node_set)(test_node_map)(test_node_set_select_copy)(test_node_map_select_copy)
|
||||
(test_node_set_no_select_copy)(test_node_map_no_select_copy)
|
||||
(test_node_set_trivially_copyable)(test_node_map_trivially_copyable))
|
||||
((default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests_std_allocator1,
|
||||
((test_set_trivially_copyable_std_allocator)
|
||||
(test_map_trivially_copyable_std_allocator)
|
||||
(test_set_trivially_copyable_no_construct)
|
||||
(test_map_trivially_copyable_no_construct)
|
||||
(test_node_set_trivially_copyable_std_allocator)
|
||||
(test_node_map_trivially_copyable_std_allocator)
|
||||
(test_node_set_trivially_copyable_no_construct)
|
||||
(test_node_map_trivially_copyable_no_construct))
|
||||
((default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests_std_allocator2,
|
||||
((test_set_trivially_copyable_std_allocator)
|
||||
(test_map_trivially_copyable_std_allocator)
|
||||
(test_set_trivially_copyable_no_construct)
|
||||
(test_map_trivially_copyable_no_construct)
|
||||
(test_node_set_trivially_copyable_std_allocator)
|
||||
(test_node_map_trivially_copyable_std_allocator)
|
||||
(test_node_set_trivially_copyable_no_construct)
|
||||
(test_node_map_trivially_copyable_no_construct))
|
||||
((default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
@@ -292,13 +596,23 @@ namespace copy_tests {
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::no_select_copy> >*
|
||||
test_multimap_no_select_copy;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(copy_construct_tests1,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy))(
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)
|
||||
(test_set_select_copy)(test_multiset_select_copy)
|
||||
(test_map_select_copy)(test_multimap_select_copy)
|
||||
(test_set_no_select_copy)(test_multiset_no_select_copy)
|
||||
(test_map_no_select_copy)(test_multimap_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(copy_construct_tests2,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_select_copy)(test_multiset_select_copy)(test_map_select_copy)(test_multimap_select_copy)(test_set_no_select_copy)(test_multiset_no_select_copy)(test_map_no_select_copy)(test_multimap_no_select_copy))(
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)
|
||||
(test_set_select_copy)(test_multiset_select_copy)
|
||||
(test_map_select_copy)(test_multimap_select_copy)
|
||||
(test_set_no_select_copy)(test_multiset_no_select_copy)
|
||||
(test_map_no_select_copy)(test_multimap_no_select_copy))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#endif
|
||||
} // namespace copy_tests
|
||||
|
||||
|
||||
@@ -269,14 +269,14 @@ template <template <class...> class UnorderedSet> void set_tests()
|
||||
test_allocator<int> int_allocator;
|
||||
|
||||
/* template<class InputIt,
|
||||
class Hash = std::hash<typename
|
||||
std::iterator_traits<InputIt>::value_type>, class Pred =
|
||||
class Hash = std::hash<typename
|
||||
std::iterator_traits<InputIt>::value_type>, class Pred =
|
||||
std::equal_to<typename std::iterator_traits<InputIt>::value_type>, class
|
||||
Alloc = std::allocator<typename std::iterator_traits<InputIt>::value_type>>
|
||||
unordered_set(InputIt, InputIt,
|
||||
unordered_set(InputIt, InputIt,
|
||||
typename see below ::size_type = see below,
|
||||
Hash = Hash(), Pred = Pred(), Alloc = Alloc())
|
||||
-> unordered_set<typename std::iterator_traits<InputIt>::value_type, Hash,
|
||||
Hash = Hash(), Pred = Pred(), Alloc = Alloc())
|
||||
-> unordered_set<typename std::iterator_traits<InputIt>::value_type, Hash,
|
||||
Pred, Alloc>; */
|
||||
|
||||
{
|
||||
@@ -390,6 +390,35 @@ template <template <class...> class UnorderedSet> void set_tests()
|
||||
BOOST_TEST_TRAIT_SAME(decltype(s),
|
||||
UnorderedSet<int, hash_equals, std::equal_to<int>, test_allocator<int> >);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class InputIterator, class Allocator>
|
||||
unordered_set(InputIterator, InputIterator, Allocator)
|
||||
-> unordered_set<iter-value-type<InputIterator>,
|
||||
hash<iter-value-type<InputIterator>>,
|
||||
equal_to<iter-value-type<InputIterator>>,
|
||||
Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
UnorderedSet s(y.begin(), y.end(), int_allocator);
|
||||
BOOST_TEST_TRAIT_SAME(
|
||||
decltype(s), UnorderedSet<int, boost::hash<int>, std::equal_to<int>,
|
||||
test_allocator<int> >);
|
||||
}
|
||||
|
||||
/*
|
||||
template<class T, class Allocator>
|
||||
unordered_set(initializer_list<T>, Allocator)
|
||||
-> unordered_set<T, hash<T>, equal_to<T>, Allocator>;
|
||||
*/
|
||||
|
||||
{
|
||||
UnorderedSet s({1, 2}, int_allocator);
|
||||
BOOST_TEST_TRAIT_SAME(
|
||||
decltype(s), UnorderedSet<int, boost::hash<int>, std::equal_to<int>,
|
||||
test_allocator<int> >);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -179,18 +179,13 @@ namespace emplace_tests {
|
||||
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_set) {
|
||||
template <class X> static void emplace_set(X*)
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
#else
|
||||
typedef boost::unordered_set<emplace_value, boost::hash<emplace_value> >
|
||||
container;
|
||||
#endif
|
||||
typedef container::iterator iterator;
|
||||
typedef X container;
|
||||
|
||||
typedef typename container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
iterator i1;
|
||||
@@ -225,7 +220,7 @@ namespace emplace_tests {
|
||||
BOOST_TEST(r1.first == x.find(v2));
|
||||
BOOST_TEST_EQ(check_.instances(), 4);
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_TEST_EQ(check_.constructions(), 6);
|
||||
BOOST_TEST_EQ(check_.constructions(), 6);
|
||||
#else
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
#endif
|
||||
@@ -294,6 +289,21 @@ namespace emplace_tests {
|
||||
BOOST_TEST(x.count(v4) == 1);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_set<emplace_value, boost::hash<emplace_value> >*
|
||||
test_set;
|
||||
|
||||
static boost::unordered_node_set<emplace_value, boost::hash<emplace_value> >*
|
||||
test_node_set;
|
||||
|
||||
UNORDERED_TEST(emplace_set, ((test_set)(test_node_set)))
|
||||
#else
|
||||
static boost::unordered_set<emplace_value, boost::hash<emplace_value> >*
|
||||
test_set;
|
||||
|
||||
UNORDERED_TEST(emplace_set, ((test_set)))
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (emplace_multiset) {
|
||||
test::check_instances check_;
|
||||
@@ -374,18 +384,12 @@ namespace emplace_tests {
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (emplace_map) {
|
||||
template <class X> static void emplace_map(X*)
|
||||
{
|
||||
test::check_instances check_;
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
#else
|
||||
typedef boost::unordered_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >
|
||||
container;
|
||||
#endif
|
||||
typedef container::iterator iterator;
|
||||
|
||||
typedef X container;
|
||||
typedef typename container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
return_type r1, r2;
|
||||
@@ -393,7 +397,9 @@ namespace emplace_tests {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
// 5/8 args + duplicate
|
||||
emplace_value k1(5, "", 'b', 4, 5);
|
||||
BOOST_TEST_EQ(check_.constructions(), 1);
|
||||
emplace_value m1(8, "xxx", 'z', 4, 5, 6, 7, 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 2);
|
||||
r1 = x.emplace(std::piecewise_construct, std::make_tuple(5, "", 'b', 4, 5),
|
||||
std::make_tuple(8, "xxx", 'z', 4, 5, 6, 7, 8));
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
@@ -485,18 +491,18 @@ namespace emplace_tests {
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
BOOST_TEST_EQ(check_.constructions(), 10);
|
||||
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(r1.first, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(15, "jkjk")));
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(r2.first, boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(275, "xxx", 'm', 6)));
|
||||
BOOST_TEST(r1.first ==
|
||||
x.emplace_hint(x.end(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(-10, "blah blah", '\0')));
|
||||
BOOST_TEST(r1.first == x.emplace_hint(r1.first,
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(15, "jkjk")));
|
||||
BOOST_TEST(r1.first == x.emplace_hint(r2.first,
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(275, "xxx", 'm', 6)));
|
||||
BOOST_TEST(
|
||||
r1.first == x.emplace_hint(x.end(), boost::unordered::piecewise_construct,
|
||||
boost::make_tuple(9, "", 'b', 4, 5, 6, 7, 8, 9),
|
||||
boost::make_tuple(-10, "blah blah", '\0')));
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
BOOST_TEST(x.find(k2)->second == m2);
|
||||
BOOST_TEST_EQ(check_.instances(), 8);
|
||||
@@ -504,6 +510,21 @@ namespace emplace_tests {
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >* test_map;
|
||||
|
||||
static boost::unordered_node_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >* test_node_map;
|
||||
|
||||
UNORDERED_TEST(emplace_map, ((test_map)(test_node_map)))
|
||||
#else
|
||||
static boost::unordered_map<emplace_value, emplace_value,
|
||||
boost::hash<emplace_value> >* test_map;
|
||||
|
||||
UNORDERED_TEST(emplace_map, ((test_map)))
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (emplace_multimap) {
|
||||
test::check_instances check_;
|
||||
@@ -571,14 +592,13 @@ namespace emplace_tests {
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (try_emplace) {
|
||||
template <class X> static void try_emplace(X*)
|
||||
{
|
||||
test::check_instances check_;
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_map<int, emplace_value> container;
|
||||
#else
|
||||
typedef boost::unordered_map<int, emplace_value> container;
|
||||
#endif
|
||||
typedef container::iterator iterator;
|
||||
|
||||
typedef X container;
|
||||
|
||||
typedef typename container::iterator iterator;
|
||||
typedef std::pair<iterator, bool> return_type;
|
||||
container x(10);
|
||||
return_type r1, r2, r3;
|
||||
@@ -615,12 +635,22 @@ namespace emplace_tests {
|
||||
BOOST_TEST_EQ(check_.constructions(), 4);
|
||||
|
||||
BOOST_TEST(r2.first == x.try_emplace(r2.first, k2, 808709, "what"));
|
||||
BOOST_TEST(
|
||||
r2.first ==
|
||||
x.try_emplace(r2.first, k2, 10, "xxx", 'a', 4, 5, 6, 7, 8, 9, 10));
|
||||
BOOST_TEST(r2.first == x.try_emplace(r2.first, k2, 10, "xxx", 'a', 4, 5, 6,
|
||||
7, 8, 9, 10));
|
||||
BOOST_TEST(r2.first->second == m2);
|
||||
BOOST_TEST_EQ(x.size(), 2u);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_map<int, emplace_value>* test_int_map;
|
||||
static boost::unordered_node_map<int, emplace_value>* test_int_node_map;
|
||||
|
||||
UNORDERED_TEST(try_emplace, ((test_int_map)(test_int_node_map)))
|
||||
#else
|
||||
static boost::unordered_map<int, emplace_value>* test_int_map;
|
||||
|
||||
UNORDERED_TEST(try_emplace, ((test_int_map)))
|
||||
#endif
|
||||
}
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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/unordered.hpp"
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/preprocessor/seq.hpp>
|
||||
#include <list>
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
// TODO: this test needs to be someday cleaned up to not be so heavily
|
||||
// macro-generated
|
||||
//
|
||||
|
||||
namespace equality_tests {
|
||||
struct mod_compare
|
||||
@@ -33,6 +37,12 @@ namespace equality_tests {
|
||||
using boost_unordered_map =
|
||||
boost::unordered_flat_map<int, int, mod_compare, mod_compare>;
|
||||
|
||||
using boost_unordered_node_set =
|
||||
boost::unordered_node_set<int, mod_compare, mod_compare>;
|
||||
|
||||
using boost_unordered_node_map =
|
||||
boost::unordered_node_map<int, int, mod_compare, mod_compare>;
|
||||
|
||||
#define UNORDERED_EQUALITY_MULTISET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
}
|
||||
@@ -64,14 +74,46 @@ namespace equality_tests {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost_unordered_set set1, set2; \
|
||||
boost_unordered_set set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
} \
|
||||
{ \
|
||||
boost_unordered_node_set set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
#else
|
||||
#define UNORDERED_EQUALITY_SET_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost_unordered_set set1, set2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_SET_INSERT, set2, seq2) \
|
||||
BOOST_TEST(set1 op set2); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost_unordered_map map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
} \
|
||||
\
|
||||
{ \
|
||||
boost_unordered_node_map map1, map2; \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map1, seq1) \
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
#else
|
||||
#define UNORDERED_EQUALITY_MAP_TEST(seq1, op, seq2) \
|
||||
{ \
|
||||
boost_unordered_map map1, map2; \
|
||||
@@ -79,6 +121,7 @@ namespace equality_tests {
|
||||
BOOST_PP_SEQ_FOR_EACH(UNORDERED_MAP_INSERT, map2, seq2) \
|
||||
BOOST_TEST(map1 op map2); \
|
||||
}
|
||||
#endif
|
||||
|
||||
#define UNORDERED_SET_INSERT(r, set, item) set.insert(item);
|
||||
#define UNORDERED_MAP_INSERT(r, map, item) \
|
||||
@@ -86,10 +129,51 @@ namespace equality_tests {
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_size_tests) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> x1, x2;
|
||||
{
|
||||
boost::unordered_flat_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_set<int> x1, x2;
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x1.insert(1);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
|
||||
x2.insert(1);
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
x2.insert(2);
|
||||
BOOST_TEST(x1 != x2);
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
}
|
||||
#else
|
||||
boost::unordered_set<int> x1, x2;
|
||||
#endif
|
||||
BOOST_TEST(x1 == x2);
|
||||
BOOST_TEST(!(x1 != x2));
|
||||
|
||||
@@ -108,6 +192,7 @@ namespace equality_tests {
|
||||
BOOST_TEST(!(x1 == x2));
|
||||
BOOST_TEST(x2 != x1);
|
||||
BOOST_TEST(!(x2 == x1));
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_key_value_tests) {
|
||||
@@ -156,6 +241,45 @@ namespace equality_tests {
|
||||
// different hash functions but the same equality predicate.
|
||||
|
||||
UNORDERED_AUTO_TEST (equality_different_hash_test) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
{
|
||||
typedef boost_unordered_set set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1);
|
||||
set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2);
|
||||
set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10);
|
||||
set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20);
|
||||
set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
|
||||
{
|
||||
typedef boost_unordered_node_set set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(1);
|
||||
set2.insert(2);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(2);
|
||||
set2.insert(1);
|
||||
BOOST_TEST(set1 == set2);
|
||||
set1.insert(10);
|
||||
set2.insert(20);
|
||||
BOOST_TEST(set1 != set2);
|
||||
set1.insert(20);
|
||||
set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
}
|
||||
#else
|
||||
typedef boost_unordered_set set;
|
||||
set set1(0, mod_compare(false), mod_compare(false));
|
||||
set set2(0, mod_compare(true), mod_compare(true));
|
||||
@@ -172,7 +296,8 @@ namespace equality_tests {
|
||||
set1.insert(20);
|
||||
set2.insert(10);
|
||||
BOOST_TEST(set1 == set2);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
} // namespace equality_tests
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -36,9 +36,21 @@ UNORDERED_AUTO_TEST (set_tests) {
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int> set;
|
||||
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<set>(values[4], values[4] + 3);
|
||||
|
||||
typedef boost::unordered_node_set<int> node_set;
|
||||
test_equal_insertion<node_set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<node_set>(values[1], values[1] + 2);
|
||||
test_equal_insertion<node_set>(values[2], values[2] + 2);
|
||||
test_equal_insertion<node_set>(values[3], values[3] + 2);
|
||||
test_equal_insertion<node_set>(values[4], values[4] + 3);
|
||||
#else
|
||||
typedef boost::unordered_set<int> set;
|
||||
#endif
|
||||
|
||||
test_equal_insertion<set>(values[0], values[0] + 1);
|
||||
test_equal_insertion<set>(values[1], values[1] + 2);
|
||||
@@ -52,6 +64,8 @@ UNORDERED_AUTO_TEST (set_tests) {
|
||||
test_equal_insertion<multiset>(values[2], values[2] + 2);
|
||||
test_equal_insertion<multiset>(values[3], values[3] + 2);
|
||||
test_equal_insertion<multiset>(values[4], values[4] + 3);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (map_tests) {
|
||||
@@ -65,11 +79,16 @@ UNORDERED_AUTO_TEST (map_tests) {
|
||||
v[2].push_back(std::pair<int const, int>(9, 13));
|
||||
v[2].push_back(std::pair<int const, int>(432, 24));
|
||||
|
||||
for (int i = 0; i < 5; ++i)
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
for (int i = 0; i < 5; ++i)
|
||||
test_equal_insertion<boost::unordered_flat_map<int, int> >(
|
||||
v[i].begin(), v[i].end());
|
||||
|
||||
for (int i2 = 0; i2 < 5; ++i2)
|
||||
test_equal_insertion<boost::unordered_node_map<int, int> >(
|
||||
v[i2].begin(), v[i2].end());
|
||||
#else
|
||||
for (int i = 0; i < 5; ++i)
|
||||
test_equal_insertion<boost::unordered_map<int, int> >(
|
||||
v[i].begin(), v[i].end());
|
||||
|
||||
|
||||
@@ -110,6 +110,8 @@ UNORDERED_AUTO_TEST (unordered_erase_if) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
test_map_erase_if<boost::unordered_flat_map<std::string, int> >();
|
||||
test_set_erase_if<boost::unordered_flat_set<int> >();
|
||||
test_map_erase_if<boost::unordered_node_map<std::string, int> >();
|
||||
test_set_erase_if<boost::unordered_node_set<int> >();
|
||||
#else
|
||||
test_map_erase_if<boost::unordered_map<std::string, int> >();
|
||||
test_map_erase_if<boost::unordered_multimap<std::string, int> >();
|
||||
|
||||
@@ -270,10 +270,16 @@ namespace erase_tests {
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_map;
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_node_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(
|
||||
erase_tests1, ((test_set)(test_map))(
|
||||
erase_tests1, ((test_set)(test_map)(test_node_set)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
@@ -284,10 +290,11 @@ namespace erase_tests {
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(
|
||||
erase_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
// clang-format off
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/postfix.hpp"
|
||||
// clang-format on
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
@@ -113,6 +109,19 @@ namespace extract_tests {
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "\n";
|
||||
}
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_node_map;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
|
||||
UNORDERED_TEST(extract_tests1,
|
||||
((test_node_map)(test_node_set))((default_generator)(generate_collisions)))
|
||||
#else
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
@@ -122,12 +131,10 @@ namespace extract_tests {
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator2<test::object> >* test_multimap;
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
|
||||
UNORDERED_TEST(
|
||||
extract_tests1, ((test_set)(test_multiset)(test_map)(test_multimap))(
|
||||
(default_generator)(generate_collisions)))
|
||||
}
|
||||
#endif
|
||||
} // namespace extract_tests
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
@@ -138,9 +138,13 @@ namespace find_tests {
|
||||
test::allocator2<test::object> >* test_set;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_map;
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_node_set;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_node_map;
|
||||
|
||||
UNORDERED_TEST(
|
||||
find_tests1, ((test_set)(test_map))(
|
||||
find_tests1, ((test_set)(test_map)(test_node_set)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
#else
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "../helpers/prefix.hpp"
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
#include <boost/unordered/unordered_flat_map_fwd.hpp>
|
||||
#include <boost/unordered/unordered_node_map_fwd.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#else
|
||||
#include <boost/unordered/unordered_map_fwd.hpp>
|
||||
@@ -23,6 +24,13 @@ void call_swap(
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void call_swap(
|
||||
boost::unordered_node_map<T, T>& x, boost::unordered_node_map<T, T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_flat_map<T, T>& x, boost::unordered_flat_map<T, T>& y)
|
||||
@@ -30,6 +38,13 @@ bool call_equals(
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_node_map<T, T>& x, boost::unordered_node_map<T, T>& y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_flat_map<T, T>& x, boost::unordered_flat_map<T, T>& y)
|
||||
@@ -37,7 +52,15 @@ bool call_not_equals(
|
||||
return x != y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_node_map<T, T>& x, boost::unordered_node_map<T, T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/unordered/unordered_node_map.hpp>
|
||||
#else
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_map<T, T>& x, boost::unordered_map<T, T>& y)
|
||||
@@ -85,6 +108,7 @@ bool call_not_equals(
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_map<int, int> int_map;
|
||||
typedef boost::unordered_node_map<int, int> int_node_map;
|
||||
#else
|
||||
typedef boost::unordered_map<int, int> int_map;
|
||||
typedef boost::unordered_multimap<int, int> int_multimap;
|
||||
@@ -106,6 +130,24 @@ UNORDERED_AUTO_TEST (use_map_fwd_declared_function) {
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (use_node_map_fwd_declared_function) {
|
||||
int_node_map x, y;
|
||||
x[1] = 2;
|
||||
y[2] = 1;
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end() && y.find(1)->second == 2);
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end() && x.find(2)->second == 1);
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (use_multimap_fwd_declared_function) {
|
||||
int_multimap x, y;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "../helpers/prefix.hpp"
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
#include <boost/unordered/unordered_flat_set_fwd.hpp>
|
||||
#include <boost/unordered/unordered_node_set_fwd.hpp>
|
||||
#include <boost/unordered/detail/implementation.hpp>
|
||||
#else
|
||||
#include <boost/unordered/unordered_set_fwd.hpp>
|
||||
@@ -31,12 +32,22 @@ template <class Value, class Hash, class Pred, class Alloc>
|
||||
true_type is_unordered_set_impl(
|
||||
boost::unordered_flat_set<Value, Hash, Pred, Alloc>*);
|
||||
|
||||
template <class Value, class Hash, class Pred, class Alloc>
|
||||
true_type is_unordered_set_impl(
|
||||
boost::unordered_node_set<Value, Hash, Pred, Alloc>*);
|
||||
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_flat_set<T>& x, boost::unordered_flat_set<T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void call_swap(boost::unordered_node_set<T>& x, boost::unordered_node_set<T>& y)
|
||||
{
|
||||
swap(x, y);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_flat_set<T>& x, boost::unordered_flat_set<T>& y)
|
||||
@@ -44,12 +55,26 @@ bool call_equals(
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_equals(
|
||||
boost::unordered_node_set<T>& x, boost::unordered_node_set<T>& y)
|
||||
{
|
||||
return x == y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_flat_set<T>& x, boost::unordered_flat_set<T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool call_not_equals(
|
||||
boost::unordered_node_set<T>& x, boost::unordered_node_set<T>& y)
|
||||
{
|
||||
return x != y;
|
||||
}
|
||||
#else
|
||||
template <class Value, class Hash, class Pred, class Alloc>
|
||||
true_type is_unordered_set_impl(
|
||||
@@ -100,6 +125,7 @@ bool call_not_equals(
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int> int_set;
|
||||
typedef boost::unordered_node_set<int> int_node_set;
|
||||
#else
|
||||
typedef boost::unordered_set<int> int_set;
|
||||
typedef boost::unordered_multiset<int> int_multiset;
|
||||
@@ -107,10 +133,15 @@ typedef boost::unordered_multiset<int> int_multiset;
|
||||
|
||||
UNORDERED_AUTO_TEST (use_fwd_declared_trait_without_definition) {
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int_set*)0)) == sizeof(true_type));
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_TEST(
|
||||
sizeof(is_unordered_set_impl((int_node_set*)0)) == sizeof(true_type));
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
#include <boost/unordered/unordered_flat_set.hpp>
|
||||
#include <boost/unordered/unordered_node_set.hpp>
|
||||
#else
|
||||
#include <boost/unordered_set.hpp>
|
||||
#endif
|
||||
@@ -118,10 +149,17 @@ UNORDERED_AUTO_TEST (use_fwd_declared_trait_without_definition) {
|
||||
UNORDERED_AUTO_TEST (use_fwd_declared_trait) {
|
||||
int_set x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int*)0)) == sizeof(false_type));
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (use_node_fwd_declared_trait) {
|
||||
int_node_set x;
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl(&x)) == sizeof(true_type));
|
||||
BOOST_TEST(sizeof(is_unordered_set_impl((int*)0)) == sizeof(false_type));
|
||||
}
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (use_set_fwd_declared_function) {
|
||||
int_set x, y;
|
||||
x.insert(1);
|
||||
@@ -138,6 +176,24 @@ UNORDERED_AUTO_TEST (use_set_fwd_declared_function) {
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (use_node_set_fwd_declared_function) {
|
||||
int_node_set x, y;
|
||||
x.insert(1);
|
||||
y.insert(2);
|
||||
call_swap(x, y);
|
||||
|
||||
BOOST_TEST(y.find(1) != y.end());
|
||||
BOOST_TEST(y.find(2) == y.end());
|
||||
|
||||
BOOST_TEST(x.find(1) == x.end());
|
||||
BOOST_TEST(x.find(2) != x.end());
|
||||
|
||||
BOOST_TEST(!call_equals(x, y));
|
||||
BOOST_TEST(call_not_equals(x, y));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (use_multiset_fwd_declared_function) {
|
||||
int_multiset x, y;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -13,11 +13,12 @@ namespace x {
|
||||
{
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<D, D> x;
|
||||
boost::unordered_node_map<D, D> y;
|
||||
#else
|
||||
boost::unordered_map<D, D> x;
|
||||
#endif
|
||||
};
|
||||
}
|
||||
} // namespace x
|
||||
|
||||
namespace incomplete_test {
|
||||
// Declare, but don't define some types.
|
||||
@@ -33,11 +34,11 @@ namespace incomplete_test {
|
||||
typedef boost::unordered_flat_map<value, value, hash, equals,
|
||||
allocator<std::pair<value const, value> > >
|
||||
map;
|
||||
typedef boost::unordered_flat_map<value, value, hash, equals,
|
||||
typedef boost::unordered_flat_set<value, hash, equals, allocator<value> > set;
|
||||
typedef boost::unordered_node_map<value, value, hash, equals,
|
||||
allocator<std::pair<value const, value> > >
|
||||
multimap;
|
||||
typedef boost::unordered_flat_set<value, hash, equals, allocator<value> > set;
|
||||
typedef boost::unordered_flat_set<value, hash, equals, allocator<value> >
|
||||
typedef boost::unordered_node_set<value, hash, equals, allocator<value> >
|
||||
multiset;
|
||||
#else
|
||||
typedef boost::unordered_map<value, value, hash, equals,
|
||||
@@ -97,7 +98,7 @@ namespace incomplete_test {
|
||||
};
|
||||
struct struct2
|
||||
{
|
||||
boost::unordered_flat_map<struct2, struct2, hash, equals,
|
||||
boost::unordered_node_map<struct2, struct2, hash, equals,
|
||||
allocator<std::pair<struct2 const, struct2> > >
|
||||
x;
|
||||
};
|
||||
@@ -107,7 +108,7 @@ namespace incomplete_test {
|
||||
};
|
||||
struct struct4
|
||||
{
|
||||
boost::unordered_flat_set<struct4, hash, equals, allocator<struct4> > x;
|
||||
boost::unordered_node_set<struct4, hash, equals, allocator<struct4> > x;
|
||||
};
|
||||
#else
|
||||
struct struct1
|
||||
@@ -195,7 +196,7 @@ namespace incomplete_test {
|
||||
bool operator==(struct2 const&, struct2 const&) { return true; }
|
||||
bool operator==(struct3 const&, struct3 const&) { return true; }
|
||||
bool operator==(struct4 const&, struct4 const&) { return true; }
|
||||
}
|
||||
} // namespace incomplete_test
|
||||
|
||||
int main()
|
||||
{
|
||||
|
||||
@@ -7,9 +7,16 @@
|
||||
#error "This test is only for the FOA-style conatiners"
|
||||
#endif
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <boost/config.hpp>
|
||||
|
||||
#if defined(BOOST_LIBSTDCXX_VERSION)
|
||||
#if BOOST_LIBSTDCXX_VERSION < 60000
|
||||
#define BOOST_UNORDERED_NO_INIT_TYPE_TESTS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
struct move_only
|
||||
{
|
||||
@@ -26,18 +33,49 @@ struct move_only
|
||||
}
|
||||
};
|
||||
|
||||
namespace std{
|
||||
namespace std {
|
||||
|
||||
template <> struct hash<move_only>
|
||||
{
|
||||
std::size_t operator()(move_only const& mo) const noexcept
|
||||
template <> struct hash<move_only>
|
||||
{
|
||||
return std::hash<int>()(mo.x_);
|
||||
std::size_t operator()(move_only const& mo) const noexcept
|
||||
{
|
||||
return std::hash<int>()(mo.x_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#ifndef BOOST_UNORDERED_NO_INIT_TYPE_TESTS
|
||||
|
||||
struct immovable
|
||||
{
|
||||
int x_ = -1;
|
||||
|
||||
immovable() = default;
|
||||
immovable(int x) : x_{x} {}
|
||||
immovable(immovable const&) = delete;
|
||||
immovable(immovable&&) = delete;
|
||||
|
||||
friend bool operator==(immovable const& lhs, immovable const& rhs)
|
||||
{
|
||||
return lhs.x_ == rhs.x_;
|
||||
}
|
||||
};
|
||||
|
||||
namespace std {
|
||||
|
||||
template <> struct hash<immovable>
|
||||
{
|
||||
std::size_t operator()(immovable const& im) const noexcept
|
||||
{
|
||||
return std::hash<int>()(im.x_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
#endif
|
||||
|
||||
struct raii_tracker
|
||||
{
|
||||
static unsigned move_constructs;
|
||||
@@ -68,15 +106,15 @@ struct raii_tracker
|
||||
}
|
||||
};
|
||||
|
||||
namespace std{
|
||||
namespace std {
|
||||
|
||||
template <> struct hash<raii_tracker>
|
||||
{
|
||||
std::size_t operator()(raii_tracker const& rt) const noexcept
|
||||
template <> struct hash<raii_tracker>
|
||||
{
|
||||
return std::hash<int>()(rt.x_);
|
||||
}
|
||||
};
|
||||
std::size_t operator()(raii_tracker const& rt) const noexcept
|
||||
{
|
||||
return std::hash<int>()(rt.x_);
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
@@ -90,9 +128,7 @@ static void test_move_only()
|
||||
boost::unordered_flat_map<move_only, int, std::hash<move_only> > map;
|
||||
|
||||
using init_type = decltype(map)::init_type;
|
||||
static_assert(
|
||||
std::is_same<decltype(std::make_pair(move_only(1), v)), init_type>::value,
|
||||
"");
|
||||
static_assert(std::is_same<std::pair<move_only, int>, init_type>::value, "");
|
||||
|
||||
map.insert(std::make_pair(move_only(1), v));
|
||||
map.insert({move_only(2), v});
|
||||
@@ -235,10 +271,167 @@ static void test_insert_hint_tracking()
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size());
|
||||
}
|
||||
|
||||
static void test_immovable()
|
||||
{
|
||||
#ifndef BOOST_UNORDERED_NO_INIT_TYPE_TESTS
|
||||
int const v = 128;
|
||||
|
||||
boost::unordered_node_map<immovable, int, std::hash<immovable> > map;
|
||||
|
||||
using init_type = decltype(map)::init_type;
|
||||
static_assert(std::is_same<std::pair<immovable, int>, init_type>::value, "");
|
||||
|
||||
map.emplace(1, v);
|
||||
map.emplace(2, v);
|
||||
|
||||
BOOST_TEST_EQ(map.size(), 2u);
|
||||
|
||||
map.rehash(1024);
|
||||
BOOST_TEST_GE(map.bucket_count(), 1024u);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void test_insert_node_tracking()
|
||||
{
|
||||
raii_tracker::reset_counts();
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
|
||||
|
||||
boost::unordered_node_map<raii_tracker, raii_tracker,
|
||||
std::hash<raii_tracker> >
|
||||
map;
|
||||
|
||||
{
|
||||
std::pair<raii_tracker, raii_tracker> value{1, 2};
|
||||
|
||||
map.insert(value);
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker, raii_tracker> value{2, 3};
|
||||
|
||||
map.insert(std::move(value));
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker const, raii_tracker> value{3, 4};
|
||||
|
||||
map.insert(value);
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker const, raii_tracker> value{4, 5};
|
||||
|
||||
map.insert(std::move(value));
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
|
||||
}
|
||||
|
||||
{
|
||||
map.insert(std::make_pair(5, 6));
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
|
||||
}
|
||||
|
||||
{
|
||||
map.insert({6, 7});
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(map.size(), 6u);
|
||||
|
||||
map.rehash(1024);
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
|
||||
}
|
||||
|
||||
static void test_insert_hint_node_tracking()
|
||||
{
|
||||
raii_tracker::reset_counts();
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
|
||||
|
||||
boost::unordered_node_map<raii_tracker, raii_tracker,
|
||||
std::hash<raii_tracker> >
|
||||
map;
|
||||
|
||||
{
|
||||
std::pair<raii_tracker, raii_tracker> value{1, 2};
|
||||
|
||||
map.insert(map.begin(), value);
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker, raii_tracker> value{2, 3};
|
||||
|
||||
map.insert(std::move(value));
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker const, raii_tracker> value{3, 4};
|
||||
|
||||
map.insert(map.begin(), value);
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker const, raii_tracker> value{4, 5};
|
||||
|
||||
map.insert(map.begin(), std::move(value));
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
|
||||
}
|
||||
|
||||
{
|
||||
map.insert(map.begin(), std::make_pair(5, 6));
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
|
||||
}
|
||||
|
||||
{
|
||||
map.insert(map.begin(), {6, 7});
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(map.size(), 6u);
|
||||
|
||||
map.rehash(1024);
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_move_only();
|
||||
test_insert_tracking();
|
||||
test_insert_hint_tracking();
|
||||
|
||||
test_immovable();
|
||||
test_insert_node_tracking();
|
||||
test_insert_hint_node_tracking();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -88,12 +88,11 @@ namespace insert_hint {
|
||||
}
|
||||
}
|
||||
#endif
|
||||
UNORDERED_AUTO_TEST (insert_hint_unique) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int> container;
|
||||
#else
|
||||
typedef boost::unordered_set<int> container;
|
||||
#endif
|
||||
|
||||
template <class X> static void insert_hint_unique(X*)
|
||||
{
|
||||
typedef X container;
|
||||
|
||||
container x;
|
||||
x.insert(x.cbegin(), 10);
|
||||
BOOST_TEST_EQ(x.size(), 1u);
|
||||
@@ -101,12 +100,10 @@ namespace insert_hint {
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_hint_unique_single) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int> container;
|
||||
#else
|
||||
typedef boost::unordered_set<int> container;
|
||||
#endif
|
||||
template <class X> static void insert_hint_unique_single(X*)
|
||||
{
|
||||
typedef X container;
|
||||
|
||||
container x;
|
||||
x.insert(10);
|
||||
|
||||
@@ -121,6 +118,18 @@ namespace insert_hint {
|
||||
BOOST_TEST_EQ(x.count(20), 1u);
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_set<int>* test_set;
|
||||
static boost::unordered_node_set<int>* test_node_set;
|
||||
|
||||
UNORDERED_TEST(insert_hint_unique, ((test_set)(test_node_set)))
|
||||
UNORDERED_TEST(insert_hint_unique_single, ((test_set)(test_node_set)))
|
||||
#else
|
||||
static boost::unordered_set<int>* test_set;
|
||||
UNORDERED_TEST(insert_hint_unique, ((test_set)))
|
||||
UNORDERED_TEST(insert_hint_unique_single, ((test_set)))
|
||||
#endif
|
||||
} // namespace insert_hint
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
+314
-151
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2010 Daniel James.
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// 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)
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include "../helpers/helpers.hpp"
|
||||
|
||||
#include <boost/move/core.hpp>
|
||||
#include <vector>
|
||||
|
||||
namespace insert_tests {
|
||||
@@ -219,7 +220,7 @@ namespace insert_tests {
|
||||
test::check_instances check_;
|
||||
|
||||
X x;
|
||||
const_iterator pos = x.begin();
|
||||
iterator pos = x.begin();
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
@@ -247,7 +248,7 @@ namespace insert_tests {
|
||||
test::check_instances check_;
|
||||
|
||||
X x;
|
||||
const_iterator pos = x.begin();
|
||||
iterator pos = x.begin();
|
||||
tracker_type tracker = test::create_ordered(x);
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
@@ -693,6 +694,69 @@ namespace insert_tests {
|
||||
BOOST_TEST_EQ(x.size(), 1000u);
|
||||
}
|
||||
|
||||
struct pointer_constructible
|
||||
{
|
||||
int x;
|
||||
|
||||
pointer_constructible(int x_) : x(x_) {}
|
||||
pointer_constructible(pointer_constructible const& p) : x(p.x) {}
|
||||
pointer_constructible(pointer_constructible* const&) : x(-1) {}
|
||||
pointer_constructible(BOOST_RV_REF(pointer_constructible*)) : x(-1) {}
|
||||
};
|
||||
|
||||
struct pointer_constructible_hash
|
||||
{
|
||||
typedef void is_transparent;
|
||||
|
||||
std::size_t operator()(pointer_constructible const& p) const
|
||||
{
|
||||
return boost::hash<int>()(p.x);
|
||||
}
|
||||
};
|
||||
|
||||
struct pointer_constructible_equal_to
|
||||
{
|
||||
typedef void is_transparent;
|
||||
|
||||
bool operator()(
|
||||
pointer_constructible const& lhs, pointer_constructible const& rhs) const
|
||||
{
|
||||
return lhs.x == rhs.x;
|
||||
}
|
||||
};
|
||||
|
||||
template <class X>
|
||||
static void set_tests2(X*)
|
||||
{
|
||||
X set, set2;
|
||||
|
||||
pointer_constructible pc(1337);
|
||||
pointer_constructible* const addr_pc = &pc;
|
||||
|
||||
set.insert(pc); // 1337
|
||||
set.insert(&pc); // -1
|
||||
set.insert(addr_pc); // -1
|
||||
|
||||
BOOST_TEST_EQ(set.size(), 2u);
|
||||
BOOST_TEST(set.find(pc) != set.end());
|
||||
BOOST_TEST(set.find(-1) != set.end());
|
||||
BOOST_TEST(set.find(-2) == set.end());
|
||||
|
||||
set2 = set;
|
||||
|
||||
BOOST_TEST_EQ(set2.size(), 2u);
|
||||
BOOST_TEST(set2.find(pc) != set2.end());
|
||||
BOOST_TEST(set2.find(-1) != set2.end());
|
||||
BOOST_TEST(set2.find(-2) == set2.end());
|
||||
|
||||
set.rehash(set.bucket_count() + 1);
|
||||
|
||||
BOOST_TEST_EQ(set.size(), 2u);
|
||||
BOOST_TEST(set.find(pc) != set.end());
|
||||
BOOST_TEST(set.find(-1) != set.end());
|
||||
BOOST_TEST(set.find(-2) == set.end());
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void try_emplace_tests(X*, test::random_generator generator)
|
||||
{
|
||||
@@ -892,45 +956,62 @@ namespace insert_tests {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_set_std_alloc;
|
||||
boost::unordered_node_set<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_node_set_std_alloc;
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
boost::unordered_node_set<test::movable, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
boost::unordered_flat_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_map;
|
||||
boost::unordered_node_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_node_map;
|
||||
|
||||
boost::unordered_flat_set<pointer_constructible, pointer_constructible_hash,
|
||||
pointer_constructible_equal_to, test::allocator1<pointer_constructible> >*
|
||||
test_pc_set;
|
||||
boost::unordered_node_set<pointer_constructible, pointer_constructible_hash,
|
||||
pointer_constructible_equal_to, test::allocator1<pointer_constructible> >*
|
||||
test_pc_node_set;
|
||||
|
||||
UNORDERED_TEST(unique_insert_tests1,
|
||||
((test_set_std_alloc)(test_set)(test_map))(
|
||||
((test_set_std_alloc)(test_node_set_std_alloc)
|
||||
(test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
insert_tests2, ((test_set)(test_map))(
|
||||
insert_tests2, ((test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(unique_emplace_tests1,
|
||||
((test_set_std_alloc)(test_set)(test_map))(
|
||||
((test_set_std_alloc)(test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(move_emplace_tests,
|
||||
((test_set_std_alloc)(test_set)(test_map))(
|
||||
((test_set_std_alloc)(test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(default_emplace_tests,
|
||||
((test_set_std_alloc)(test_set)(test_map))(
|
||||
((test_set_std_alloc)(test_set)(test_node_set)(test_map)(test_node_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(map_tests,
|
||||
((test_map))((default_generator)(generate_collisions)(limited_range)))
|
||||
((test_map)(test_node_map))
|
||||
((default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
map_tests2, ((test_map))((default_generator)(generate_collisions)))
|
||||
map_tests2, ((test_map)(test_node_map))((default_generator)(generate_collisions)))
|
||||
|
||||
UNORDERED_TEST(map_insert_range_test1,
|
||||
((test_map))((default_generator)(generate_collisions)(limited_range)))
|
||||
((test_map)(test_node_map))((default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(map_insert_range_test2,
|
||||
((test_map))((default_generator)(generate_collisions)(limited_range)))
|
||||
((test_map)(test_node_map))((default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(
|
||||
set_tests, ((test_set_std_alloc)(test_set))((default_generator)))
|
||||
set_tests, ((test_set_std_alloc)(test_set)(test_node_set))((default_generator)))
|
||||
|
||||
UNORDERED_TEST(set_tests2, ((test_pc_set)(test_pc_node_set)))
|
||||
#else
|
||||
boost::unordered_set<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_set_std_alloc;
|
||||
@@ -946,6 +1027,10 @@ namespace insert_tests {
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_multimap;
|
||||
|
||||
boost::unordered_set<pointer_constructible, pointer_constructible_hash,
|
||||
pointer_constructible_equal_to, test::allocator1<pointer_constructible> >*
|
||||
test_pc_set;
|
||||
|
||||
UNORDERED_TEST(unique_insert_tests1,
|
||||
((test_set_std_alloc)(test_set)(test_map))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
@@ -990,6 +1075,8 @@ namespace insert_tests {
|
||||
|
||||
UNORDERED_TEST(
|
||||
set_tests, ((test_set_std_alloc)(test_set)(test_multiset))((default_generator)))
|
||||
|
||||
UNORDERED_TEST(set_tests2, ((test_pc_set)))
|
||||
#endif
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
@@ -1009,23 +1096,19 @@ namespace insert_tests {
|
||||
}
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_initializer_list_set) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> set;
|
||||
#else
|
||||
boost::unordered_set<int> set;
|
||||
#endif
|
||||
template <template <class Key, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>, class Allocator = std::allocator<Key> >
|
||||
class Set>
|
||||
static void insert_initializer_list_set_impl()
|
||||
{
|
||||
Set<int> set;
|
||||
|
||||
set.insert({1, 2, 3, 1});
|
||||
BOOST_TEST_EQ(set.size(), 3u);
|
||||
BOOST_TEST(set.find(1) != set.end());
|
||||
BOOST_TEST(set.find(4) == set.end());
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<initialize_from_two_ints> set2;
|
||||
#else
|
||||
boost::unordered_set<initialize_from_two_ints> set2;
|
||||
#endif
|
||||
|
||||
Set<initialize_from_two_ints> set2;
|
||||
#if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 5))
|
||||
set2.insert({{1, 2}});
|
||||
#else
|
||||
@@ -1053,6 +1136,16 @@ namespace insert_tests {
|
||||
BOOST_TEST(set2.find({8, 7}) == set2.end());
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_initializer_list_set) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
insert_initializer_list_set_impl<boost::unordered_flat_set>();
|
||||
insert_initializer_list_set_impl<boost::unordered_node_set>();
|
||||
#else
|
||||
insert_initializer_list_set_impl<boost::unordered_set>();
|
||||
boost::unordered_set<int> set;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
#if !BOOST_WORKAROUND(BOOST_MSVC, == 1800)
|
||||
|
||||
@@ -1074,18 +1167,31 @@ namespace insert_tests {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_initializer_list_map) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<std::string, std::string> map;
|
||||
#else
|
||||
boost::unordered_map<std::string, std::string> map;
|
||||
#endif
|
||||
// map.insert({});
|
||||
template <class X> static void insert_initializer_list_map(X*)
|
||||
{
|
||||
X map;
|
||||
|
||||
BOOST_TEST(map.empty());
|
||||
map.insert({{"a", "b"}, {"a", "b"}, {"d", ""}});
|
||||
BOOST_TEST_EQ(map.size(), 2u);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_map<std::string, std::string>* test_str_map;
|
||||
static boost::unordered_node_map<std::string, std::string>* test_str_node_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_initializer_list_map,
|
||||
((test_str_map)(test_str_node_map)))
|
||||
// clang-format on
|
||||
#else
|
||||
static boost::unordered_map<std::string, std::string>* test_str_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(insert_initializer_list_map, ((test_str_map)))
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (insert_initializer_list_multimap) {
|
||||
boost::unordered_multimap<std::string, std::string> multimap;
|
||||
@@ -1124,65 +1230,72 @@ namespace insert_tests {
|
||||
}
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (map_emplace_test) {
|
||||
{
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >
|
||||
x;
|
||||
#else
|
||||
|
||||
boost::unordered_map<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >
|
||||
x;
|
||||
#endif
|
||||
|
||||
template <class X> static void map_emplace_test(X*)
|
||||
{
|
||||
X x;
|
||||
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
|
||||
x.emplace();
|
||||
BOOST_TEST(
|
||||
x.find(0) != x.end() && x.find(0)->second == overloaded_constructor());
|
||||
x.emplace();
|
||||
BOOST_TEST(
|
||||
x.find(0) != x.end() && x.find(0)->second == overloaded_constructor());
|
||||
#endif
|
||||
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(
|
||||
x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3));
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(
|
||||
x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3));
|
||||
|
||||
x.try_emplace(5);
|
||||
BOOST_TEST(
|
||||
x.find(5) != x.end() && x.find(5)->second == overloaded_constructor());
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
{
|
||||
boost::unordered_multimap<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
|
||||
x.emplace();
|
||||
BOOST_TEST(
|
||||
x.find(0) != x.end() && x.find(0)->second == overloaded_constructor());
|
||||
#endif
|
||||
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(
|
||||
x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3));
|
||||
}
|
||||
#endif
|
||||
x.try_emplace(5);
|
||||
BOOST_TEST(
|
||||
x.find(5) != x.end() && x.find(5)->second == overloaded_constructor());
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (set_emplace_test) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<overloaded_constructor> x;
|
||||
overloaded_constructor check;
|
||||
#else
|
||||
boost::unordered_set<overloaded_constructor> x;
|
||||
overloaded_constructor check;
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
template <class X> static void multimap_emplace_test(X*)
|
||||
{
|
||||
X x;
|
||||
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
|
||||
x.emplace();
|
||||
BOOST_TEST(
|
||||
x.find(0) != x.end() && x.find(0)->second == overloaded_constructor());
|
||||
#endif
|
||||
|
||||
x.emplace(2, 3);
|
||||
BOOST_TEST(
|
||||
x.find(2) != x.end() && x.find(2)->second == overloaded_constructor(3));
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_map<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >*
|
||||
test_oc_map;
|
||||
|
||||
static boost::unordered_node_map<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >*
|
||||
test_oc_node_map;
|
||||
|
||||
UNORDERED_TEST(map_emplace_test, ((test_oc_map)(test_oc_node_map)))
|
||||
#else
|
||||
static boost::unordered_map<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >*
|
||||
test_oc_map;
|
||||
|
||||
static boost::unordered_multimap<int, overloaded_constructor, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<int const, overloaded_constructor> > >*
|
||||
test_oc_multimap;
|
||||
|
||||
UNORDERED_TEST(map_emplace_test, ((test_oc_map)))
|
||||
UNORDERED_TEST(multimap_emplace_test, ((test_oc_multimap)))
|
||||
#endif
|
||||
|
||||
template <class X> static void set_emplace_test(X*)
|
||||
{
|
||||
X x;
|
||||
overloaded_constructor check;
|
||||
|
||||
#if !BOOST_UNORDERED_SUN_WORKAROUNDS1
|
||||
x.emplace();
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
@@ -1209,6 +1322,18 @@ namespace insert_tests {
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_set<overloaded_constructor>* test_oc_set;
|
||||
static boost::unordered_node_set<overloaded_constructor>* test_oc_node_set;
|
||||
|
||||
UNORDERED_TEST(set_emplace_test, ((test_oc_set)(test_oc_node_set)))
|
||||
#else
|
||||
static boost::unordered_set<overloaded_constructor>* test_oc_set;
|
||||
static boost::unordered_multiset<overloaded_constructor>* test_oc_multiset;
|
||||
|
||||
UNORDERED_TEST(set_emplace_test, ((test_oc_set)(test_oc_multiset)))
|
||||
#endif
|
||||
|
||||
struct derived_from_piecewise_construct_t
|
||||
: boost::unordered::piecewise_construct_t
|
||||
{
|
||||
@@ -1358,6 +1483,14 @@ namespace insert_tests {
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
|
||||
static boost::unordered_map<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>, std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >* test_pw_oc_map;
|
||||
|
||||
static boost::unordered_set<std::pair<overloaded_constructor,
|
||||
overloaded_constructor> >* test_pair_oc_set;
|
||||
|
||||
#define PIECEWISE_TEST_NAME boost_tuple_piecewise_tests
|
||||
#define PIECEWISE_NAMESPACE boost::unordered
|
||||
#define TUPLE_NAMESPACE boost
|
||||
@@ -1389,6 +1522,14 @@ namespace insert_tests {
|
||||
#if !defined(BOOST_NO_CXX11_HDR_TUPLE) && \
|
||||
BOOST_UNORDERED_HAVE_PIECEWISE_CONSTRUCT
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_set<std::pair<overloaded_constructor,
|
||||
overloaded_constructor> >* test_pair_oc_set;
|
||||
|
||||
static boost::unordered_node_set<std::pair<overloaded_constructor,
|
||||
overloaded_constructor> >* test_pair_oc_node_set;
|
||||
#endif
|
||||
|
||||
#define PIECEWISE_TEST_NAME std_piecewise_tests
|
||||
#define PIECEWISE_NAMESPACE std
|
||||
#define TUPLE_NAMESPACE std
|
||||
@@ -1402,27 +1543,17 @@ RUN_TESTS_QUIET()
|
||||
|
||||
#else // PIECEWISE_TEST_NAME
|
||||
|
||||
UNORDERED_AUTO_TEST (PIECEWISE_TEST_NAME) {
|
||||
#define MAP_PIECEWISE_TEST BOOST_PP_CAT(map_, PIECEWISE_TEST_NAME)
|
||||
#define SET_PIECEWISE_TEST BOOST_PP_CAT(set_, PIECEWISE_TEST_NAME)
|
||||
|
||||
template <class X>
|
||||
static void MAP_PIECEWISE_TEST(X*)
|
||||
{
|
||||
#if EMULATING_PIECEWISE_CONSTRUCTION
|
||||
test::detail::disable_construction_tracking _scoped;
|
||||
#endif
|
||||
|
||||
{
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
boost::unordered_flat_map<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<
|
||||
std::pair<overloaded_constructor const, overloaded_constructor> > >
|
||||
x;
|
||||
#else
|
||||
boost::unordered_map<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<
|
||||
std::pair<overloaded_constructor const, overloaded_constructor> > >
|
||||
x;
|
||||
#endif
|
||||
X x;
|
||||
|
||||
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
|
||||
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
|
||||
@@ -1466,70 +1597,102 @@ UNORDERED_AUTO_TEST (PIECEWISE_TEST_NAME) {
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
}
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
|
||||
template <class X>
|
||||
static void SET_PIECEWISE_TEST(X*)
|
||||
{
|
||||
boost::unordered_multimap<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<
|
||||
std::pair<overloaded_constructor const, overloaded_constructor> > >
|
||||
x;
|
||||
#if EMULATING_PIECEWISE_CONSTRUCTION
|
||||
test::detail::disable_construction_tracking _scoped;
|
||||
#endif
|
||||
|
||||
X x;
|
||||
std::pair<overloaded_constructor, overloaded_constructor> check;
|
||||
|
||||
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
|
||||
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second == overloaded_constructor());
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
|
||||
x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1),
|
||||
TUPLE_NAMESPACE::make_tuple());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second == overloaded_constructor());
|
||||
|
||||
x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3),
|
||||
TUPLE_NAMESPACE::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(
|
||||
d, TUPLE_NAMESPACE::make_tuple(9, 3, 1), TUPLE_NAMESPACE::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
x.clear();
|
||||
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
|
||||
TUPLE_NAMESPACE::make_tuple(1), TUPLE_NAMESPACE::make_tuple(2, 3));
|
||||
check =
|
||||
std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (BOOST_PP_CAT(PIECEWISE_TEST_NAME, 2)) {
|
||||
#if defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
static boost::unordered_flat_map<overloaded_constructor,
|
||||
overloaded_constructor, boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >* test_pw_oc_map;
|
||||
|
||||
static boost::unordered_node_map<overloaded_constructor,
|
||||
overloaded_constructor, boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<std::pair<overloaded_constructor const,
|
||||
overloaded_constructor> > >* test_pw_oc_node_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(MAP_PIECEWISE_TEST, ((test_pw_oc_map)(test_pw_oc_node_map)))
|
||||
// clang-format on
|
||||
#else
|
||||
// clang-format off
|
||||
UNORDERED_TEST(MAP_PIECEWISE_TEST, ((test_pw_oc_map)))
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
UNORDERED_AUTO_TEST (BOOST_PP_CAT(multimap_, PIECEWISE_TEST_NAME)) {
|
||||
{
|
||||
#if EMULATING_PIECEWISE_CONSTRUCTION
|
||||
test::detail::disable_construction_tracking _scoped;
|
||||
test::detail::disable_construction_tracking _scoped;
|
||||
#endif
|
||||
boost::unordered_multimap<overloaded_constructor, overloaded_constructor,
|
||||
boost::hash<overloaded_constructor>,
|
||||
std::equal_to<overloaded_constructor>,
|
||||
test::allocator1<
|
||||
std::pair<overloaded_constructor const, overloaded_constructor> > >
|
||||
x;
|
||||
|
||||
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
|
||||
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor()) != x.end() &&
|
||||
x.find(overloaded_constructor())->second == overloaded_constructor());
|
||||
|
||||
x.emplace(convertible_to_piecewise(), TUPLE_NAMESPACE::make_tuple(1),
|
||||
TUPLE_NAMESPACE::make_tuple());
|
||||
BOOST_TEST(
|
||||
x.find(overloaded_constructor(1)) != x.end() &&
|
||||
x.find(overloaded_constructor(1))->second == overloaded_constructor());
|
||||
|
||||
x.emplace(piecewise_rvalue(), TUPLE_NAMESPACE::make_tuple(2, 3),
|
||||
TUPLE_NAMESPACE::make_tuple(4, 5, 6));
|
||||
BOOST_TEST(x.find(overloaded_constructor(2, 3)) != x.end() &&
|
||||
x.find(overloaded_constructor(2, 3))->second ==
|
||||
overloaded_constructor(4, 5, 6));
|
||||
|
||||
derived_from_piecewise_construct_t d;
|
||||
x.emplace(d, TUPLE_NAMESPACE::make_tuple(9, 3, 1),
|
||||
TUPLE_NAMESPACE::make_tuple(10));
|
||||
BOOST_TEST(x.find(overloaded_constructor(9, 3, 1)) != x.end() &&
|
||||
x.find(overloaded_constructor(9, 3, 1))->second ==
|
||||
overloaded_constructor(10));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<
|
||||
std::pair<overloaded_constructor, overloaded_constructor> >
|
||||
x;
|
||||
// clang-format off
|
||||
UNORDERED_TEST(SET_PIECEWISE_TEST,
|
||||
((test_pair_oc_set)(test_pair_oc_node_set)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<
|
||||
std::pair<overloaded_constructor, overloaded_constructor> >
|
||||
x;
|
||||
// clang-format off
|
||||
UNORDERED_TEST(SET_PIECEWISE_TEST, ((test_pair_oc_set)))
|
||||
// clang-format on
|
||||
#endif
|
||||
std::pair<overloaded_constructor, overloaded_constructor> check;
|
||||
|
||||
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
|
||||
TUPLE_NAMESPACE::make_tuple(), TUPLE_NAMESPACE::make_tuple());
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
|
||||
x.clear();
|
||||
x.emplace(PIECEWISE_NAMESPACE::piecewise_construct,
|
||||
TUPLE_NAMESPACE::make_tuple(1), TUPLE_NAMESPACE::make_tuple(2, 3));
|
||||
check =
|
||||
std::make_pair(overloaded_constructor(1), overloaded_constructor(2, 3));
|
||||
BOOST_TEST(x.find(check) != x.end() && *x.find(check) == check);
|
||||
}
|
||||
|
||||
#undef PIECEWISE_TEST_NAME
|
||||
#undef PIECEWISE_NAMESPACE
|
||||
|
||||
@@ -1,20 +1,23 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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/unordered.hpp"
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
void foo(boost::unordered_flat_set<int>&, boost::unordered_flat_map<int, int>&);
|
||||
void foo(boost::unordered_flat_set<int>&, boost::unordered_flat_map<int, int>&,
|
||||
boost::unordered_node_set<int>&, boost::unordered_node_map<int, int>&);
|
||||
|
||||
int main()
|
||||
{
|
||||
boost::unordered_flat_set<int> x1;
|
||||
boost::unordered_flat_map<int, int> x2;
|
||||
boost::unordered_node_set<int> x3;
|
||||
boost::unordered_node_map<int, int> x4;
|
||||
|
||||
foo(x1, x2);
|
||||
foo(x1, x2, x3, x4);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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/unordered.hpp"
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
void foo(
|
||||
boost::unordered_flat_set<int>& x1, boost::unordered_flat_map<int, int>& x2)
|
||||
void foo(boost::unordered_flat_set<int>& x1,
|
||||
boost::unordered_flat_map<int, int>& x2, boost::unordered_node_set<int>& x3,
|
||||
boost::unordered_node_map<int, int>& x4)
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_CODEGEARC, BOOST_TESTED_AT(0x0613))
|
||||
struct dummy
|
||||
@@ -20,6 +21,8 @@ void foo(
|
||||
|
||||
x1.insert(1);
|
||||
x2[2] = 2;
|
||||
x3.insert(3);
|
||||
x4.insert(std::make_pair(4, 5));
|
||||
}
|
||||
#else
|
||||
void foo(boost::unordered_set<int>& x1, boost::unordered_map<int, int>& x2,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -86,12 +86,17 @@ namespace load_factor_tests {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int>* int_set_ptr;
|
||||
boost::unordered_flat_map<int, int>* int_map_ptr;
|
||||
boost::unordered_node_set<int>* int_node_set_ptr;
|
||||
boost::unordered_node_map<int, int>* int_node_map_ptr;
|
||||
|
||||
UNORDERED_TEST(set_load_factor_tests, ((int_set_ptr)(int_map_ptr)))
|
||||
// clang-format off
|
||||
UNORDERED_TEST(set_load_factor_tests,
|
||||
((int_set_ptr)(int_map_ptr)(int_node_set_ptr)(int_node_map_ptr)))
|
||||
|
||||
UNORDERED_TEST(load_factor_insert_tests,
|
||||
((int_set_ptr)(int_map_ptr))(
|
||||
((int_set_ptr)(int_map_ptr)(int_node_set_ptr)(int_node_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<int>* int_set_ptr;
|
||||
boost::unordered_multiset<int>* int_multiset_ptr;
|
||||
|
||||
@@ -69,9 +69,24 @@ boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_map_tracking;
|
||||
|
||||
boost::unordered_node_set<int>* int_node_set_ptr;
|
||||
boost::unordered_node_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_node_map_ptr;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set_tracking;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_node_map_tracking;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(max_load_tests,
|
||||
((int_set_ptr)(test_map_ptr)(test_set_tracking)(test_map_tracking))(
|
||||
((int_set_ptr)(test_map_ptr)(test_set_tracking)(test_map_tracking)
|
||||
(int_node_set_ptr)(test_node_map_ptr)
|
||||
(test_node_set_tracking)(test_node_map_tracking))(
|
||||
(sequential)))
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -16,14 +16,9 @@
|
||||
|
||||
namespace merge_tests {
|
||||
|
||||
UNORDERED_AUTO_TEST (merge_set) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> x;
|
||||
boost::unordered_flat_set<int> y;
|
||||
#else
|
||||
boost::unordered_set<int> x;
|
||||
boost::unordered_set<int> y;
|
||||
#endif
|
||||
template <class X> static void merge_set(X*)
|
||||
{
|
||||
X x, y;
|
||||
|
||||
x.merge(y);
|
||||
BOOST_TEST(x.empty());
|
||||
@@ -237,22 +232,23 @@ namespace merge_tests {
|
||||
using test::generate_collisions;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int>* int_set;
|
||||
|
||||
boost::unordered_flat_set<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_set_std_alloc;
|
||||
|
||||
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set;
|
||||
|
||||
|
||||
boost::unordered_flat_map<test::movable, test::movable, test::hash, test::equal_to,
|
||||
test::allocator2<test::movable> >* test_map;
|
||||
boost::unordered_flat_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(merge_set, ((int_set)))
|
||||
|
||||
UNORDERED_TEST(merge_empty_test,
|
||||
((test_set_std_alloc))
|
||||
((test_set_std_alloc))
|
||||
@@ -308,7 +304,82 @@ UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
// clang-format on
|
||||
|
||||
boost::unordered_node_set<int>* int_node_set;
|
||||
|
||||
boost::unordered_node_set<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_node_set_std_alloc;
|
||||
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_node_map_std_alloc;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
|
||||
boost::unordered_node_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_node_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(merge_set, ((int_node_set)))
|
||||
|
||||
UNORDERED_TEST(merge_empty_test,
|
||||
((test_node_set_std_alloc))
|
||||
((test_node_set_std_alloc))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_empty_test,
|
||||
((test_node_map_std_alloc))
|
||||
((test_node_map_std_alloc))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_empty_test,
|
||||
((test_node_set))
|
||||
((test_node_set))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_empty_test,
|
||||
((test_node_map))
|
||||
((test_node_map))
|
||||
((default_generator)(generate_collisions)))
|
||||
|
||||
UNORDERED_TEST(merge_into_empty_test,
|
||||
((test_node_set_std_alloc))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_empty_test,
|
||||
((test_node_map_std_alloc))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_empty_test,
|
||||
((test_node_set))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_empty_test,
|
||||
((test_node_map))
|
||||
((default_generator)(generate_collisions)))
|
||||
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_node_set_std_alloc))
|
||||
((test_node_set_std_alloc))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_node_map_std_alloc))
|
||||
((test_node_map_std_alloc))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_node_set))
|
||||
((test_node_set))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
((test_node_map))
|
||||
((test_node_map))
|
||||
((0)(1)(2))
|
||||
((0)(1)(2))
|
||||
((default_generator)(generate_collisions)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<int>* int_set;
|
||||
|
||||
boost::unordered_set<test::movable, test::hash, test::equal_to,
|
||||
std::allocator<test::movable> >* test_set_std_alloc;
|
||||
boost::unordered_multiset<test::movable, test::hash, test::equal_to,
|
||||
@@ -330,6 +401,8 @@ UNORDERED_TEST(merge_into_unique_keys_test,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_multimap;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(merge_set, ((int_set)))
|
||||
|
||||
UNORDERED_TEST(merge_empty_test,
|
||||
((test_set_std_alloc)(test_multiset_std_alloc))
|
||||
((test_set_std_alloc)(test_multiset_std_alloc))
|
||||
@@ -412,6 +485,6 @@ UNORDERED_TEST(merge_into_equiv_keys_test,
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
}
|
||||
} // namespace merge_tests
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -408,18 +408,68 @@ namespace move_tests {
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_map_no_prop_move;
|
||||
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
std::allocator<std::pair<test::object const, test::object> > >*
|
||||
test_node_map_std_alloc;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_node_set;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_node_map;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||
test_node_set_prop_move;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::propagate_move> >* test_node_map_prop_move;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||
test_node_set_no_prop_move;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_node_map_no_prop_move;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(move_construct_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))(
|
||||
((test_map_std_alloc)(test_set)(test_map)
|
||||
(test_set_prop_move)(test_map_prop_move)
|
||||
(test_set_no_prop_move)(test_map_no_prop_move)
|
||||
(test_node_map_std_alloc)(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_move)(test_node_map_prop_move)
|
||||
(test_node_set_no_prop_move)(test_node_map_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(move_assign_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))(
|
||||
((test_map_std_alloc)(test_set)(test_map)
|
||||
(test_set_prop_move)(test_map_prop_move)
|
||||
(test_set_no_prop_move)(test_map_no_prop_move)
|
||||
(test_node_map_std_alloc)(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_move)(test_node_map_prop_move)
|
||||
(test_node_set_no_prop_move)(test_node_map_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(move_construct_tests2,
|
||||
((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))(
|
||||
((test_set)(test_map)
|
||||
(test_set_prop_move)(test_map_prop_move)
|
||||
(test_set_no_prop_move)(test_map_no_prop_move)
|
||||
(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_move)(test_node_map_prop_move)
|
||||
(test_node_set_no_prop_move)(test_node_map_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(move_assign_tests2,
|
||||
((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))(
|
||||
((test_set)(test_map)
|
||||
(test_set_prop_move)(test_map_prop_move)
|
||||
(test_set_no_prop_move)(test_map_no_prop_move)
|
||||
(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_move)(test_node_map_prop_move)
|
||||
(test_node_set_no_prop_move)(test_node_map_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<std::pair<test::object const, test::object> > >*
|
||||
|
||||
@@ -0,0 +1,107 @@
|
||||
// Copyright 2022 Christian Mazakas
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#include <boost/unordered/detail/narrow_cast.hpp>
|
||||
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
#include <boost/cstdint.hpp>
|
||||
|
||||
// want to prove that for the wider type, the higher bits of the value
|
||||
// represenation don't affect the results of the narrowing, which in this case
|
||||
// is masking out the high bits when comapred to the narrow type
|
||||
|
||||
static void signed_integral_narrowing()
|
||||
{
|
||||
// test positive range, fits
|
||||
// [0, 127]
|
||||
for (boost::int32_t i = 0x00; i < 0x80; ++i) {
|
||||
boost::int8_t k = (boost::int8_t)i;
|
||||
BOOST_TEST_GE(k, 0);
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(i), k);
|
||||
}
|
||||
|
||||
// test positive range, doesn't fit
|
||||
// [0xff00, 0xff7f]
|
||||
for (boost::int32_t i = 0x00; i < 0x80; ++i) {
|
||||
boost::int32_t j = i + 0xff00;
|
||||
boost::int8_t k = (boost::int8_t)i;
|
||||
BOOST_TEST_GE(k, 0);
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(j), k);
|
||||
}
|
||||
|
||||
// test negative range, fits
|
||||
// [-128, -1]
|
||||
for (boost::int32_t i = 0x00; i < 0x80; ++i) {
|
||||
boost::int32_t j = i + (boost::int32_t)0xffffff80;
|
||||
boost::int8_t k = (boost::int8_t)j;
|
||||
BOOST_TEST_LT(j, 0);
|
||||
BOOST_TEST_LT(k, 0);
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(j), k);
|
||||
}
|
||||
|
||||
// test negative range, doesn't fit
|
||||
for (boost::int32_t i = 0x00; i < 0x80; ++i) {
|
||||
boost::int32_t j = i + (boost::int32_t)0x80000000;
|
||||
boost::int8_t k = (boost::int8_t)(i);
|
||||
BOOST_TEST_LT(j, 0);
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(j), k);
|
||||
}
|
||||
|
||||
for (boost::int32_t i = 0x00; i < 0x100; ++i) {
|
||||
boost::int32_t j = (boost::int32_t)0x80ff0000 + i;
|
||||
BOOST_TEST_LT(j, 0);
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(j),
|
||||
(boost::int8_t)i);
|
||||
}
|
||||
|
||||
// test special values
|
||||
{
|
||||
boost::int32_t x = 0xff;
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(x), -1);
|
||||
}
|
||||
|
||||
{
|
||||
boost::int32_t x = (boost::int32_t)0xffffff00;
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(x),
|
||||
(boost::int8_t)0x00);
|
||||
}
|
||||
|
||||
{
|
||||
boost::int32_t x = (boost::int32_t)0xffffff7f;
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(x),
|
||||
(boost::int8_t)0x7f);
|
||||
}
|
||||
|
||||
{
|
||||
boost::int32_t x = (boost::int32_t)0xffffffff;
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::int8_t>(x),
|
||||
(boost::int8_t)-1);
|
||||
}
|
||||
}
|
||||
|
||||
static void unsigned_integral_narrowing()
|
||||
{
|
||||
// test range: [0x00, 0xff]
|
||||
for (boost::uint32_t i = 0x00; i < 0x100; ++i) {
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::uint8_t>(i),
|
||||
(boost::uint8_t)(i & 0xff));
|
||||
}
|
||||
|
||||
// test range: [0xffffff00, 0xffffffff]
|
||||
boost::uint32_t i = 0xffffff00;
|
||||
for (; i < 0xffffffff; ++i) {
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::uint8_t>(i),
|
||||
(boost::uint8_t)(i & 0xff));
|
||||
}
|
||||
BOOST_TEST_EQ(boost::unordered::detail::narrow_cast<boost::uint8_t>(i),
|
||||
(boost::uint8_t)(i & 0xff));
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
signed_integral_narrowing();
|
||||
unsigned_integral_narrowing();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2023 Christian Mazakas
|
||||
// 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/postfix.hpp"
|
||||
#include "../helpers/prefix.hpp"
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered_set.hpp>
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
@@ -17,15 +17,19 @@
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
UNORDERED_AUTO_TEST (example1) {
|
||||
typedef boost::unordered_map<int, std::string>::insert_return_type
|
||||
insert_return_type;
|
||||
template <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 Map>
|
||||
static void example1()
|
||||
{
|
||||
typedef typename Map<int, std::string>::insert_return_type insert_return_type;
|
||||
|
||||
boost::unordered_map<int, std::string> src;
|
||||
Map<int, std::string> src;
|
||||
src.emplace(1, "one");
|
||||
src.emplace(2, "two");
|
||||
src.emplace(3, "buckle my shoe");
|
||||
boost::unordered_map<int, std::string> dst;
|
||||
Map<int, std::string> dst;
|
||||
dst.emplace(3, "three");
|
||||
|
||||
dst.insert(src.extract(src.find(1)));
|
||||
@@ -42,12 +46,16 @@ UNORDERED_AUTO_TEST (example1) {
|
||||
BOOST_TEST(r.node.mapped() == "buckle my shoe");
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (example2) {
|
||||
boost::unordered_set<int> src;
|
||||
template <template <class Key, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>, class Allocator = std::allocator<Key> >
|
||||
class Set>
|
||||
static void example2()
|
||||
{
|
||||
Set<int> src;
|
||||
src.insert(1);
|
||||
src.insert(3);
|
||||
src.insert(5);
|
||||
boost::unordered_set<int> dst;
|
||||
Set<int> dst;
|
||||
dst.insert(2);
|
||||
dst.insert(4);
|
||||
dst.insert(5);
|
||||
@@ -57,14 +65,18 @@ UNORDERED_AUTO_TEST (example2) {
|
||||
// dst == {1, 2, 3, 4, 5}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (example3) {
|
||||
typedef boost::unordered_set<int>::iterator iterator;
|
||||
template <template <class Key, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>, class Allocator = std::allocator<Key> >
|
||||
class Set>
|
||||
static void example3()
|
||||
{
|
||||
typedef typename Set<int>::iterator iterator;
|
||||
|
||||
boost::unordered_set<int> src;
|
||||
Set<int> src;
|
||||
src.insert(1);
|
||||
src.insert(3);
|
||||
src.insert(5);
|
||||
boost::unordered_set<int> dst;
|
||||
Set<int> dst;
|
||||
dst.insert(2);
|
||||
dst.insert(4);
|
||||
dst.insert(5);
|
||||
@@ -88,16 +100,24 @@ UNORDERED_AUTO_TEST (example3) {
|
||||
BOOST_TEST(it == dst2.end());
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (failed_insertion_with_hint) {
|
||||
template <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 Map,
|
||||
template <class Key, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>, class Allocator = std::allocator<Key> >
|
||||
class Set>
|
||||
static void failed_insertion_with_hint()
|
||||
{
|
||||
{
|
||||
boost::unordered_set<int> src;
|
||||
boost::unordered_set<int> dst;
|
||||
Set<int> src;
|
||||
Set<int> dst;
|
||||
src.emplace(10);
|
||||
src.emplace(20);
|
||||
dst.emplace(10);
|
||||
dst.emplace(20);
|
||||
|
||||
boost::unordered_set<int>::node_type nh = src.extract(10);
|
||||
typename Set<int>::node_type nh = src.extract(10);
|
||||
|
||||
BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10));
|
||||
BOOST_TEST(nh);
|
||||
@@ -116,14 +136,14 @@ UNORDERED_AUTO_TEST (failed_insertion_with_hint) {
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_map<int, int> src;
|
||||
boost::unordered_map<int, int> dst;
|
||||
Map<int, int> src;
|
||||
Map<int, int> dst;
|
||||
src.emplace(10, 30);
|
||||
src.emplace(20, 5);
|
||||
dst.emplace(10, 20);
|
||||
dst.emplace(20, 2);
|
||||
|
||||
boost::unordered_map<int, int>::node_type nh = src.extract(10);
|
||||
typename Map<int, int>::node_type nh = src.extract(10);
|
||||
BOOST_TEST(dst.insert(dst.find(10), boost::move(nh)) == dst.find(10));
|
||||
BOOST_TEST(nh);
|
||||
BOOST_TEST(!nh.empty());
|
||||
@@ -231,20 +251,38 @@ template <typename Container> void node_handle_tests_impl(Container& c)
|
||||
BOOST_TEST(!n4);
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (node_handle_tests) {
|
||||
boost::unordered_set<int> x1;
|
||||
template <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 Map,
|
||||
template <class Key, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>, class Allocator = std::allocator<Key> >
|
||||
class Set>
|
||||
static void node_handle_tests()
|
||||
{
|
||||
Set<int> x1;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
node_handle_tests_impl(x1);
|
||||
|
||||
boost::unordered_map<int, std::string> x2;
|
||||
Map<int, std::string> x2;
|
||||
x2.emplace(10, "ten");
|
||||
x2.emplace(-23, "twenty");
|
||||
x2.emplace(-76, "thirty");
|
||||
node_handle_tests_impl(x2);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
|
||||
template <class X> typename X::iterator insert_empty_node(X& x)
|
||||
{
|
||||
typedef typename X::node_type node_type;
|
||||
return x.insert(node_type()).position;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
typename boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>::iterator
|
||||
insert_empty_node(boost::unordered_map<Key, T, Hash, KeyEqual, Allocator>& c)
|
||||
@@ -288,8 +326,10 @@ insert_empty_node(boost::unordered_multiset<T, Hash, KeyEqual, Allocator>& c)
|
||||
return c.insert(node_type());
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
void insert_node_handle_unique(Container1& c1, Container2& c2)
|
||||
static void insert_node_handle_unique(Container1& c1, Container2& c2)
|
||||
{
|
||||
typedef typename Container1::node_type node_type;
|
||||
typedef typename Container1::value_type value_type;
|
||||
@@ -330,7 +370,7 @@ void insert_node_handle_unique(Container1& c1, Container2& c2)
|
||||
}
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
void insert_node_handle_unique2(Container1& c1, Container2& c2)
|
||||
static void insert_node_handle_unique2(Container1& c1, Container2& c2)
|
||||
{
|
||||
typedef typename Container1::node_type node_type;
|
||||
typedef typename Container1::value_type value_type;
|
||||
@@ -362,6 +402,130 @@ void insert_node_handle_unique2(Container1& c1, Container2& c2)
|
||||
}
|
||||
}
|
||||
|
||||
struct hash_thing
|
||||
{
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
return static_cast<std::size_t>(x * 13 + 5);
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
|
||||
UNORDERED_AUTO_TEST (examples) {
|
||||
example1<boost::unordered_node_map>();
|
||||
example2<boost::unordered_node_set>();
|
||||
example3<boost::unordered_node_set>();
|
||||
failed_insertion_with_hint<boost::unordered_node_map,
|
||||
boost::unordered_node_set>();
|
||||
node_handle_tests<boost::unordered_node_map, boost::unordered_node_set>();
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_node_handle_unique_tests) {
|
||||
{
|
||||
boost::unordered_node_set<int> x1;
|
||||
boost::unordered_node_set<int> x2;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
x2.emplace(140);
|
||||
insert_node_handle_unique(x1, x2);
|
||||
BOOST_TEST(x2.size() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_set<int> x1;
|
||||
boost::unordered_node_set<int> x2;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
x2.emplace(140);
|
||||
insert_node_handle_unique(x1, x2);
|
||||
BOOST_TEST(x2.size() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_map<int, int, hash_thing> x1;
|
||||
boost::unordered_node_map<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_unique(x1, x2);
|
||||
BOOST_TEST(x2.size() == 4);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_map<int, int, hash_thing> x1;
|
||||
boost::unordered_node_map<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_unique(x1, x2);
|
||||
BOOST_TEST(x2.size() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_node_handle_unique_tests2) {
|
||||
{
|
||||
boost::unordered_node_set<int> x1;
|
||||
boost::unordered_node_set<int> x2;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
x2.emplace(140);
|
||||
insert_node_handle_unique2(x1, x2);
|
||||
BOOST_TEST(x2.size() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_set<int> x1;
|
||||
boost::unordered_node_set<int> x2;
|
||||
x1.emplace(100);
|
||||
x1.emplace(140);
|
||||
x1.emplace(-55);
|
||||
x2.emplace(140);
|
||||
insert_node_handle_unique2(x1, x2);
|
||||
BOOST_TEST(x2.size() == 3);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_map<int, int, hash_thing> x1;
|
||||
boost::unordered_node_map<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_unique2(x1, x2);
|
||||
BOOST_TEST(x2.size() == 4);
|
||||
}
|
||||
|
||||
{
|
||||
boost::unordered_node_map<int, int, hash_thing> x1;
|
||||
boost::unordered_node_map<int, int> x2;
|
||||
x1.emplace(67, 50);
|
||||
x1.emplace(23, 45);
|
||||
x1.emplace(18, 19);
|
||||
x2.emplace(23, 50);
|
||||
x2.emplace(12, 49);
|
||||
insert_node_handle_unique2(x1, x2);
|
||||
BOOST_TEST(x2.size() == 4);
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
UNORDERED_AUTO_TEST (examples) {
|
||||
example1<boost::unordered_map>();
|
||||
example2<boost::unordered_set>();
|
||||
example3<boost::unordered_set>();
|
||||
failed_insertion_with_hint<boost::unordered_map, boost::unordered_set>();
|
||||
node_handle_tests<boost::unordered_map, boost::unordered_set>();
|
||||
}
|
||||
|
||||
template <typename Container1, typename Container2>
|
||||
void insert_node_handle_equiv(Container1& c1, Container2& c2)
|
||||
{
|
||||
@@ -389,14 +553,6 @@ void insert_node_handle_equiv(Container1& c1, Container2& c2)
|
||||
}
|
||||
}
|
||||
|
||||
struct hash_thing
|
||||
{
|
||||
std::size_t operator()(int x) const
|
||||
{
|
||||
return static_cast<std::size_t>(x * 13 + 5);
|
||||
}
|
||||
};
|
||||
|
||||
UNORDERED_AUTO_TEST (insert_node_handle_unique_tests) {
|
||||
{
|
||||
boost::unordered_set<int> x1;
|
||||
@@ -547,4 +703,6 @@ UNORDERED_AUTO_TEST (insert_node_handle_unique_tests2) {
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -6,8 +6,8 @@
|
||||
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/fwd.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
@@ -203,6 +203,10 @@ namespace noexcept_tests {
|
||||
boost::unordered_flat_set<int> >::value));
|
||||
BOOST_TEST((boost::is_nothrow_move_constructible<
|
||||
boost::unordered_flat_map<int, int> >::value));
|
||||
BOOST_TEST((boost::is_nothrow_move_constructible<
|
||||
boost::unordered_node_set<int> >::value));
|
||||
BOOST_TEST((boost::is_nothrow_move_constructible<
|
||||
boost::unordered_node_map<int, int> >::value));
|
||||
#else
|
||||
BOOST_TEST((boost::is_nothrow_move_constructible<
|
||||
boost::unordered_set<int> >::value));
|
||||
@@ -222,6 +226,13 @@ namespace noexcept_tests {
|
||||
BOOST_TEST(
|
||||
(!boost::is_nothrow_move_constructible<boost::unordered_flat_set<int,
|
||||
boost::hash<int>, equal_to_possible_exception> >::value));
|
||||
|
||||
BOOST_TEST(
|
||||
(!boost::is_nothrow_move_constructible<
|
||||
boost::unordered_node_set<int, hash_possible_exception> >::value));
|
||||
BOOST_TEST(
|
||||
(!boost::is_nothrow_move_constructible<boost::unordered_node_set<int,
|
||||
boost::hash<int>, equal_to_possible_exception> >::value));
|
||||
#else
|
||||
BOOST_TEST((!boost::is_nothrow_move_constructible<
|
||||
boost::unordered_set<int, hash_possible_exception> >::value));
|
||||
@@ -231,31 +242,22 @@ namespace noexcept_tests {
|
||||
#endif
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test_nothrow_move_when_noexcept) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int, hash_nothrow_move_construct,
|
||||
equal_to_nothrow_move_construct>
|
||||
throwing_set;
|
||||
#else
|
||||
typedef boost::unordered_set<int, hash_nothrow_move_construct,
|
||||
equal_to_nothrow_move_construct>
|
||||
throwing_set;
|
||||
#endif
|
||||
|
||||
template <class X> static void test_nothrow_move_when_noexcept(X*)
|
||||
{
|
||||
if (have_is_nothrow_move) {
|
||||
BOOST_TEST(boost::is_nothrow_move_constructible<throwing_set>::value);
|
||||
BOOST_TEST(boost::is_nothrow_move_constructible<X>::value);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
|
||||
throwing_set x1;
|
||||
X x1;
|
||||
x1.insert(10);
|
||||
x1.insert(50);
|
||||
|
||||
try {
|
||||
throwing_test_exception = true;
|
||||
|
||||
throwing_set x2 = boost::move(x1);
|
||||
X x2 = boost::move(x1);
|
||||
BOOST_TEST(x2.size() == 2);
|
||||
BOOST_TEST(*x2.begin() == 10 || *x2.begin() == 50);
|
||||
BOOST_TEST(have_is_nothrow_move);
|
||||
@@ -327,24 +329,16 @@ namespace noexcept_tests {
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (test_nothrow_swap_when_noexcept) {
|
||||
#if BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int, hash_nothrow_swap,
|
||||
equal_to_nothrow_swap>
|
||||
throwing_set;
|
||||
#else
|
||||
typedef boost::unordered_set<int, hash_nothrow_swap, equal_to_nothrow_swap>
|
||||
throwing_set;
|
||||
#endif
|
||||
|
||||
template <class X> static void test_nothrow_swap_when_noexcept(X*)
|
||||
{
|
||||
if (have_is_nothrow_swap) {
|
||||
BOOST_TEST(boost::is_nothrow_swappable<throwing_set>::value);
|
||||
BOOST_TEST(boost::is_nothrow_swappable<X>::value);
|
||||
}
|
||||
|
||||
throwing_test_exception = false;
|
||||
|
||||
throwing_set x1;
|
||||
throwing_set x2;
|
||||
X x1;
|
||||
X x2;
|
||||
x1.insert(10);
|
||||
x1.insert(50);
|
||||
for (int i = 0; i < 100; ++i) {
|
||||
@@ -365,7 +359,7 @@ namespace noexcept_tests {
|
||||
|
||||
throwing_test_exception = false;
|
||||
}
|
||||
}
|
||||
} // namespace noexcept_tests
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop)
|
||||
@@ -401,6 +395,7 @@ template <class T> class allocator2
|
||||
{
|
||||
BOOST_COPYABLE_AND_MOVABLE(allocator2)
|
||||
allocator2 operator=(BOOST_COPY_ASSIGN_REF(allocator2));
|
||||
|
||||
public:
|
||||
typedef T value_type;
|
||||
typedef boost::true_type propagate_on_container_move_assignment;
|
||||
@@ -431,23 +426,53 @@ UNORDERED_AUTO_TEST (prelim_allocator_checks) {
|
||||
|
||||
BOOST_TEST(boost::allocator_is_always_equal<allocator2<int> >::type::value);
|
||||
BOOST_TEST(boost::allocator_propagate_on_container_move_assignment<
|
||||
allocator2<int> >::type::value);
|
||||
allocator2<int> >::type::value);
|
||||
}
|
||||
|
||||
using test::default_generator;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int, noexcept_tests::hash_nothrow_move_assign,
|
||||
noexcept_tests::equal_to_nothrow_move_assign, allocator1<int> >*
|
||||
throwing_set_alloc1;
|
||||
boost::unordered_flat_set<int, noexcept_tests::hash_nothrow_move_construct,
|
||||
noexcept_tests::equal_to_nothrow_move_construct>* throwing_set;
|
||||
boost::unordered_flat_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap>* throwing_set2;
|
||||
|
||||
boost::unordered_flat_set<int, noexcept_tests::hash_nothrow_move_assign,
|
||||
noexcept_tests::equal_to_nothrow_move_assign, allocator2<int> >*
|
||||
throwing_set_alloc2;
|
||||
boost::unordered_flat_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap, allocator1<int> >* throwing_set_alloc1;
|
||||
|
||||
boost::unordered_flat_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap, allocator2<int> >* throwing_set_alloc2;
|
||||
|
||||
boost::unordered_node_set<int, noexcept_tests::hash_nothrow_move_construct,
|
||||
noexcept_tests::equal_to_nothrow_move_construct>* throwing_node_set;
|
||||
boost::unordered_node_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap>* throwing_node_set2;
|
||||
|
||||
boost::unordered_node_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap, allocator1<int> >*
|
||||
throwing_node_set_alloc1;
|
||||
|
||||
boost::unordered_node_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap, allocator2<int> >*
|
||||
throwing_node_set_alloc2;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(
|
||||
test_nothrow_move_when_noexcept, ((throwing_set)(throwing_node_set)))
|
||||
UNORDERED_TEST(
|
||||
test_nothrow_swap_when_noexcept, ((throwing_set2)(throwing_node_set2)))
|
||||
UNORDERED_TEST(test_nothrow_move_assign_when_noexcept,
|
||||
((throwing_set_alloc1)(throwing_set_alloc2))((default_generator)))
|
||||
((throwing_set_alloc1)(throwing_set_alloc2)
|
||||
(throwing_node_set_alloc1)(throwing_node_set_alloc2))(
|
||||
(default_generator)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<int, noexcept_tests::hash_nothrow_move_construct,
|
||||
noexcept_tests::equal_to_nothrow_move_construct>* throwing_set;
|
||||
|
||||
boost::unordered_set<int, noexcept_tests::hash_nothrow_swap,
|
||||
noexcept_tests::equal_to_nothrow_swap>* throwing_set2;
|
||||
|
||||
boost::unordered_set<int, noexcept_tests::hash_nothrow_move_assign,
|
||||
noexcept_tests::equal_to_nothrow_move_assign, allocator1<int> >*
|
||||
throwing_set_alloc1;
|
||||
@@ -456,6 +481,8 @@ boost::unordered_set<int, noexcept_tests::hash_nothrow_move_assign,
|
||||
noexcept_tests::equal_to_nothrow_move_assign, allocator2<int> >*
|
||||
throwing_set_alloc2;
|
||||
|
||||
UNORDERED_TEST(test_nothrow_move_when_noexcept, ((throwing_set)))
|
||||
UNORDERED_TEST(test_nothrow_swap_when_noexcept, ((throwing_set2)))
|
||||
UNORDERED_TEST(test_nothrow_move_assign_when_noexcept,
|
||||
((throwing_set_alloc1)(throwing_set_alloc2))((default_generator)))
|
||||
#endif
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright (C) 2022 Christian Mazakas
|
||||
// Copyright (C) 2022-2023 Christian Mazakas
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@@ -335,12 +335,14 @@ namespace move_tests {
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
template <class T> static void extract(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
(void)y.extract(get_key(*v.begin()));
|
||||
BOOST_TEST_EQ(y.size(),
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T> static void merge(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
@@ -375,6 +377,7 @@ namespace move_tests {
|
||||
static_cast<typename T::size_type>(std::distance(y.begin(), y.end())));
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
template <class T> static void buckets(T& y, test::random_values<T> const& v)
|
||||
{
|
||||
(void)y.begin(0);
|
||||
@@ -384,6 +387,7 @@ namespace move_tests {
|
||||
(void)y.bucket_size(0);
|
||||
(void)y.bucket(get_key(*v.begin()));
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class T>
|
||||
static void double_move_construct(T& y, test::random_values<T> const&)
|
||||
@@ -607,9 +611,38 @@ namespace move_tests {
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_map_no_prop_move;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator2<test::object> >* test_node_set;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_node_map;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_move> >*
|
||||
test_node_set_prop_move;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::propagate_move> >* test_node_map_prop_move;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_move> >*
|
||||
test_node_set_no_prop_move;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_node_map_no_prop_move;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(post_move_tests,
|
||||
((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)(test_set_no_prop_move)(test_map_no_prop_move))(
|
||||
((test_set)(test_map)(test_set_prop_move)(test_map_prop_move)
|
||||
(test_set_no_prop_move)(test_map_no_prop_move)
|
||||
(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_move)(test_node_map_prop_move)
|
||||
(test_node_set_no_prop_move)(test_node_map_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<std::pair<test::object const, test::object> > >*
|
||||
@@ -654,12 +687,14 @@ namespace move_tests {
|
||||
test::cxx11_allocator<std::pair<test::object const, test::object>,
|
||||
test::no_propagate_move> >* test_multimap_no_prop_move;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(post_move_tests,
|
||||
((test_set)(test_multiset)(test_map)(test_multimap)(test_set_prop_move)(
|
||||
test_multiset_prop_move)(test_map_prop_move)(test_multimap_prop_move)(
|
||||
test_set_no_prop_move)(test_multiset_no_prop_move)(test_map_no_prop_move)(
|
||||
test_multimap_no_prop_move))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -21,8 +21,7 @@ void macros_test()
|
||||
BOOST_ERROR("std::numeric_limits<size_t>::digits >= 64, but "
|
||||
"BOOST_UNORDERED_FCA_HAS_64B_SIZE_T is not defined");
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
|
||||
BOOST_ERROR("std::numeric_limits<size_t>::digits < 64, but "
|
||||
"BOOST_UNORDERED_FCA_HAS_64B_SIZE_T is defined");
|
||||
@@ -155,7 +154,7 @@ void get_remainder_test()
|
||||
|
||||
for (std::size_t i = 0; i < 1000000u; ++i) {
|
||||
boost::uint64_t f = rng();
|
||||
boost::uint32_t d = static_cast<uint32_t>(rng());
|
||||
boost::uint32_t d = rng() & 0xffffffffu;
|
||||
|
||||
boost::uint64_t r1 =
|
||||
boost::unordered::detail::prime_fmod_size<>::get_remainder(f, d);
|
||||
@@ -180,14 +179,14 @@ void modulo_test()
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for (std::size_t i = 0; i < 1000000u; ++i) {
|
||||
std::size_t hash = static_cast<std::size_t>(rng());
|
||||
std::size_t hash = static_cast<std::size_t>(-1) & rng();
|
||||
|
||||
for (std::size_t j = 0; j < sizes_len; ++j) {
|
||||
std::size_t h = hash;
|
||||
|
||||
#if defined(BOOST_UNORDERED_FCA_HAS_64B_SIZE_T)
|
||||
if (sizes[j] <= UINT_MAX) {
|
||||
h = boost::uint32_t(h) + boost::uint32_t(h >> 32);
|
||||
h = boost::uint32_t(h & 0xffffffffu) + boost::uint32_t(h >> 32);
|
||||
}
|
||||
#endif
|
||||
std::size_t p1 =
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -437,6 +437,35 @@ namespace rehash_tests {
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
template <class X>
|
||||
void rehash_node_stability(X*, test::random_generator generator)
|
||||
{
|
||||
typedef typename X::value_type value_type;
|
||||
std::set<value_type const*> elements;
|
||||
|
||||
test::random_values<X> v(1000, generator);
|
||||
test::ordered<X> tracker;
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
X x(v.begin(), v.end());
|
||||
|
||||
typedef typename X::iterator iterator;
|
||||
for (iterator pos = x.begin(); pos != x.end(); ++pos) {
|
||||
elements.insert(boost::addressof(*pos));
|
||||
}
|
||||
|
||||
x.rehash(2 * x.bucket_count());
|
||||
|
||||
for (iterator pos = x.begin(); pos != x.end(); ++pos) {
|
||||
if (!BOOST_TEST(
|
||||
elements.find(boost::addressof(*pos)) != elements.end())) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
template <class X> void rehash_test1(X*, test::random_generator generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
@@ -581,32 +610,67 @@ namespace rehash_tests {
|
||||
monotonic_allocator<std::pair<test::object const, test::object> > >*
|
||||
test_map_monotonic;
|
||||
|
||||
UNORDERED_TEST(rehash_empty_test1, ((int_set_ptr)(test_map_ptr)))
|
||||
boost::unordered_node_set<int>* int_node_set_ptr;
|
||||
boost::unordered_node_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_node_map_ptr;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set_tracking;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_node_map_tracking;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
monotonic_allocator<test::object> >* test_node_set_monotonic;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
monotonic_allocator<std::pair<test::object const, test::object> > >*
|
||||
test_node_map_monotonic;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(rehash_empty_test1,
|
||||
((int_set_ptr)(test_map_ptr)
|
||||
(int_node_set_ptr)(test_node_map_ptr)))
|
||||
UNORDERED_TEST(rehash_empty_test2,
|
||||
((int_set_ptr)(test_map_ptr))(
|
||||
((int_set_ptr)(test_map_ptr)
|
||||
(int_node_set_ptr)(test_node_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_empty_test3,
|
||||
((int_set_ptr)(test_map_ptr))(
|
||||
((int_set_ptr)(test_map_ptr)
|
||||
(int_node_set_ptr)(test_node_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_test1,
|
||||
((int_set_ptr)(test_map_ptr)
|
||||
(int_node_set_ptr)(test_node_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(reserve_empty_test1,
|
||||
((int_set_ptr)(test_map_ptr)(int_node_set_ptr)(test_node_map_ptr)))
|
||||
UNORDERED_TEST(reserve_empty_test2,
|
||||
((int_set_ptr)(test_map_ptr)(int_node_set_ptr)(test_node_map_ptr)))
|
||||
UNORDERED_TEST(reserve_test1,
|
||||
((int_set_ptr)(test_map_ptr)(int_node_set_ptr)(test_node_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(reserve_test2,
|
||||
((int_set_ptr)(test_map_ptr)(int_node_set_ptr)(test_node_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(
|
||||
rehash_test1, ((int_set_ptr)(test_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(reserve_empty_test1, ((int_set_ptr)(test_map_ptr)))
|
||||
UNORDERED_TEST(reserve_empty_test2, ((int_set_ptr)(test_map_ptr)))
|
||||
UNORDERED_TEST(
|
||||
reserve_test1, ((int_set_ptr)(test_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(
|
||||
reserve_test2, ((int_set_ptr)(test_map_ptr))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_empty_tracking,
|
||||
((test_set_tracking)(test_map_tracking))(
|
||||
((test_set_tracking)(test_map_tracking)
|
||||
(test_node_set_tracking)(test_node_map_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(
|
||||
rehash_nonempty_tracking, ((test_set_tracking)(test_map_tracking))(
|
||||
(default_generator)(limited_range)))
|
||||
UNORDERED_TEST(rehash_stability, ((test_set_monotonic)(test_map_monotonic))(
|
||||
(default_generator)(limited_range)))
|
||||
UNORDERED_TEST(rehash_nonempty_tracking,
|
||||
((test_set_tracking)(test_map_tracking)
|
||||
(test_node_set_tracking)(test_node_map_tracking))(
|
||||
(default_generator)(limited_range)))
|
||||
UNORDERED_TEST(rehash_stability,
|
||||
((test_set_monotonic)(test_map_monotonic)
|
||||
(test_node_set_monotonic)(test_node_map_monotonic))(
|
||||
(default_generator)(limited_range)))
|
||||
UNORDERED_TEST(rehash_node_stability,
|
||||
((int_node_set_ptr)(test_node_map_ptr)
|
||||
(test_node_set_tracking)(test_node_map_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_set<int>* int_set_ptr;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
@@ -639,6 +703,7 @@ namespace rehash_tests {
|
||||
monotonic_allocator<std::pair<test::object const, test::object> > >*
|
||||
test_multimap_monotonic;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(rehash_empty_test1,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)))
|
||||
UNORDERED_TEST(rehash_empty_test2,
|
||||
@@ -669,6 +734,12 @@ namespace rehash_tests {
|
||||
UNORDERED_TEST(rehash_stability,
|
||||
((test_set_monotonic)(test_multiset_monotonic)(test_map_monotonic)(test_multimap_monotonic))(
|
||||
(default_generator)(limited_range)))
|
||||
UNORDERED_TEST(rehash_node_stability,
|
||||
((int_set_ptr)(test_map_ptr)(test_set_tracking)(test_map_tracking)
|
||||
(test_multiset_ptr)(int_multimap_ptr)
|
||||
(test_multiset_tracking)(test_multimap_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#endif
|
||||
} // namespace rehash_tests
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// Copyright 2021-2022 Christian Mazakas.
|
||||
// Copyright 2021-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -45,7 +45,8 @@ template <typename T> struct A
|
||||
|
||||
template <class T> int A<T>::count = 0;
|
||||
|
||||
template <class UnorderedContainer> void bucket_count_constructor()
|
||||
template <class UnorderedContainer>
|
||||
void bucket_count_constructor(UnorderedContainer*)
|
||||
{
|
||||
BOOST_TEST_EQ(num_allocations, 0u);
|
||||
BOOST_TEST_EQ(total_allocation, 0u);
|
||||
@@ -64,7 +65,8 @@ template <class UnorderedContainer> void bucket_count_constructor()
|
||||
num_allocations = 0;
|
||||
}
|
||||
|
||||
template <class UnorderedContainer> void range_bucket_constructor()
|
||||
template <class UnorderedContainer>
|
||||
void range_bucket_constructor(UnorderedContainer*)
|
||||
{
|
||||
BOOST_TEST_EQ(num_allocations, 0u);
|
||||
BOOST_TEST_EQ(total_allocation, 0u);
|
||||
@@ -85,7 +87,7 @@ template <class UnorderedContainer> void range_bucket_constructor()
|
||||
num_allocations = 0;
|
||||
}
|
||||
|
||||
template <class UnorderedContainer> void reserve_tests()
|
||||
template <class UnorderedContainer> void reserve_tests(UnorderedContainer*)
|
||||
{
|
||||
BOOST_TEST_EQ(num_allocations, 0u);
|
||||
BOOST_TEST_EQ(total_allocation, 0u);
|
||||
@@ -124,7 +126,7 @@ template <class UnorderedContainer> void reserve_tests()
|
||||
num_allocations = 0;
|
||||
}
|
||||
|
||||
template <class UnorderedContainer> void rehash_tests()
|
||||
template <class UnorderedContainer> void rehash_tests(UnorderedContainer*)
|
||||
{
|
||||
BOOST_TEST_EQ(num_allocations, 0u);
|
||||
BOOST_TEST_EQ(total_allocation, 0u);
|
||||
@@ -191,89 +193,81 @@ template <class UnorderedContainer> void rehash_tests()
|
||||
num_allocations = 0;
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (unordered_set_reserve) {
|
||||
{
|
||||
// prove Allocator invariants
|
||||
// from cppref:
|
||||
// Given:
|
||||
// * A, an Allocator type for type T
|
||||
// * B, the corresponding Allocator type for some cv-unqualified object type
|
||||
// U (as obtained by rebinding A)
|
||||
//
|
||||
// Expression:
|
||||
// A a(b)
|
||||
//
|
||||
// Return Type:
|
||||
// Constructs `a` such that `B(a)==b` and `A(b)==a`.
|
||||
// (Note: This implies that all allocators related by rebind maintain each
|
||||
// other's resources, such as memory pools.)
|
||||
//
|
||||
//
|
||||
typedef boost::allocator_rebind<A<int>, float>::type alloc_rebound;
|
||||
alloc_rebound b;
|
||||
A<int> a(b);
|
||||
BOOST_ASSERT(alloc_rebound(a) == b);
|
||||
BOOST_ASSERT(A<int>(b) == a);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_set<int*, boost::hash<int*>,
|
||||
std::equal_to<int*>, A<int*> >
|
||||
unordered_set;
|
||||
|
||||
typedef boost::unordered_flat_map<int*, int*, boost::hash<int*>,
|
||||
std::equal_to<int*>, A<std::pair<int const*, int*> > >
|
||||
unordered_map;
|
||||
|
||||
bucket_count_constructor<unordered_set>();
|
||||
bucket_count_constructor<unordered_map>();
|
||||
|
||||
range_bucket_constructor<unordered_set>();
|
||||
range_bucket_constructor<unordered_map>();
|
||||
|
||||
reserve_tests<unordered_set>();
|
||||
reserve_tests<unordered_map>();
|
||||
|
||||
rehash_tests<unordered_set>();
|
||||
rehash_tests<unordered_map>();
|
||||
|
||||
#else
|
||||
typedef boost::unordered_set<int, boost::hash<int>, std::equal_to<int>,
|
||||
A<int> >
|
||||
unordered_set;
|
||||
|
||||
typedef boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
A<int> >
|
||||
unordered_multiset;
|
||||
|
||||
typedef boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
A<std::pair<int const, int> > >
|
||||
unordered_map;
|
||||
|
||||
typedef boost::unordered_multimap<int, int, boost::hash<int>,
|
||||
std::equal_to<int>, A<std::pair<int const, int> > >
|
||||
unordered_multimap;
|
||||
|
||||
bucket_count_constructor<unordered_set>();
|
||||
bucket_count_constructor<unordered_map>();
|
||||
bucket_count_constructor<unordered_multiset>();
|
||||
bucket_count_constructor<unordered_multimap>();
|
||||
|
||||
range_bucket_constructor<unordered_set>();
|
||||
range_bucket_constructor<unordered_map>();
|
||||
range_bucket_constructor<unordered_multiset>();
|
||||
range_bucket_constructor<unordered_multimap>();
|
||||
|
||||
reserve_tests<unordered_set>();
|
||||
reserve_tests<unordered_map>();
|
||||
reserve_tests<unordered_multiset>();
|
||||
reserve_tests<unordered_multimap>();
|
||||
|
||||
rehash_tests<unordered_set>();
|
||||
rehash_tests<unordered_map>();
|
||||
rehash_tests<unordered_multiset>();
|
||||
rehash_tests<unordered_multimap>();
|
||||
#endif
|
||||
UNORDERED_AUTO_TEST (allocator_check) {
|
||||
// prove Allocator invariants
|
||||
// from cppref:
|
||||
// Given:
|
||||
// * A, an Allocator type for type T
|
||||
// * B, the corresponding Allocator type for some cv-unqualified object type
|
||||
// U (as obtained by rebinding A)
|
||||
//
|
||||
// Expression:
|
||||
// A a(b)
|
||||
//
|
||||
// Return Type:
|
||||
// Constructs `a` such that `B(a)==b` and `A(b)==a`.
|
||||
// (Note: This implies that all allocators related by rebind maintain each
|
||||
// other's resources, such as memory pools.)
|
||||
//
|
||||
//
|
||||
typedef boost::allocator_rebind<A<int>, float>::type alloc_rebound;
|
||||
alloc_rebound b;
|
||||
A<int> a(b);
|
||||
BOOST_ASSERT(alloc_rebound(a) == b);
|
||||
BOOST_ASSERT(A<int>(b) == a);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_set<int*, boost::hash<int*>, std::equal_to<int*>,
|
||||
A<int*> >* test_set;
|
||||
static boost::unordered_flat_map<int*, int*, boost::hash<int*>,
|
||||
std::equal_to<int*>, A<std::pair<int const*, int*> > >* test_map;
|
||||
|
||||
static boost::unordered_node_set<int*, boost::hash<int*>, std::equal_to<int*>,
|
||||
A<int*> >* test_node_set;
|
||||
|
||||
static boost::unordered_node_map<int*, int*, boost::hash<int*>,
|
||||
std::equal_to<int*>, A<std::pair<int const*, int*> > >* test_node_map;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(bucket_count_constructor,
|
||||
((test_set)(test_map)(test_node_set)(test_node_map)))
|
||||
|
||||
UNORDERED_TEST(range_bucket_constructor,
|
||||
((test_set)(test_map)(test_node_set)(test_node_map)))
|
||||
|
||||
UNORDERED_TEST(reserve_tests,
|
||||
((test_set)(test_map)(test_node_set)(test_node_map)))
|
||||
|
||||
UNORDERED_TEST(rehash_tests,
|
||||
((test_set)(test_map)(test_node_set)(test_node_map)))
|
||||
// clang-format on
|
||||
#else
|
||||
static boost::unordered_set<int, boost::hash<int>, std::equal_to<int>, A<int> >*
|
||||
test_set;
|
||||
|
||||
static boost::unordered_multiset<int, boost::hash<int>, std::equal_to<int>,
|
||||
A<int> >* test_multiset;
|
||||
|
||||
static boost::unordered_map<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
A<std::pair<int const, int> > >* test_map;
|
||||
|
||||
static boost::unordered_multimap<int, int, boost::hash<int>, std::equal_to<int>,
|
||||
A<std::pair<int const, int> > >* test_multimap;
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(bucket_count_constructor,
|
||||
((test_set)(test_map)(test_multiset)(test_multimap)))
|
||||
|
||||
UNORDERED_TEST(range_bucket_constructor,
|
||||
((test_set)(test_map)(test_multiset)(test_multimap)))
|
||||
|
||||
UNORDERED_TEST(reserve_tests,
|
||||
((test_set)(test_map)(test_multiset)(test_multimap)))
|
||||
|
||||
UNORDERED_TEST(rehash_tests,
|
||||
((test_set)(test_map)(test_multiset)(test_multimap)))
|
||||
// clang-format on
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -312,7 +312,10 @@ void set_scary_test()
|
||||
UNORDERED_AUTO_TEST (scary_tests) {
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
map_scary_test<boost::unordered_flat_map>();
|
||||
map_scary_test<boost::unordered_node_map>();
|
||||
|
||||
set_scary_test<boost::unordered_flat_set>();
|
||||
set_scary_test<boost::unordered_node_set>();
|
||||
#else
|
||||
map_scary_test<boost::unordered_map>();
|
||||
map_scary_test<boost::unordered_multimap>();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
|
||||
// Copyright 2021-2022 Christian Mazakas.
|
||||
// Copyright 2021-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -65,21 +65,12 @@ typedef std::scoped_allocator_adaptor<test::allocator<pair_type>,
|
||||
test::allocator<boost::uint64_t> >
|
||||
allocator_type;
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef boost::unordered_flat_map<const boost::uint64_t, vector_type,
|
||||
boost::hash<boost::uint64_t>, std::equal_to<boost::uint64_t>, allocator_type>
|
||||
map_type;
|
||||
#else
|
||||
typedef boost::unordered_map<const boost::uint64_t, vector_type,
|
||||
boost::hash<boost::uint64_t>, std::equal_to<boost::uint64_t>, allocator_type>
|
||||
map_type;
|
||||
#endif
|
||||
|
||||
UNORDERED_AUTO_TEST (scoped_allocator) {
|
||||
template <class X> static void scoped_allocator(X*)
|
||||
{
|
||||
allocator_type alloc(
|
||||
test::allocator<pair_type>(1337), test::allocator<boost::uint64_t>(7331));
|
||||
|
||||
map_type map(alloc);
|
||||
X map(alloc);
|
||||
|
||||
for (unsigned i = 0; i < 10; ++i) {
|
||||
boost::ignore_unused(map[i]);
|
||||
@@ -88,6 +79,24 @@ UNORDERED_AUTO_TEST (scoped_allocator) {
|
||||
BOOST_TEST(map.size() == 10);
|
||||
}
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_map<const boost::uint64_t, vector_type,
|
||||
boost::hash<boost::uint64_t>, std::equal_to<boost::uint64_t>, allocator_type>*
|
||||
test_map;
|
||||
|
||||
static boost::unordered_node_map<const boost::uint64_t, vector_type,
|
||||
boost::hash<boost::uint64_t>, std::equal_to<boost::uint64_t>, allocator_type>*
|
||||
test_node_map;
|
||||
|
||||
UNORDERED_TEST(scoped_allocator, ((test_map)(test_node_map)))
|
||||
#else
|
||||
static boost::unordered_map<const boost::uint64_t, vector_type,
|
||||
boost::hash<boost::uint64_t>, std::equal_to<boost::uint64_t>, allocator_type>*
|
||||
test_map;
|
||||
|
||||
UNORDERED_TEST(scoped_allocator, ((test_map)))
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
#endif
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -8,10 +8,13 @@
|
||||
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include <cstdlib>
|
||||
#include <algorithm>
|
||||
#include "../helpers/equivalent.hpp"
|
||||
#include "../helpers/generators.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
|
||||
test::seed_t initialize_seed(14878);
|
||||
|
||||
template <class X> void simple_test(X const& a)
|
||||
{
|
||||
@@ -84,59 +87,76 @@ template <class X> void simple_test(X const& a)
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_AUTO_TEST (simple_tests) {
|
||||
using namespace std;
|
||||
srand(14878);
|
||||
template <class X> static void simple_set_tests(X*)
|
||||
{
|
||||
X x;
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_set.\n";
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_set<int> set;
|
||||
#else
|
||||
boost::unordered_set<int> set;
|
||||
#endif
|
||||
simple_test(set);
|
||||
simple_test(x);
|
||||
|
||||
set.insert(1);
|
||||
set.insert(2);
|
||||
set.insert(1456);
|
||||
simple_test(set);
|
||||
x.insert(1);
|
||||
x.insert(2);
|
||||
x.insert(1456);
|
||||
simple_test(x);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multiset.\n";
|
||||
boost::unordered_multiset<int> multiset;
|
||||
simple_test(multiset);
|
||||
template <class X> static void simple_multiset_tests(X*)
|
||||
{
|
||||
X x;
|
||||
simple_test(x);
|
||||
|
||||
for (int i1 = 0; i1 < 1000; ++i1) {
|
||||
int count = rand() % 10, index = rand();
|
||||
for (int j = 0; j < count; ++j)
|
||||
multiset.insert(index);
|
||||
x.insert(index);
|
||||
}
|
||||
simple_test(multiset);
|
||||
simple_test(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_map.\n";
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
boost::unordered_flat_map<int, int> map;
|
||||
#else
|
||||
boost::unordered_map<int, int> map;
|
||||
#endif
|
||||
template <class X> static void simple_map_tests(X*)
|
||||
{
|
||||
X x;
|
||||
|
||||
for (int i2 = 0; i2 < 1000; ++i2) {
|
||||
map.insert(std::pair<const int, int>(rand(), rand()));
|
||||
x.insert(std::pair<const int, int>(rand(), rand()));
|
||||
}
|
||||
simple_test(map);
|
||||
simple_test(x);
|
||||
}
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
BOOST_LIGHTWEIGHT_TEST_OSTREAM << "Test unordered_multimap.\n";
|
||||
boost::unordered_multimap<int, int> multimap;
|
||||
template <class X> static void simple_multimap_tests(X*)
|
||||
{
|
||||
X x;
|
||||
|
||||
for (int i3 = 0; i3 < 1000; ++i3) {
|
||||
int count = rand() % 10, index = rand();
|
||||
for (int j = 0; j < count; ++j)
|
||||
multimap.insert(std::pair<const int, int>(index, rand()));
|
||||
x.insert(std::pair<const int, int>(index, rand()));
|
||||
}
|
||||
simple_test(multimap);
|
||||
#endif
|
||||
simple_test(x);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef BOOST_UNORDERED_FOA_TESTS
|
||||
static boost::unordered_flat_set<int>* flat_set;
|
||||
static boost::unordered_flat_map<int, int>* flat_map;
|
||||
static boost::unordered_node_set<int>* node_set;
|
||||
static boost::unordered_node_map<int, int>* node_map;
|
||||
|
||||
UNORDERED_TEST(simple_map_tests, ((flat_map)(node_map)))
|
||||
UNORDERED_TEST(simple_set_tests, ((flat_set)(node_set)))
|
||||
#else
|
||||
static boost::unordered_set<int>* set;
|
||||
static boost::unordered_map<int, int>* map;
|
||||
static boost::unordered_multiset<int>* multiset;
|
||||
static boost::unordered_multimap<int, int>* multimap;
|
||||
|
||||
UNORDERED_TEST(simple_set_tests, ((set)))
|
||||
UNORDERED_TEST(simple_map_tests, ((map)))
|
||||
UNORDERED_TEST(simple_multiset_tests, ((multiset)))
|
||||
UNORDERED_TEST(simple_multimap_tests, ((multimap)))
|
||||
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Copyright 2022-2023 Christian Mazakas.
|
||||
// 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)
|
||||
|
||||
@@ -168,19 +168,58 @@ namespace swap_tests {
|
||||
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||
test_map_no_prop_swap;
|
||||
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, std::allocator<test::object> >* test_node_map_std_alloc;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_node_set;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::allocator1<test::object> >* test_node_map;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::propagate_swap> >*
|
||||
test_node_set_prop_swap;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to, test::cxx11_allocator<test::object, test::propagate_swap> >*
|
||||
test_node_map_prop_swap;
|
||||
|
||||
boost::unordered_node_set<test::object, test::hash, test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||
test_node_set_no_prop_swap;
|
||||
boost::unordered_node_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::cxx11_allocator<test::object, test::no_propagate_swap> >*
|
||||
test_node_map_no_prop_swap;
|
||||
|
||||
UNORDERED_AUTO_TEST (check_traits) {
|
||||
BOOST_TEST(!is_propagate(test_set));
|
||||
BOOST_TEST(is_propagate(test_set_prop_swap));
|
||||
BOOST_TEST(!is_propagate(test_set_no_prop_swap));
|
||||
|
||||
BOOST_TEST(!is_propagate(test_node_set));
|
||||
BOOST_TEST(is_propagate(test_node_set_prop_swap));
|
||||
BOOST_TEST(!is_propagate(test_node_set_no_prop_swap));
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
UNORDERED_TEST(swap_tests1,
|
||||
((test_map_std_alloc)(test_set)(test_map)(test_set_prop_swap)(test_map_prop_swap)(test_set_no_prop_swap)(test_map_no_prop_swap))(
|
||||
((test_map_std_alloc)(test_set)(test_map)
|
||||
(test_set_prop_swap)(test_map_prop_swap)
|
||||
(test_set_no_prop_swap)(test_map_no_prop_swap)
|
||||
(test_node_map_std_alloc)(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_swap)(test_node_map_prop_swap)
|
||||
(test_node_set_no_prop_swap)(test_node_map_no_prop_swap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
|
||||
UNORDERED_TEST(swap_tests2,
|
||||
((test_set)(test_map)(test_set_prop_swap)(test_map_prop_swap)(test_set_no_prop_swap)(test_map_no_prop_swap))(
|
||||
((test_set)(test_map)
|
||||
(test_set_prop_swap)(test_map_prop_swap)
|
||||
(test_set_no_prop_swap)(test_map_no_prop_swap)
|
||||
(test_node_set)(test_node_map)
|
||||
(test_node_set_prop_swap)(test_node_map_prop_swap)
|
||||
(test_node_set_no_prop_swap)(test_node_map_no_prop_swap))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
// clang-format on
|
||||
#else
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
std::allocator<test::object> >* test_map_std_alloc;
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user