Compare commits
198 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d67d58cb4b | |||
| 0e19223e5b | |||
| 8ee48fe909 | |||
| ef0b3a0cd8 | |||
| 44b669a71c | |||
| 554ce65a69 | |||
| c37d9a3bf1 | |||
| 4fcc6a9cab | |||
| 0d61746fa3 | |||
| 20559cbe5c | |||
| 6728ffcf6d | |||
| 9f5f8b1b48 | |||
| aedebff4e1 | |||
| 47fa9cd17e | |||
| a0e1bc295a | |||
| f5bd5bc3d0 | |||
| 630031706b | |||
| 9bc7876583 | |||
| b482890453 | |||
| bc764d34cf | |||
| a9da328e1d | |||
| 087f2052fc | |||
| 51a75c0fd0 | |||
| ce5033c4a0 | |||
| bcbb13e0cf | |||
| 7aac692162 | |||
| f1729bb8a1 | |||
| b4884b7201 | |||
| b0a13f896f | |||
| cb86544fcf | |||
| 6c97eabbb3 | |||
| 968c2e9c11 | |||
| 53a6566a98 | |||
| 9b1ec6cbce | |||
| 3f3b2128ec | |||
| d3e6be7356 | |||
| 423eb08f00 | |||
| 777f2084a3 | |||
| e5bf418c3d | |||
| 9d8beff688 | |||
| 91f63697a7 | |||
| 22344ab27f | |||
| d742ee3a3b | |||
| d881d4d5e2 | |||
| 15318f0e46 | |||
| e32f72d69c | |||
| e37e749b0b | |||
| b02d013d44 | |||
| 33dbd7cd76 | |||
| 8f382e874d | |||
| bce9b5927a | |||
| c6aa90651c | |||
| cddb7cb8b1 | |||
| a36a7327eb | |||
| d2dc503e4a | |||
| 0c7b51cc16 | |||
| 3f0f8efbba | |||
| 8d59040ece | |||
| 15d04295d6 | |||
| 866ab46385 | |||
| 4cd1827104 | |||
| 3bd7e93ac6 | |||
| 1d991d065e | |||
| 8782036a88 | |||
| f088a5b9b9 | |||
| 16386f586f | |||
| 59a7fa09ba | |||
| 8cbd9ad80a | |||
| b0ee2b5116 | |||
| adb91ac06d | |||
| 11322de29f | |||
| 0c90a84aa0 | |||
| aa16d1b8a9 | |||
| 6b65c8f230 | |||
| b445ff639d | |||
| 08187c7a1f | |||
| 6953014874 | |||
| 7b24cf6607 | |||
| 6f0a715541 | |||
| 85c7900339 | |||
| c0cd51bd2a | |||
| 73891c6ec8 | |||
| 82f4d9899c | |||
| cad3509a17 | |||
| 44582ecbb9 | |||
| 9e38e3c578 | |||
| d5d6a18298 | |||
| 88f8228079 | |||
| 31c3ce97de | |||
| 651f209e20 | |||
| d9d4ff1676 | |||
| 2ce456768d | |||
| 65d4a9cafa | |||
| 8d2a5c25ea | |||
| 49f0929466 | |||
| 0673c5653c | |||
| a3a1ab6ad2 | |||
| 7d639e2e86 | |||
| 32b9f06fe5 | |||
| 3d302980d4 | |||
| 1dc1962b8c | |||
| a0c7112652 | |||
| b031b61b94 | |||
| b9fe4ed789 | |||
| c707bcb6d8 | |||
| 771943e291 | |||
| 675e30bd95 | |||
| 2cab340749 | |||
| c3786357a6 | |||
| 33ee8ea302 | |||
| 583225ad9f | |||
| c16a3f2a4a | |||
| 1d93fa12a2 | |||
| f4f322b94d | |||
| 3299b31787 | |||
| 95a37b0d3d | |||
| 4d6ebc7eb3 | |||
| a0679e5ffe | |||
| b01f9ee15d | |||
| 215d8e82cb | |||
| 067884a4e2 | |||
| ca2a46f290 | |||
| d007a5a7bd | |||
| b0195297f0 | |||
| 52061a7c64 | |||
| 829a4a1620 | |||
| 6dd58f4e9c | |||
| a2ad7966ea | |||
| 9d897faece | |||
| 389e967484 | |||
| 0365be763a | |||
| fc3fca4264 | |||
| bf0ae6e63a | |||
| 9057369f93 | |||
| aec9c48cf4 | |||
| 3968ff0567 | |||
| 8170716156 | |||
| 651727508b | |||
| b3b4853dfa | |||
| 1f3980986d | |||
| 4e458f0054 | |||
| 8fe3ebc7b3 | |||
| cf298cba7f | |||
| d83efc5ea4 | |||
| ff9d08a917 | |||
| e1a30831fe | |||
| 34e5773a4a | |||
| c26137f2dd | |||
| 1264805a59 | |||
| bfb6520107 | |||
| ab867a65f4 | |||
| 5239b101e2 | |||
| c5f64ed1d3 | |||
| a06498f5ce | |||
| bcd8969b9a | |||
| bc7e77f239 | |||
| 66222eee6a | |||
| ee1974dc87 | |||
| 4918bb6b7e | |||
| e563c89b1c | |||
| ce076782fd | |||
| b206513a11 | |||
| bf4a5efd2d | |||
| 6b6dde4f97 | |||
| ac1a236de6 | |||
| d4adcd9b71 | |||
| c046b916f8 | |||
| 4be37cfdaf | |||
| 6994a37b23 | |||
| 6bf84067b3 | |||
| 48ff743d06 | |||
| 5339bf67d9 | |||
| 1979ce98a2 | |||
| a22c133c3d | |||
| f919ce532a | |||
| 30187f7743 | |||
| dd30162c9e | |||
| fde765c494 | |||
| 9c476ef72a | |||
| 470abf41d8 | |||
| a3626b5095 | |||
| 948151bd7d | |||
| f965298154 | |||
| 5a4d93a72d | |||
| bee4ed2e5f | |||
| bd24dfd284 | |||
| faf54eef0d | |||
| 97b52879f5 | |||
| 9a7d1d336a | |||
| 3fc18d56ac | |||
| 6bcf457b46 | |||
| 01b2369700 | |||
| fcb3f0e82a | |||
| 1e4deb10a1 | |||
| 6ee93f17e4 | |||
| 7e41e08a57 | |||
| 7a6c8eca09 | |||
| dce386068b |
@@ -31,14 +31,9 @@ environment:
|
||||
B2_VARIANT: debug,release
|
||||
|
||||
matrix:
|
||||
- FLAVOR: Visual Studio 2008, 2010, 2012
|
||||
- FLAVOR: Visual Studio 2015
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
|
||||
B2_ADDRESS_MODEL: 32 # No 64bit support
|
||||
|
||||
- FLAVOR: Visual Studio 2013, 2015
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||
B2_TOOLSET: msvc-12.0,msvc-14.0
|
||||
B2_TOOLSET: msvc-14.0
|
||||
|
||||
- FLAVOR: Visual Studio 2017, C++14
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
@@ -55,43 +50,27 @@ environment:
|
||||
B2_CXXSTD: latest
|
||||
B2_TOOLSET: msvc-14.1
|
||||
|
||||
- FLAVOR: cygwin (32-bit, C++03,11)
|
||||
- FLAVOR: cygwin (32-bit, C++11)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 03,11
|
||||
B2_CXXSTD: 11
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (32-bit, C++14,1z)
|
||||
- FLAVOR: cygwin (32-bit, C++14)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 14,1z
|
||||
B2_CXXSTD: 14
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, C++03,11)
|
||||
- FLAVOR: cygwin (32-bit, C++1z)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 03,11
|
||||
ADDPATH: C:\cygwin\bin;
|
||||
B2_ADDRESS_MODEL: 32
|
||||
B2_CXXSTD: 1z
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, C++14,1z)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 14,1z
|
||||
B2_TOOLSET: gcc
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest, C++03)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 03
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
B2_VARIANT: release
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest, C++11)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
@@ -119,13 +98,6 @@ environment:
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
B2_VARIANT: release
|
||||
|
||||
- FLAVOR: mingw-w64, 32 bit, C++03
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||
B2_CXXSTD: 03
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 32
|
||||
|
||||
- FLAVOR: mingw-w64, 32 bit, C++11
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||
@@ -154,13 +126,6 @@ environment:
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 32
|
||||
|
||||
- FLAVOR: mingw-w64, 64 bit, C++03
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
B2_CXXSTD: 03
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 64
|
||||
|
||||
- FLAVOR: mingw-w64, 64 bit, C++11
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||
|
||||
@@ -100,40 +100,16 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
};
|
||||
|
||||
[
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.4 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.4', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
||||
"g++-4.4-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.6 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.6', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
||||
"g++-4.6-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.7 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.7', CXXSTD: '98,0x', ADDRMD: '32,64' },
|
||||
"g++-4.7-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.8* 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 14.04 GCC 4.9 32/64",
|
||||
"cppalliance/droneubuntu1404:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '03,11', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' },
|
||||
"g++-4.9-multilib",
|
||||
[ "ppa:ubuntu-toolchain-r/test" ],
|
||||
),
|
||||
@@ -141,26 +117,26 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
linux_pipeline(
|
||||
"Linux 16.04 GCC 5* 32/64",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 6 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
"g++-6-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 7* 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 8 32/64 (03,11)",
|
||||
"Linux 18.04 GCC 8 32/64 (11)",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '11', ADDRMD: '32,64' },
|
||||
"g++-8-multilib",
|
||||
),
|
||||
|
||||
@@ -172,9 +148,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* 32/64 (03,11,14)",
|
||||
"Linux 20.04 GCC 9* 32/64 (11,14)",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
@@ -186,14 +162,14 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* S390x (03,11,14)",
|
||||
"Linux 20.04 GCC 9* S390x (11,14)",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14' },
|
||||
arch="s390x",
|
||||
),
|
||||
|
||||
@@ -205,9 +181,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 10 32/64 (03,11,14)",
|
||||
"Linux 20.04 GCC 10 32/64 (11,14)",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
"g++-10-multilib",
|
||||
),
|
||||
|
||||
@@ -219,9 +195,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 11* 32/64 (03,11,14)",
|
||||
"Linux 22.04 GCC 11* 32/64 (11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
@@ -231,9 +207,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32 ASAN (03,11,14)",
|
||||
"Linux 22.04 GCC 12 32 ASAN (11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11', ADDRMD: '32' } + asan,
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11', ADDRMD: '32' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
@@ -266,9 +242,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 ASAN (03,11,14)",
|
||||
"Linux 22.04 GCC 12 64 ASAN (11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14', ADDRMD: '64' } + asan,
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14', ADDRMD: '64' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
@@ -301,9 +277,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 23.04 GCC 13 32/64 (03,11,14)",
|
||||
"Linux 23.04 GCC 13 32/64 (11,14)",
|
||||
"cppalliance/droneubuntu2304:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14', ADDRMD: '32,64' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14', ADDRMD: '32,64' },
|
||||
"g++-13 g++-13-multilib",
|
||||
),
|
||||
|
||||
@@ -317,112 +293,112 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.5",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,11' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '11' },
|
||||
"clang-3.5",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.6",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '03,11,14' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '11,14' },
|
||||
"clang-3.6",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.7",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,11,14' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '11,14' },
|
||||
"clang-3.7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.8",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '03,11,14' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '11,14' },
|
||||
"clang-3.8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 3.9",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '03,11,14' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '11,14' },
|
||||
"clang-3.9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 4.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '03,11,14' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '11,14' },
|
||||
"clang-4.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 5.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '03,11,14,1z' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14,1z' },
|
||||
"clang-5.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 6.0",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '03,11,14,17' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '11,14,17' },
|
||||
"clang-6.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 7",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,11,14,17' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '11,14,17' },
|
||||
"clang-7",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 8",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '03,11,14,17' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '11,14,17' },
|
||||
"clang-8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 9",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,11,14,17,2a' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '11,14,17,2a' },
|
||||
"clang-9",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 10",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '03,11,14,17,2a' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '11,14,17,2a' },
|
||||
"clang-10",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 11",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,11,14,17,2a' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '11,14,17,2a' },
|
||||
"clang-11",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 12",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '03,11,14,17,2a' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '11,14,17,2a' },
|
||||
"clang-12",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 13",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '11,14,17,20' },
|
||||
"clang-13",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 UBSAN (03,11,14)",
|
||||
"Linux 22.04 Clang 14 UBSAN (11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14' } + ubsan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14' } + ubsan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
@@ -434,9 +410,9 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 ASAN (03,11,14)",
|
||||
"Linux 22.04 Clang 14 ASAN (11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14' } + asan,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14' } + asan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
@@ -457,14 +433,14 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' },
|
||||
"clang-15",
|
||||
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
"MacOS 10.15 Xcode 12.2 UBSAN (03,11)",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11' } + ubsan,
|
||||
"MacOS 10.15 Xcode 12.2 UBSAN (11)",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11' } + ubsan,
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
@@ -479,7 +455,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,
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + asan,
|
||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
||||
),
|
||||
|
||||
|
||||
@@ -20,4 +20,4 @@ b2 -d0 headers
|
||||
|
||||
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
||||
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
||||
b2 -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
b2 --abbreviate-paths -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% variant=debug,release embed-manifest-via=linker
|
||||
|
||||
@@ -32,6 +32,16 @@ env:
|
||||
CODECOV_NAME: Github Actions
|
||||
|
||||
jobs:
|
||||
runner-selection:
|
||||
# runs-on: ubuntu-latest
|
||||
runs-on: ${{ github.repository_owner == 'boostorg' && fromJSON('[ "self-hosted", "linux", "x64", "ubuntu-latest-aws" ]') || 'ubuntu-latest' }}
|
||||
outputs:
|
||||
labelmatrix: ${{ steps.aws_hosted_runners.outputs.labelmatrix }}
|
||||
steps:
|
||||
- name: AWS Hosted Runners
|
||||
id: aws_hosted_runners
|
||||
uses: cppalliance/aws-hosted-runners@v1.0.0
|
||||
|
||||
posix:
|
||||
defaults:
|
||||
run:
|
||||
@@ -42,50 +52,71 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
# Linux, gcc
|
||||
- { compiler: gcc-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-7' }
|
||||
- { compiler: gcc-8, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-8' }
|
||||
- { compiler: gcc-9, cxxstd: '03,11,14,17', os: ubuntu-20.04, install: 'g++-9' }
|
||||
- { compiler: gcc-10, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-10' }
|
||||
- { compiler: gcc-11, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-11' }
|
||||
- { name: "gcc-12 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
|
||||
- { name: "gcc-12 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
|
||||
- { compiler: gcc-7, cxxstd: '11,14,17', os: 'ubuntu-20.04', install: 'g++-7' }
|
||||
- { compiler: gcc-8, cxxstd: '11,14,17', os: 'ubuntu-20.04', install: 'g++-8' }
|
||||
- { compiler: gcc-9, cxxstd: '11,14,17', os: 'ubuntu-22.04', install: 'g++-9' }
|
||||
- { compiler: gcc-10, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-10' }
|
||||
- { compiler: gcc-11, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-11' }
|
||||
- { name: "gcc-12 w/ sanitizers (11)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '11', os: 'ubuntu-22.04', ccache_key: "san1" }
|
||||
- { name: "gcc-12 w/ sanitizers (14)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '14', os: 'ubuntu-22.04', ccache_key: "san1" }
|
||||
- { name: "gcc-12 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '17', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "gcc-12 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '20', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "gcc-12 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '2b', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: Collect coverage, coverage: yes,
|
||||
compiler: gcc-12, cxxstd: '03,20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
compiler: gcc-12, cxxstd: '20', os: 'ubuntu-22.04', install: 'g++-12-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
|
||||
- { name: "cfoa tsan (gcc)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: gcc-12,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes }
|
||||
- { name: "cfoa tsan (gcc-12)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-22.04', compiler: gcc-12,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan" }
|
||||
|
||||
# Linux, clang, libc++
|
||||
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
|
||||
- { compiler: clang-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-10 libc++-10-dev libc++abi-10-dev' }
|
||||
- { compiler: clang-11, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, stdlib: libc++, install: 'clang-11 libc++-11-dev libc++abi-11-dev' }
|
||||
# clang-12 doesn't work on ubuntu-22.04, the linker can't find -lunwind for some reason
|
||||
- { name: "clang-12 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '03,11,14', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san1" }
|
||||
- { name: "clang-12 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '17,20,2b', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
- { compiler: clang-13, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
- { compiler: clang-14, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
- { compiler: clang-7, cxxstd: '11,14,17', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
|
||||
- { compiler: clang-10, cxxstd: '11,14,17,20', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-10 libc++-10-dev libc++abi-10-dev' }
|
||||
- { compiler: clang-11, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-11 libc++-11-dev libc++abi-11-dev' }
|
||||
# clang-12 doesn't work on 'ubuntu-22.04', the linker can't find -lunwind for some reason
|
||||
- { name: "clang-12 w/ sanitizers (11,14)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '11,14', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san1" }
|
||||
- { name: "clang-12 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '17', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
- { name: "clang-12 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '20', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
- { name: "clang-12 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '2b', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
||||
- { compiler: 'clang-13', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
- { compiler: 'clang-13', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
||||
|
||||
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
|
||||
- { name: "clang-14 w/ sanitizers (03,11,14)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
|
||||
- { name: "clang-14 w/ sanitizers (17,20,2b)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
|
||||
- { name: "clang-14 w/ sanitizers (11,14)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '11,14', os: 'ubuntu-22.04', ccache_key: "san1" }
|
||||
- { name: "clang-14 w/ sanitizers (17)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '17', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "clang-14 w/ sanitizers (20)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '20', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
- { name: "clang-14 w/ sanitizers (2b)", sanitize: yes,
|
||||
compiler: clang-14, cxxstd: '2b', os: 'ubuntu-22.04', ccache_key: "san2" }
|
||||
|
||||
- { name: "cfoa tsan (clang)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: clang-14,
|
||||
- { name: "cfoa tsan (clang-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-22.04', compiler: clang-14,
|
||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
|
||||
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
||||
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev', ccache_key: "tsan" }
|
||||
|
||||
- { compiler: 'clang-15', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
- { compiler: 'clang-15', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
||||
|
||||
# OSX, clang
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-12, sanitize: yes }
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: macos-12, thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests' }
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: 'macos-11' }
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: 'macos-12', sanitize: yes, ccache_key: "san1" }
|
||||
- { compiler: clang, cxxstd: '11,14,17,2a', os: 'macos-12', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache_key: "tsan" }
|
||||
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-13' }
|
||||
|
||||
timeout-minutes: 180
|
||||
runs-on: ${{matrix.os}}
|
||||
timeout-minutes: 360
|
||||
# posix (gcc-12 w/ sanitizers is taking longer than 210 minutes
|
||||
# timeout-minutes: 210
|
||||
needs: [runner-selection]
|
||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
|
||||
container: ${{matrix.container}}
|
||||
env: {B2_USE_CCACHE: 1}
|
||||
|
||||
@@ -229,15 +260,16 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { 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' }
|
||||
- { 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: '11,14,17,2a', addrmd: '64', os: 'windows-2019', variant: 'debug,release' }
|
||||
|
||||
runs-on: ${{matrix.os}}
|
||||
needs: [runner-selection]
|
||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -291,10 +323,11 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { sys: MINGW32, compiler: gcc, cxxstd: '03,11,17,20' }
|
||||
- { sys: MINGW64, compiler: gcc, cxxstd: '03,11,17,20' }
|
||||
- { sys: MINGW32, compiler: gcc, cxxstd: '11,17,20' }
|
||||
- { sys: MINGW64, compiler: gcc, cxxstd: '11,17,20' }
|
||||
|
||||
runs-on: windows-latest
|
||||
needs: [runner-selection]
|
||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['windows-latest'] }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
@@ -348,11 +381,12 @@ jobs:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { os: ubuntu-20.04, build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
|
||||
- { os: windows-2019, build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
|
||||
- { os: 'ubuntu-20.04', build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
|
||||
- { os: 'windows-2019', build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
|
||||
|
||||
timeout-minutes: 120
|
||||
runs-on: ${{matrix.os}}
|
||||
needs: [runner-selection]
|
||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 28 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 26 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 25 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 62 KiB After Width: | Height: | Size: 62 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 57 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 54 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 53 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 58 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 53 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 48 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 55 KiB After Width: | Height: | Size: 52 KiB |
|
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 41 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 54 KiB |
|
Before Width: | Height: | Size: 47 KiB After Width: | Height: | Size: 43 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 47 KiB |
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 44 KiB |
|
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
@@ -298,7 +298,7 @@ The successful lookup benchmarks are done by looking up all `n` values, in their
|
||||
The unsuccessful lookup benchmarks use `n` randomly generated integers but using a different seed value.
|
||||
|
||||
|
||||
=== GCC 11, x64
|
||||
=== GCC 12, x64
|
||||
|
||||
|
||||
[caption=]
|
||||
@@ -317,7 +317,7 @@ h|unsuccessful lookup
|
||||
|
||||
|===
|
||||
|
||||
=== Clang 12, x64
|
||||
=== Clang 15, x64
|
||||
|
||||
|
||||
[caption=]
|
||||
@@ -336,7 +336,7 @@ h|unsuccessful lookup
|
||||
|
||||
|===
|
||||
|
||||
=== Visual Studio 2019, x64
|
||||
=== Visual Studio 2022, x64
|
||||
|
||||
|
||||
[caption=]
|
||||
@@ -374,7 +374,7 @@ h|unsuccessful lookup
|
||||
|
||||
|===
|
||||
|
||||
=== GCC 11, x86
|
||||
=== GCC 12, x86
|
||||
|
||||
|
||||
[caption=]
|
||||
@@ -393,7 +393,7 @@ h|unsuccessful lookup
|
||||
|
||||
|===
|
||||
|
||||
=== Clang 12, x86
|
||||
=== Clang 15, x86
|
||||
|
||||
|
||||
[caption=]
|
||||
@@ -412,7 +412,7 @@ h|unsuccessful lookup
|
||||
|
||||
|===
|
||||
|
||||
=== Visual Studio 2019, x86
|
||||
=== Visual Studio 2022, x86
|
||||
|
||||
|
||||
[caption=]
|
||||
@@ -447,6 +447,10 @@ operations follow a https://en.wikipedia.org/wiki/Zipf%27s_law#Formal_definition
|
||||
with different _skew_ parameters: the higher the skew, the more concentrated are the keys in the lower values
|
||||
of the covered range.
|
||||
|
||||
`boost::concurrent_flat_map` is exercised using both regular and xref:#concurrent_bulk_visitation[bulk visitation]:
|
||||
in the latter case, lookup keys are buffered in a local array and then processed at
|
||||
once each time the buffer reaches xref:#concurrent_flat_map_constants[`bulk_visit_size`].
|
||||
|
||||
=== GCC 12, x64
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,22 @@
|
||||
:github-pr-url: https://github.com/boostorg/unordered/pull
|
||||
:cpp: C++
|
||||
|
||||
== Release 1.84.0 - Major update
|
||||
|
||||
* Added `boost::concurrent_flat_set`.
|
||||
* Added `[c]visit_while` operations to concurrent containers,
|
||||
with serial and parallel variants.
|
||||
* Added efficient move construction of `boost::unordered_flat_(map|set)` from
|
||||
`boost::concurrent_flat_(map|set)` and vice versa.
|
||||
* Added bulk visitation to concurrent containers for increased lookup performance.
|
||||
* Added debug-mode mechanisms for detecting illegal reentrancies into
|
||||
a concurrent container from user code.
|
||||
* Added Boost.Serialization support to all containers and their (non-local) iterator types.
|
||||
* Added support for fancy pointers to open-addressing and concurrent containers.
|
||||
This enables scenarios like the use of Boost.Interprocess allocators to construct containers in shared memory.
|
||||
* Starting with this release, `boost::unordered_[multi]set` and `boost::unordered_[multi]map`
|
||||
only work with C++11 onwards.
|
||||
|
||||
== Release 1.83.0 - Major update
|
||||
|
||||
* Added `boost::concurrent_flat_map`, a fast, thread-safe hashmap based on open addressing.
|
||||
|
||||
@@ -7,116 +7,54 @@
|
||||
|
||||
== Closed-addressing Containers
|
||||
|
||||
`unordered_[multi]set` and `unordered_[multi]map` are intended to provide a conformant
|
||||
implementation of the {cpp}20 standard that will work with {cpp}98 upwards.
|
||||
This wide compatibility does mean some compromises have to be made.
|
||||
With a compiler and library that fully support {cpp}11, the differences should
|
||||
be minor.
|
||||
`boost::unordered_[multi]set` and `boost::unordered_[multi]map` provide a conformant
|
||||
implementation for {cpp}11 (or later) compilers of the latest standard revision of
|
||||
{cpp} unordered associative containers, with very minor deviations as noted.
|
||||
The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]
|
||||
and support https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers^].
|
||||
|
||||
=== Move Emulation
|
||||
=== Deduction Guides
|
||||
|
||||
Support for move semantics is implemented using Boost.Move. If rvalue
|
||||
references are available it will use them, but if not it uses a close,
|
||||
but imperfect emulation. On such compilers:
|
||||
Deduction guides for
|
||||
https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[class template argument deduction (CTAD)^]
|
||||
are only available on {cpp}17 (or later) compilers.
|
||||
|
||||
* Non-copyable objects can be stored in the containers.
|
||||
They can be constructed in place using `emplace`, or if they support
|
||||
Boost.Move, moved into place.
|
||||
* The containers themselves are not movable.
|
||||
* Argument forwarding is not perfect.
|
||||
=== Piecewise Pair Emplacement
|
||||
|
||||
=== Use of Allocators
|
||||
|
||||
{cpp}11 introduced a new allocator system. It's backwards compatible due to
|
||||
the lax requirements for allocators in the old standard, but might need
|
||||
some changes for allocators which worked with the old versions of the
|
||||
unordered containers.
|
||||
It uses a traits class, `allocator_traits` to handle the allocator
|
||||
adding extra functionality, and making some methods and types optional.
|
||||
During development a stable release of
|
||||
`allocator_traits` wasn't available so an internal partial implementation
|
||||
is always used in this version. Hopefully a future version will use the
|
||||
standard implementation where available.
|
||||
|
||||
The member functions `construct`, `destroy` and `max_size` are now
|
||||
optional, if they're not available a fallback is used.
|
||||
A full implementation of `allocator_traits` requires sophisticated
|
||||
member function detection so that the fallback is used whenever the
|
||||
member function call is not well formed.
|
||||
This requires support for SFINAE expressions, which are available on
|
||||
GCC from version 4.4 and Clang.
|
||||
|
||||
On other compilers, there's just a test to see if the allocator has
|
||||
a member, but no check that it can be called. So rather than using a
|
||||
fallback there will just be a compile error.
|
||||
|
||||
`propagate_on_container_copy_assignment`,
|
||||
`propagate_on_container_move_assignment`,
|
||||
`propagate_on_container_swap` and
|
||||
`select_on_container_copy_construction` are also supported.
|
||||
Due to imperfect move emulation, some assignments might check
|
||||
`propagate_on_container_copy_assignment` on some compilers and
|
||||
`propagate_on_container_move_assignment` on others.
|
||||
|
||||
=== Construction/Destruction Using Allocators
|
||||
|
||||
The following support is required for full use of {cpp}11 style
|
||||
construction/destruction:
|
||||
|
||||
* Variadic templates.
|
||||
* Piecewise construction of `std::pair`.
|
||||
* Either `std::allocator_traits` or expression SFINAE.
|
||||
|
||||
This is detected using Boost.Config. The macro
|
||||
`BOOST_UNORDERED_CXX11_CONSTRUCTION` will be set to 1 if it is found, or 0
|
||||
otherwise.
|
||||
|
||||
When this is the case `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` will always be used, apart from when piecewise
|
||||
constructing a `std::pair` using `boost::tuple` (see <<compliance_pairs,below>>), but that should be easily avoided.
|
||||
|
||||
When support is not available `allocator_traits::construct` and
|
||||
`allocator_traits::destroy` are never called.
|
||||
|
||||
=== Pointer Traits
|
||||
|
||||
`pointer_traits` aren't used. Instead, pointer types are obtained from
|
||||
rebound allocators, this can cause problems if the allocator can't be
|
||||
used with incomplete types. If `const_pointer` is not defined in the
|
||||
allocator, `boost::pointer_to_other<pointer, const value_type>::type`
|
||||
is used to obtain a const pointer.
|
||||
|
||||
=== Pairs
|
||||
|
||||
Since the containers use `std::pair` they're limited to the version
|
||||
from the current standard library. But since {cpp}11 ``std::pair``'s
|
||||
`piecewise_construct` based constructor is very useful, `emplace`
|
||||
emulates it with a `piecewise_construct` in the `boost::unordered`
|
||||
namespace. So for example, the following will work:
|
||||
In accordance with the standard specification,
|
||||
`boost::unordered_[multi]map::emplace` supports piecewise pair construction:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
boost::unordered_multimap<std::string, std::complex> x;
|
||||
|
||||
x.emplace(
|
||||
std::piecewise_construct,
|
||||
std::make_tuple("key"), std::make_tuple(1, 2));
|
||||
----
|
||||
|
||||
Additionally, the same
|
||||
functionality is provided via non-standard `boost::unordered::piecewise_construct`
|
||||
and Boost.Tuple:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
x.emplace(
|
||||
boost::unordered::piecewise_construct,
|
||||
boost::make_tuple("key"), boost::make_tuple(1, 2));
|
||||
----
|
||||
|
||||
Older drafts of the standard also supported variadic constructors
|
||||
for `std::pair`, where the first argument would be used for the
|
||||
first part of the pair, and the remaining for the second part.
|
||||
This feature has been retained for backwards compatibility with
|
||||
previous versions of Boost.Unordered: users are encouraged to
|
||||
update their code to use `std::piecewise_construct` and
|
||||
``std::tuple``s instead.
|
||||
|
||||
=== Miscellaneous
|
||||
=== Swap
|
||||
|
||||
When swapping, `Pred` and `Hash` are not currently swapped by calling
|
||||
`swap`, their copy constructors are used. As a consequence when swapping
|
||||
`swap`, their copy constructors are used. As a consequence, when swapping
|
||||
an exception may be thrown from their copy constructor.
|
||||
|
||||
Variadic constructor arguments for `emplace` are only used when both
|
||||
rvalue references and variadic template parameters are available.
|
||||
Otherwise `emplace` can only take up to 10 constructors arguments.
|
||||
|
||||
== Open-addressing Containers
|
||||
|
||||
The C++ standard does not currently provide any open-addressing container
|
||||
@@ -129,7 +67,9 @@ radically different from that imposed by the standard (closed addressing).
|
||||
Open-addressing containers provided by Boost.Unordered only work with reasonably
|
||||
compliant C++11 (or later) compilers. Language-level features such as move semantics
|
||||
and variadic template parameters are then not emulated.
|
||||
The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^].
|
||||
The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]
|
||||
and support https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers^].
|
||||
|
||||
|
||||
The main differences with C++ unordered associative containers are:
|
||||
|
||||
@@ -148,22 +88,24 @@ The main differences with C++ unordered associative containers are:
|
||||
|
||||
== Concurrent Containers
|
||||
|
||||
There is currently no specification in the C++ standard for this or any other concurrent
|
||||
data structure. `boost::concurrent_flat_map` takes the same template parameters as `std::unordered_map`
|
||||
and all the maps provided by Boost.Unordered, and its API is modelled after that of
|
||||
`boost::unordered_flat_map` with the crucial difference that iterators are not provided
|
||||
There is currently no specification in the C++ standard for this or any other type of concurrent
|
||||
data structure. The APIs of `boost::concurrent_flat_set` and `boost::concurrent_flat_map`
|
||||
are modelled after `std::unordered_flat_set` and `std::unordered_flat_map`, respectively,
|
||||
with the crucial difference that iterators are not provided
|
||||
due to their inherent problems in concurrent scenarios (high contention, prone to deadlocking):
|
||||
so, `boost::concurrent_flat_map` is technically not a
|
||||
so, Boost.Unordered concurrent containers are technically not models of
|
||||
https://en.cppreference.com/w/cpp/named_req/Container[Container^], although
|
||||
it meets all the requirements of https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]
|
||||
containers except those implying iterators.
|
||||
they meet all the requirements of https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]
|
||||
containers (including
|
||||
https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointer^] support)
|
||||
except those implying iterators.
|
||||
|
||||
In a non-concurrent unordered container, iterators serve two main purposes:
|
||||
|
||||
* Access to an element previously located via lookup.
|
||||
* Container traversal.
|
||||
|
||||
In place of iterators, `boost::concurrent_flat_map` uses _internal visitation_
|
||||
In place of iterators, `boost::concurrent_flat_set` and `boost::concurrent_flat_map` use _internal visitation_
|
||||
facilities as a thread-safe substitute. Classical operations returning an iterator to an
|
||||
element already existing in the container, like for instance:
|
||||
|
||||
@@ -191,15 +133,15 @@ template<class F> size_t visit_all(F f);
|
||||
----
|
||||
|
||||
of which there are parallelized versions in C++17 compilers with parallel
|
||||
algorithm support. In general, the interface of `boost::concurrent_flat_map`
|
||||
is derived from that of `boost::unordered_flat_map` by a fairly straightforward
|
||||
process of replacing iterators with visitation where applicable. If
|
||||
`iterator` and `const_iterator` provide mutable and const access to elements,
|
||||
algorithm support. In general, the interface of concurrent containers
|
||||
is derived from that of their non-concurrent counterparts by a fairly straightforward
|
||||
process of replacing iterators with visitation where applicable. If for
|
||||
regular maps `iterator` and `const_iterator` provide mutable and const access to elements,
|
||||
respectively, here visitation is granted mutable or const access depending on
|
||||
the constness of the member function used (there are also `*cvisit` overloads for
|
||||
explicit const visitation).
|
||||
explicit const visitation); In the case of `boost::concurrent_flat_set`, visitation is always const.
|
||||
|
||||
The one notable operation not provided is `operator[]`/`at`, which can be
|
||||
One notable operation not provided by `boost::concurrent_flat_map` is `operator[]`/`at`, which can be
|
||||
replaced, if in a more convoluted manner, by
|
||||
xref:#concurrent_flat_map_try_emplace_or_cvisit[`try_emplace_or_visit`].
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
:idprefix: concurrent_
|
||||
|
||||
Boost.Unordered currently provides just one concurrent container named `boost::concurrent_flat_map`.
|
||||
`boost::concurrent_flat_map` is a hash table that allows concurrent write/read access from
|
||||
Boost.Unordered provides `boost::concurrent_flat_set` and `boost::concurrent_flat_map`,
|
||||
hash tables that allow concurrent write/read access from
|
||||
different threads without having to implement any synchronzation mechanism on the user's side.
|
||||
|
||||
[source,c++]
|
||||
@@ -36,16 +36,16 @@ In the example above, threads access `m` without synchronization, just as we'd d
|
||||
single-threaded scenario. In an ideal setting, if a given workload is distributed among
|
||||
_N_ threads, execution is _N_ times faster than with one thread —this limit is
|
||||
never attained in practice due to synchronization overheads and _contention_ (one thread
|
||||
waiting for another to leave a locked portion of the map), but `boost::concurrent_flat_map`
|
||||
is designed to perform with very little overhead and typically achieves _linear scaling_
|
||||
waiting for another to leave a locked portion of the map), but Boost.Unordered concurrent containers
|
||||
are designed to perform with very little overhead and typically achieve _linear scaling_
|
||||
(that is, performance is proportional to the number of threads up to the number of
|
||||
logical cores in the CPU).
|
||||
|
||||
== Visitation-based API
|
||||
|
||||
The first thing a new user of `boost::concurrent_flat_map` will notice is that this
|
||||
class _does not provide iterators_ (which makes it technically
|
||||
not a https://en.cppreference.com/w/cpp/named_req/Container[Container^]
|
||||
The first thing a new user of `boost::concurrent_flat_set` or `boost::concurrent_flat_map`
|
||||
will notice is that these classes _do not provide iterators_ (which makes them technically
|
||||
not https://en.cppreference.com/w/cpp/named_req/Container[Containers^]
|
||||
in the C++ standard sense). The reason for this is that iterators are inherently
|
||||
thread-unsafe. Consider this hypothetical code:
|
||||
|
||||
@@ -73,7 +73,7 @@ m.visit(k, [](const auto& x) { // x is the element with key k (if it exists)
|
||||
----
|
||||
|
||||
The visitation function passed by the user (in this case, a lambda function)
|
||||
is executed internally by `boost::concurrent_flat_map` in
|
||||
is executed internally by Boost.Unordered in
|
||||
a thread-safe manner, so it can access the element without worrying about other
|
||||
threads interfering in the process.
|
||||
|
||||
@@ -112,7 +112,7 @@ if (found) {
|
||||
}
|
||||
----
|
||||
|
||||
Visitation is prominent in the API provided by `boost::concurrent_flat_map`, and
|
||||
Visitation is prominent in the API provided by `boost::concurrent_flat_set` and `boost::concurrent_flat_map`, and
|
||||
many classical operations have visitation-enabled variations:
|
||||
|
||||
[source,c++]
|
||||
@@ -129,13 +129,17 @@ the element: as a general rule, operations on a `boost::concurrent_flat_map` `m`
|
||||
will grant visitation functions const/non-const access to the element depending on whether
|
||||
`m` is const/non-const. Const access can be always be explicitly requested
|
||||
by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result
|
||||
in higher parallelization. Consult the xref:#concurrent_flat_map[reference]
|
||||
for a complete list of available operations.
|
||||
in higher parallelization. For `boost::concurrent_flat_set`, on the other hand,
|
||||
visitation is always const access.
|
||||
Consult the references of
|
||||
xref:#concurrent_flat_set[`boost::concurrent_flat_set`] and
|
||||
xref:#concurrent_flat_map[`boost::concurrent_flat_map`]
|
||||
for the complete list of visitation-enabled operations.
|
||||
|
||||
== Whole-Table Visitation
|
||||
|
||||
In the absence of iterators, `boost::concurrent_flat_map` provides `visit_all`
|
||||
as an alternative way to process all the elements in the map:
|
||||
In the absence of iterators, `visit_all` is provided
|
||||
as an alternative way to process all the elements in the container:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -154,7 +158,28 @@ m.visit_all(std::execution::par, [](auto& x) { // run in parallel
|
||||
});
|
||||
----
|
||||
|
||||
There is another whole-table visitation operation, `erase_if`:
|
||||
Traversal can be interrupted midway:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
// finds the key to a given (unique) value
|
||||
|
||||
int key = 0;
|
||||
int value = ...;
|
||||
bool found = !m.visit_while([&](const auto& x) {
|
||||
if(x.second == value) {
|
||||
key = x.first;
|
||||
return false; // finish
|
||||
}
|
||||
else {
|
||||
return true; // keep on visiting
|
||||
}
|
||||
});
|
||||
|
||||
if(found) { ... }
|
||||
----
|
||||
|
||||
There is one last whole-table visitation operation, `erase_if`:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
@@ -163,15 +188,64 @@ m.erase_if([](auto& x) {
|
||||
});
|
||||
----
|
||||
|
||||
`erase_if` can also be parallelized. Note that, in order to increase efficiency,
|
||||
these operations do not block the table during execution: this implies that elements
|
||||
`visit_while` and `erase_if` can also be parallelized. Note that, in order to increase efficiency,
|
||||
whole-table visitation operations do not block the table during execution: this implies that elements
|
||||
may be inserted, modified or erased by other threads during visitation. It is
|
||||
advisable not to assume too much about the exact global state of a `boost::concurrent_flat_map`
|
||||
advisable not to assume too much about the exact global state of a concurrent container
|
||||
at any point in your program.
|
||||
|
||||
== Bulk visitation
|
||||
|
||||
Suppose you have an `std::array` of keys you want to look up for in a concurrent map:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
std::array<int, N> keys;
|
||||
...
|
||||
for(const auto& key: keys) {
|
||||
m.visit(key, [](auto& x) { ++x.second; });
|
||||
}
|
||||
----
|
||||
|
||||
_Bulk visitation_ allows us to pass all the keys in one operation:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
m.visit(keys.begin(), keys.end(), [](auto& x) { ++x.second; });
|
||||
----
|
||||
|
||||
This functionality is not provided for mere syntactic convenience, though: by processing all the
|
||||
keys at once, some internal optimizations can be applied that increase
|
||||
performance over the regular, one-at-a-time case (consult the
|
||||
xref:#benchmarks_boostconcurrent_flat_map[benchmarks]). In fact, it may be beneficial
|
||||
to buffer incoming keys so that they can be bulk visited in chunks:
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
static constexpr auto bulk_visit_size = boost::concurrent_flat_map<int,int>::bulk_visit_size;
|
||||
std::array<int, bulk_visit_size> buffer;
|
||||
std::size_t i=0;
|
||||
while(...) { // processing loop
|
||||
...
|
||||
buffer[i++] = k;
|
||||
if(i == bulk_visit_size) {
|
||||
map.visit(buffer.begin(), buffer.end(), [](auto& x) { ++x.second; });
|
||||
i = 0;
|
||||
}
|
||||
...
|
||||
}
|
||||
// flush remaining keys
|
||||
map.visit(buffer.begin(), buffer.begin() + i, [](auto& x) { ++x.second; });
|
||||
----
|
||||
|
||||
There's a latency/throughput tradeoff here: it will take longer for incoming keys to
|
||||
be processed (since they are buffered), but the number of processed keys per second
|
||||
is higher. `bulk_visit_size` is the recommended chunk size —smaller buffers
|
||||
may yield worse performance.
|
||||
|
||||
== Blocking Operations
|
||||
|
||||
``boost::concurrent_flat_map``s can be copied, assigned, cleared and merged just like any
|
||||
``boost::concurrent_flat_set``s and ``boost::concurrent_flat_map``s can be copied, assigned, cleared and merged just like any
|
||||
Boost.Unordered container. Unlike most other operations, these are _blocking_,
|
||||
that is, all other threads are prevented from accesing the tables involved while a copy, assignment,
|
||||
clear or merge operation is in progress. Blocking is taken care of automatically by the library
|
||||
@@ -180,3 +254,31 @@ and the user need not take any special precaution, but overall performance may b
|
||||
Another blocking operation is _rehashing_, which happens explicitly via `rehash`/`reserve`
|
||||
or during insertion when the table's load hits `max_load()`. As with non-concurrent containers,
|
||||
reserving space in advance of bulk insertions will generally speed up the process.
|
||||
|
||||
== Interoperability with non-concurrent containers
|
||||
|
||||
As open-addressing and concurrent containers are based on the same internal data structure,
|
||||
`boost::unordered_flat_set` and `boost::unordered_flat_map` can
|
||||
be efficiently move-constructed from `boost::concurrent_flat_set` and `boost::concurrent_flat_map`,
|
||||
respectively, and vice versa.
|
||||
This interoperability comes handy in multistage scenarios where parts of the data processing happen
|
||||
in parallel whereas other steps are non-concurrent (or non-modifying). In the following example,
|
||||
we want to construct a histogram from a huge input vector of words:
|
||||
the population phase can be done in parallel with `boost::concurrent_flat_map` and results
|
||||
then transferred to the final container.
|
||||
|
||||
[source,c++]
|
||||
----
|
||||
std::vector<std::string> words = ...;
|
||||
|
||||
// Insert words in parallel
|
||||
boost::concurrent_flat_map<std::string_view, std::size_t> m0;
|
||||
std::for_each(
|
||||
std::execution::par, words.begin(), words.end(),
|
||||
[&](const auto& word) {
|
||||
m0.try_emplace_or_visit(word, 1, [](auto& x) { ++x.second; });
|
||||
});
|
||||
|
||||
// Transfer to a regular unordered_flat_map
|
||||
boost::unordered_flat_map m=std::move(m0);
|
||||
----
|
||||
|
||||
@@ -50,6 +50,9 @@ namespace boost {
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
// constants
|
||||
static constexpr size_type xref:#concurrent_flat_map_constants[bulk_visit_size] = _implementation-defined_;
|
||||
|
||||
// construct/copy/destroy
|
||||
xref:#concurrent_flat_map_default_constructor[concurrent_flat_map]();
|
||||
explicit xref:#concurrent_flat_map_bucket_count_constructor[concurrent_flat_map](size_type n,
|
||||
@@ -69,6 +72,7 @@ namespace boost {
|
||||
explicit xref:#concurrent_flat_map_allocator_constructor[concurrent_flat_map](const Allocator& a);
|
||||
xref:#concurrent_flat_map_copy_constructor_with_allocator[concurrent_flat_map](const concurrent_flat_map& other, const Allocator& a);
|
||||
xref:#concurrent_flat_map_move_constructor_with_allocator[concurrent_flat_map](concurrent_flat_map&& other, const Allocator& a);
|
||||
xref:#concurrent_flat_map_move_constructor_from_unordered_flat_map[concurrent_flat_map](unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other);
|
||||
xref:#concurrent_flat_map_initializer_list_constructor[concurrent_flat_map](std::initializer_list<value_type> il,
|
||||
size_type n = _implementation-defined_
|
||||
const hasher& hf = hasher(),
|
||||
@@ -89,9 +93,10 @@ namespace boost {
|
||||
const allocator_type& a);
|
||||
xref:#concurrent_flat_map_destructor[~concurrent_flat_map]();
|
||||
concurrent_flat_map& xref:#concurrent_flat_map_copy_assignment[operator++=++](const concurrent_flat_map& other);
|
||||
concurrent_flat_map& xref:#concurrent_flat_map_move_assignment[operator++=++](concurrent_flat_map&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
concurrent_flat_map& xref:#concurrent_flat_map_move_assignment[operator++=++](concurrent_flat_map&& other) ++noexcept(
|
||||
(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);++
|
||||
concurrent_flat_map& xref:#concurrent_flat_map_initializer_list_assignment[operator++=++](std::initializer_list<value_type>);
|
||||
allocator_type xref:#concurrent_flat_map_get_allocator[get_allocator]() const noexcept;
|
||||
|
||||
@@ -104,6 +109,13 @@ namespace boost {
|
||||
template<class K, class F> size_t xref:#concurrent_flat_map_cvisit[visit](const K& k, F f) const;
|
||||
template<class K, class F> size_t xref:#concurrent_flat_map_cvisit[cvisit](const K& k, F f) const;
|
||||
|
||||
template<class FwdIterator, class F>
|
||||
size_t xref:concurrent_flat_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f);
|
||||
template<class FwdIterator, class F>
|
||||
size_t xref:concurrent_flat_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const;
|
||||
template<class FwdIterator, class F>
|
||||
size_t xref:concurrent_flat_map_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const;
|
||||
|
||||
template<class F> size_t xref:#concurrent_flat_map_cvisit_all[visit_all](F f);
|
||||
template<class F> size_t xref:#concurrent_flat_map_cvisit_all[visit_all](F f) const;
|
||||
template<class F> size_t xref:#concurrent_flat_map_cvisit_all[cvisit_all](F f) const;
|
||||
@@ -114,6 +126,16 @@ namespace boost {
|
||||
template<class ExecutionPolicy, class F>
|
||||
void xref:#concurrent_flat_map_parallel_cvisit_all[cvisit_all](ExecutionPolicy&& policy, F f) const;
|
||||
|
||||
template<class F> bool xref:#concurrent_flat_map_cvisit_while[visit_while](F f);
|
||||
template<class F> bool xref:#concurrent_flat_map_cvisit_while[visit_while](F f) const;
|
||||
template<class F> bool xref:#concurrent_flat_map_cvisit_while[cvisit_while](F f) const;
|
||||
template<class ExecutionPolicy, class F>
|
||||
bool xref:#concurrent_flat_map_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f);
|
||||
template<class ExecutionPolicy, class F>
|
||||
bool xref:#concurrent_flat_map_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f) const;
|
||||
template<class ExecutionPolicy, class F>
|
||||
bool xref:#concurrent_flat_map_parallel_cvisit_while[cvisit_while](ExecutionPolicy&& policy, F f) const;
|
||||
|
||||
// capacity
|
||||
++[[nodiscard]]++ bool xref:#concurrent_flat_map_empty[empty]() const noexcept;
|
||||
size_type xref:#concurrent_flat_map_size[size]() const noexcept;
|
||||
@@ -305,8 +327,7 @@ https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the table.
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the table's value type.
|
||||
`std::allocator_traits<Allocator>::pointer` and `std::allocator_traits<Allocator>::const_pointer`
|
||||
must be convertible to/from `value_type*` and `const value_type*`, respectively.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -364,6 +385,25 @@ if concurrent outstanding operations on `y` do not access `x` directly or indire
|
||||
|
||||
---
|
||||
|
||||
=== Configuration Macros
|
||||
|
||||
==== `BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK`
|
||||
|
||||
In debug builds (more precisely, when
|
||||
link:../../../assert/doc/html/assert.html#boost_assert_is_void[`BOOST_ASSERT_IS_VOID`^]
|
||||
is not defined), __container reentrancies__ (illegaly invoking an operation on `m` from within
|
||||
a function visiting elements of `m`) are detected and signalled through `BOOST_ASSERT_MSG`.
|
||||
When run-time speed is a concern, the feature can be disabled by globally defining
|
||||
this macro.
|
||||
|
||||
=== Constants
|
||||
|
||||
```cpp
|
||||
static constexpr size_type bulk_visit_size;
|
||||
```
|
||||
|
||||
Chunk size internally used in xref:concurrent_flat_map_bulk_visit[bulk visit] operations.
|
||||
|
||||
=== Constructors
|
||||
|
||||
==== Default Constructor
|
||||
@@ -491,6 +531,21 @@ Concurrency:;; Blocking on `other`.
|
||||
|
||||
---
|
||||
|
||||
==== Move Constructor from unordered_flat_map
|
||||
|
||||
```c++
|
||||
concurrent_flat_map(unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other);
|
||||
```
|
||||
|
||||
Move construction from a xref:#unordered_flat_map[`unordered_flat_map`].
|
||||
The internal bucket array of `other` is transferred directly to the new container.
|
||||
The hash function, predicate and allocator are moved-constructed from `other`.
|
||||
|
||||
[horizontal]
|
||||
Complexity:;; O(`bucket_count()`)
|
||||
|
||||
---
|
||||
|
||||
==== Initializer List Constructor
|
||||
[source,c++,subs="+quotes"]
|
||||
----
|
||||
@@ -635,8 +690,9 @@ Concurrency:;; Blocking on `*this` and `other`.
|
||||
==== Move Assignment
|
||||
```c++
|
||||
concurrent_flat_map& operator=(concurrent_flat_map&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
noexcept((boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);
|
||||
```
|
||||
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`.
|
||||
@@ -683,6 +739,42 @@ Notes:;; The `template<class K, class F>` overloads only participate in overload
|
||||
|
||||
---
|
||||
|
||||
==== Bulk visit
|
||||
|
||||
```c++
|
||||
template<class FwdIterator, class F>
|
||||
size_t visit(FwdIterator first, FwdIterator last, F f);
|
||||
template<class FwdIterator, class F>
|
||||
size_t visit(FwdIterator first, FwdIterator last, F f) const;
|
||||
template<class FwdIterator, class F>
|
||||
size_t cvisit(FwdIterator first, FwdIterator last, F f) const;
|
||||
```
|
||||
|
||||
For each element `k` in the range [`first`, `last`),
|
||||
if there is an element `x` in the container with key equivalent to `k`,
|
||||
invokes `f` with a reference to `x`.
|
||||
Such reference is const iff `*this` is const.
|
||||
|
||||
Although functionally equivalent to individually invoking
|
||||
xref:concurrent_flat_map_cvisit[`[c\]visit`] for each key, bulk visitation
|
||||
performs generally faster due to internal streamlining optimizations.
|
||||
It is advisable that `std::distance(first,last)` be at least
|
||||
xref:#concurrent_flat_map_constants[`bulk_visit_size`] to enjoy
|
||||
a performance gain: beyond this size, performance is not expected
|
||||
to increase further.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^]
|
||||
({cpp}11 to {cpp}17),
|
||||
or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later).
|
||||
For `K` = `std::iterator_traits<FwdIterator>::value_type`, either `K` is `key_type` or
|
||||
else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs.
|
||||
In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent.
|
||||
This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
|
||||
Returns:;; The number of elements visited.
|
||||
|
||||
---
|
||||
|
||||
==== [c]visit_all
|
||||
|
||||
```c++
|
||||
@@ -720,6 +812,50 @@ Unsequenced execution policies are not allowed.
|
||||
|
||||
---
|
||||
|
||||
==== [c]visit_while
|
||||
|
||||
```c++
|
||||
template<class F> bool visit_while(F f);
|
||||
template<class F> bool visit_while(F f) const;
|
||||
template<class F> bool cvisit_while(F f) const;
|
||||
```
|
||||
|
||||
Successively invokes `f` with references to each of the elements in the table until `f` returns `false`
|
||||
or all the elements are visited.
|
||||
Such references to the elements are const iff `*this` is const.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; `false` iff `f` ever returns `false`.
|
||||
|
||||
---
|
||||
|
||||
==== Parallel [c]visit_while
|
||||
|
||||
```c++
|
||||
template<class ExecutionPolicy, class F> bool visit_while(ExecutionPolicy&& policy, F f);
|
||||
template<class ExecutionPolicy, class F> bool visit_while(ExecutionPolicy&& policy, F f) const;
|
||||
template<class ExecutionPolicy, class F> bool cvisit_while(ExecutionPolicy&& policy, F f) const;
|
||||
```
|
||||
|
||||
Invokes `f` with references to each of the elements in the table until `f` returns `false`
|
||||
or all the elements are visited.
|
||||
Such references to the elements are const iff `*this` is const.
|
||||
Execution is parallelized according to the semantics of the execution policy specified.
|
||||
|
||||
[horizontal]
|
||||
Returns:;; `false` iff `f` ever returns `false`.
|
||||
Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`.
|
||||
Notes:;; Only available in compilers supporting C++17 parallel algorithms. +
|
||||
+
|
||||
These overloads only participate in overload resolution if `std::is_execution_policy_v<std::remove_cvref_t<ExecutionPolicy>>` is `true`. +
|
||||
+
|
||||
Unsequenced execution policies are not allowed. +
|
||||
+
|
||||
Parallelization implies that execution does not necessary finish as soon as `f` returns `false`, and as a result
|
||||
`f` may be invoked with further elements for which the return value is also `false`.
|
||||
|
||||
---
|
||||
|
||||
=== Size and Capacity
|
||||
|
||||
==== empty
|
||||
@@ -962,13 +1098,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#concurrent_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -1010,13 +1146,13 @@ if there is an element with an equivalent key; otherwise, the construction is of
|
||||
```c++
|
||||
// first four overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<Key>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
|
||||
// last two overloads
|
||||
value_type(std::piecewise_construct,
|
||||
std::forward_as_tuple(boost::forward<K>(k)),
|
||||
std::forward_as_tuple(boost::forward<Args>(args)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
Invalidates pointers and references to elements if a rehashing is issued.
|
||||
@@ -1038,19 +1174,19 @@ template<class K, class M> bool insert_or_assign(K&& k, M&& obj);
|
||||
|
||||
Inserts a new element into the table or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
If there is no such element, it is added to the table 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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -1436,3 +1572,33 @@ Equivalent to
|
||||
-----
|
||||
c.xref:#concurrent_flat_map_erase_if[erase_if](pred);
|
||||
-----
|
||||
|
||||
=== Serialization
|
||||
|
||||
``concurrent_flat_map``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an concurrent_flat_map to an archive
|
||||
|
||||
Saves all the elements of a `concurrent_flat_map` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `std::remove_const<key_type>::type` and `std::remove_const<mapped_type>::type`
|
||||
are serializable (XML serializable), and they do support Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
Concurrency:;; Blocking on `x`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an concurrent_flat_map from an archive
|
||||
|
||||
Deletes all preexisting elements of a `concurrent_flat_map` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `concurrent_flat_map` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
Concurrency:;; Blocking on `x`.
|
||||
|
||||
@@ -44,7 +44,8 @@ boost::unordered_flat_map
|
||||
|
||||
^.^h|*Concurrent*
|
||||
^|
|
||||
^| `boost::concurrent_flat_map`
|
||||
^| `boost::concurrent_flat_set` +
|
||||
`boost::concurrent_flat_map`
|
||||
|
||||
|===
|
||||
|
||||
@@ -56,9 +57,8 @@ in the market within the technical constraints imposed by the required standard
|
||||
interface to accommodate the implementation.
|
||||
There are two variants: **flat** (the fastest) and **node-based**, which
|
||||
provide pointer stability under rehashing at the expense of being slower.
|
||||
* Finally, `boost::concurrent_flat_map` (the only **concurrent container** provided
|
||||
at present) is a hashmap designed and implemented to be used in high-performance
|
||||
multithreaded scenarios. Its interface is radically different from that of regular C++ containers.
|
||||
* Finally, **concurrent containers** are designed and implemented to be used in high-performance
|
||||
multithreaded scenarios. Their interface is radically different from that of regular C++ containers.
|
||||
|
||||
All sets and maps in Boost.Unordered are instantiatied similarly as
|
||||
`std::unordered_set` and `std::unordered_map`, respectively:
|
||||
@@ -73,6 +73,7 @@ namespace boost {
|
||||
class Alloc = std::allocator<Key> >
|
||||
class unordered_set;
|
||||
// same for unordered_multiset, unordered_flat_set, unordered_node_set
|
||||
// and concurrent_flat_set
|
||||
|
||||
template <
|
||||
class Key, class Mapped,
|
||||
|
||||
@@ -121,20 +121,21 @@ for Visual Studio on an x64-mode Intel CPU with SSE2 and for GCC on an IBM s390x
|
||||
== Concurrent Containers
|
||||
|
||||
The same data structure used by Boost.Unordered open-addressing containers has been chosen
|
||||
also as the foundation of `boost::concurrent_flat_map`:
|
||||
also as the foundation of `boost::concurrent_flat_set` and `boost::concurrent_flat_map`:
|
||||
|
||||
* Open-addressing is faster than closed-addressing alternatives, both in non-concurrent and
|
||||
concurrent scenarios.
|
||||
* Open-addressing layouts are eminently suitable for concurrent access and modification
|
||||
with minimal locking. In particular, the metadata array can be used for implementations of
|
||||
lookup that are lock-free up to the last step of actual element comparison.
|
||||
* Layout compatibility with Boost.Unordered flat containers allows for fast transfer
|
||||
of all elements between `boost::concurrent_flat_map` and `boost::unordered_flat_map`.
|
||||
(This feature has not been implemented yet.)
|
||||
* Layout compatibility with Boost.Unordered flat containers allows for
|
||||
xref:#concurrent_interoperability_with_non_concurrent_containers[fast transfer]
|
||||
of all elements between `boost::concurrent_flat_map` and `boost::unordered_flat_map`,
|
||||
and vice versa.
|
||||
|
||||
=== Hash Function and Platform Interoperability
|
||||
|
||||
`boost::concurrent_flat_map` makes the same decisions and provides the same guarantees
|
||||
Concurrent containers make the same decisions and provide the same guarantees
|
||||
as Boost.Unordered open-addressing containers with regards to
|
||||
xref:#rationale_hash_function[hash function defaults] and
|
||||
xref:#rationale_platform_interoperability[platform interoperability].
|
||||
|
||||
@@ -11,3 +11,4 @@ include::unordered_flat_set.adoc[]
|
||||
include::unordered_node_map.adoc[]
|
||||
include::unordered_node_set.adoc[]
|
||||
include::concurrent_flat_map.adoc[]
|
||||
include::concurrent_flat_set.adoc[]
|
||||
|
||||
@@ -67,8 +67,8 @@ xref:#rationale_closed_addressing_containers[corresponding section].
|
||||
|
||||
== Open-addressing Containers
|
||||
|
||||
The diagram shows the basic internal layout of `boost::unordered_flat_map`/`unordered_node_map` and
|
||||
`boost:unordered_flat_set`/`unordered_node_set`.
|
||||
The diagram shows the basic internal layout of `boost::unordered_flat_set`/`unordered_node_set` and
|
||||
`boost:unordered_flat_map`/`unordered_node_map`.
|
||||
|
||||
|
||||
[#img-foa-layout]
|
||||
@@ -76,7 +76,7 @@ The diagram shows the basic internal layout of `boost::unordered_flat_map`/`unor
|
||||
image::foa.png[align=center]
|
||||
|
||||
As with all open-addressing containers, elements (or pointers to the element nodes in the case of
|
||||
`boost::unordered_node_map` and `boost::unordered_node_set`) are stored directly in the bucket array.
|
||||
`boost::unordered_node_set` and `boost::unordered_node_map`) 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.
|
||||
@@ -129,7 +129,7 @@ xref:#rationale_open_addresing_containers[corresponding section].
|
||||
|
||||
== Concurrent Containers
|
||||
|
||||
`boost::concurrent_flat_map` uses the basic
|
||||
`boost::concurrent_flat_set` and `boost::concurrent_flat_map` use the basic
|
||||
xref:#structures_open_addressing_containers[open-addressing layout] described above
|
||||
augmented with synchronization mechanisms.
|
||||
|
||||
|
||||
@@ -77,6 +77,7 @@ namespace boost {
|
||||
explicit xref:#unordered_flat_map_allocator_constructor[unordered_flat_map](const Allocator& a);
|
||||
xref:#unordered_flat_map_copy_constructor_with_allocator[unordered_flat_map](const unordered_flat_map& other, const Allocator& a);
|
||||
xref:#unordered_flat_map_move_constructor_with_allocator[unordered_flat_map](unordered_flat_map&& other, const Allocator& a);
|
||||
xref:#unordered_flat_map_move_constructor_from_concurrent_flat_map[unordered_flat_map](concurrent_flat_map<Key, T, Hash, Pred, Allocator>&& other);
|
||||
xref:#unordered_flat_map_initializer_list_constructor[unordered_flat_map](std::initializer_list<value_type> il,
|
||||
size_type n = _implementation-defined_
|
||||
const hasher& hf = hasher(),
|
||||
@@ -96,9 +97,10 @@ namespace boost {
|
||||
const allocator_type& a);
|
||||
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::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
unordered_flat_map& xref:#unordered_flat_map_move_assignment[operator++=++](unordered_flat_map&& other) ++noexcept(
|
||||
(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::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;
|
||||
|
||||
@@ -311,8 +313,7 @@ https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the contain
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
`std::allocator_traits<Allocator>::pointer` and `std::allocator_traits<Allocator>::const_pointer`
|
||||
must be convertible to/from `value_type*` and `const value_type*`, respectively.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -472,6 +473,22 @@ from `other`, and the allocator is copy-constructed from `a`.
|
||||
|
||||
---
|
||||
|
||||
==== Move Constructor from concurrent_flat_map
|
||||
|
||||
```c++
|
||||
unordered_flat_map(concurrent_flat_map<Key, T, Hash, Pred, Allocator>&& other);
|
||||
```
|
||||
|
||||
Move construction from a xref:#concurrent_flat_map[`concurrent_flat_map`].
|
||||
The internal bucket array of `other` is transferred directly to the new container.
|
||||
The hash function, predicate and allocator are moved-constructed from `other`.
|
||||
|
||||
[horizontal]
|
||||
Complexity:;; Constant time.
|
||||
Concurrency:;; Blocking on `other`.
|
||||
|
||||
---
|
||||
|
||||
==== Initializer List Constructor
|
||||
[source,c++,subs="+quotes"]
|
||||
----
|
||||
@@ -615,8 +632,9 @@ 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::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
noexcept((boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);
|
||||
```
|
||||
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`.
|
||||
@@ -891,13 +909,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#unordered_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -936,13 +954,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#unordered_flat_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -967,19 +985,19 @@ template<class K, class M>
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -1005,19 +1023,19 @@ template<class K, class M>
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted. This implementation ignores it.
|
||||
@@ -1308,7 +1326,7 @@ void rehash(size_type n);
|
||||
|
||||
Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed.
|
||||
|
||||
Invalidates iterators, pointers and references, and changes the order of elements.
|
||||
|
||||
@@ -1447,4 +1465,54 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_flat_map``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_flat_map to an archive
|
||||
|
||||
Saves all the elements of an `unordered_flat_map` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `std::remove_const<key_type>::type` and `std::remove_const<mapped_type>::type`
|
||||
are serializable (XML serializable), and they do support Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_flat_map from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_flat_map` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_flat_map` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_flat_map` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_flat_map` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -71,7 +71,7 @@ namespace boost {
|
||||
xref:#unordered_flat_set_iterator_range_constructor_with_allocator[unordered_flat_set](InputIterator f, InputIterator l, const allocator_type& a);
|
||||
explicit xref:#unordered_flat_set_allocator_constructor[unordered_flat_set](const Allocator& a);
|
||||
xref:#unordered_flat_set_copy_constructor_with_allocator[unordered_flat_set](const unordered_flat_set& other, const Allocator& a);
|
||||
xref:#unordered_flat_set_move_constructor_with_allocator[unordered_flat_set](unordered_flat_set&& other, const Allocator& a);
|
||||
xref:#unordered_flat_set_move_constructor_from_concurrent_flat_set[unordered_flat_set](concurrent_flat_set<Key, Hash, Pred, Allocator>&& other);
|
||||
xref:#unordered_flat_set_initializer_list_constructor[unordered_flat_set](std::initializer_list<value_type> il,
|
||||
size_type n = _implementation-defined_
|
||||
const hasher& hf = hasher(),
|
||||
@@ -91,9 +91,10 @@ namespace boost {
|
||||
const allocator_type& a);
|
||||
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::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
unordered_flat_set& xref:#unordered_flat_set_move_assignment[operator++=++](unordered_flat_set&& other) ++noexcept(
|
||||
(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::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;
|
||||
|
||||
@@ -261,8 +262,7 @@ and https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the con
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
`std::allocator_traits<Allocator>::pointer` and `std::allocator_traits<Allocator>::const_pointer`
|
||||
must be convertible to/from `value_type*` and `const value_type*`, respectively.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -422,6 +422,22 @@ from `other`, and the allocator is copy-constructed from `a`.
|
||||
|
||||
---
|
||||
|
||||
==== Move Constructor from concurrent_flat_set
|
||||
|
||||
```c++
|
||||
unordered_flat_set(concurrent_flat_set<Key, Hash, Pred, Allocator>&& other);
|
||||
```
|
||||
|
||||
Move construction from a xref:#concurrent_flat_set[`concurrent_flat_set`].
|
||||
The internal bucket array of `other` is transferred directly to the new container.
|
||||
The hash function, predicate and allocator are moved-constructed from `other`.
|
||||
|
||||
[horizontal]
|
||||
Complexity:;; Constant time.
|
||||
Concurrency:;; Blocking on `other`.
|
||||
|
||||
---
|
||||
|
||||
==== Initializer List Constructor
|
||||
[source,c++,subs="+quotes"]
|
||||
----
|
||||
@@ -565,8 +581,9 @@ 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::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
noexcept((boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);
|
||||
```
|
||||
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`.
|
||||
@@ -1087,7 +1104,7 @@ void rehash(size_type n);
|
||||
|
||||
Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed.
|
||||
|
||||
Invalidates iterators, pointers and references, and changes the order of elements.
|
||||
|
||||
@@ -1201,4 +1218,54 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_flat_set``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_flat_set to an archive
|
||||
|
||||
Saves all the elements of an `unordered_flat_set` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type`
|
||||
is serializable (XML serializable), and it supports Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_flat_set from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_flat_set` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_flat_set` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_flat_set` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_flat_set` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace boost {
|
||||
using hasher = Hash;
|
||||
using key_equal = Pred;
|
||||
using allocator_type = Allocator;
|
||||
using pointer = typename boost::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename boost::allocator_traits<Allocator>::const_pointer;
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = _implementation-defined_;
|
||||
using difference_type = _implementation-defined_;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = _implementation-defined_;
|
||||
using const_iterator = _implementation-defined_;
|
||||
@@ -316,6 +316,7 @@ namespace boost {
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -323,51 +324,15 @@ The elements are organized into buckets. Keys with the same hash code are stored
|
||||
|
||||
The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash.
|
||||
|
||||
---
|
||||
=== Configuration macros
|
||||
|
||||
==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
|
||||
Globally define this macro to support loading of ``unordered_map``s saved to
|
||||
a Boost.Serialization archive with a version of Boost prior to Boost 1.84.
|
||||
|
||||
=== Typedefs
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::pointer pointer;
|
||||
----
|
||||
|
||||
`value_type*` if `allocator_type::pointer` is not defined.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::const_pointer const_pointer;
|
||||
----
|
||||
|
||||
`boost::pointer_to_other<pointer, value_type>::type` if `allocator_type::const_pointer` is not defined.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ size_type;
|
||||
----
|
||||
|
||||
An unsigned integral type.
|
||||
|
||||
`size_type` can represent any non-negative value of `difference_type`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ difference_type;
|
||||
----
|
||||
|
||||
A signed integral type.
|
||||
|
||||
Is identical to the difference type of `iterator` and `const_iterator`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ iterator;
|
||||
@@ -419,7 +384,8 @@ A const_local_iterator object can be used to iterate through a single bucket.
|
||||
typedef _implementation-defined_ node_type;
|
||||
----
|
||||
|
||||
See node_handle_map for details.
|
||||
A class for holding extracted container elements, modelling
|
||||
https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle].
|
||||
|
||||
---
|
||||
|
||||
@@ -428,7 +394,20 @@ See node_handle_map for details.
|
||||
typedef _implementation-defined_ insert_return_type;
|
||||
----
|
||||
|
||||
Structure returned by inserting node_type.
|
||||
A specialization of an internal class template:
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
template<class Iterator, class NodeType>
|
||||
struct _insert_return_type_ // name is exposition only
|
||||
{
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
----
|
||||
|
||||
with `Iterator` = `iterator` and `NodeType` = `node_type`.
|
||||
|
||||
---
|
||||
|
||||
@@ -508,10 +487,7 @@ The move constructor.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; This is implemented using Boost.Move.
|
||||
Requires:;; `value_type` is move-constructible. +
|
||||
+
|
||||
On compilers without rvalue reference support the emulation does not support moving without calling `boost::move` if `value_type` is not copyable.
|
||||
So, for example, you can't return the container from a function.
|
||||
Requires:;; `value_type` is move-constructible.
|
||||
|
||||
---
|
||||
|
||||
@@ -711,7 +687,6 @@ The move assignment operator.
|
||||
If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; On compilers without rvalue references, this is emulated using Boost.Move. Note that on some compilers the copy assignment operator may be used in some circumstances.
|
||||
Requires:;; `value_type` is move constructible.
|
||||
|
||||
---
|
||||
@@ -822,11 +797,7 @@ 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -847,11 +818,7 @@ 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -1029,13 +996,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -1045,10 +1012,6 @@ 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`.
|
||||
--
|
||||
|
||||
---
|
||||
@@ -1078,13 +1041,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -1096,10 +1059,6 @@ 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`.
|
||||
--
|
||||
|
||||
---
|
||||
@@ -1116,19 +1075,19 @@ template<class K, class M>
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -1156,19 +1115,19 @@ template<class K, class M>
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted.
|
||||
@@ -1761,9 +1720,7 @@ template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1777,9 +1734,7 @@ template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
=== Swap
|
||||
```c++
|
||||
@@ -1825,4 +1780,59 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_map``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_map to an archive
|
||||
|
||||
Saves all the elements of an `unordered_map` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `std::remove_const<key_type>::type` and `std::remove_const<mapped_type>::type`
|
||||
are serializable (XML serializable), and they do support Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_map from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_map` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_map` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^]
|
||||
from `(std::remove_const<key_type>::type&&, std::remove_const<mapped_type>::type&&)`.
|
||||
`x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
Note:;; If the archive was saved using a release of Boost prior to Boost 1.84,
|
||||
the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
has to be globally defined for this operation to succeed; otherwise, an exception is thrown.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_map` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_map` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -26,12 +26,12 @@ namespace boost {
|
||||
using hasher = Hash;
|
||||
using key_equal = Pred;
|
||||
using allocator_type = Allocator;
|
||||
using pointer = typename boost::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename boost::allocator_traits<Allocator>::const_pointer;
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = _implementation-defined_;
|
||||
using difference_type = _implementation-defined_;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = _implementation-defined_;
|
||||
using const_iterator = _implementation-defined_;
|
||||
@@ -283,6 +283,7 @@ namespace boost {
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -290,49 +291,15 @@ The elements are organized into buckets. Keys with the same hash code are stored
|
||||
|
||||
The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash.
|
||||
|
||||
=== Configuration macros
|
||||
|
||||
==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
|
||||
Globally define this macro to support loading of ``unordered_multimap``s saved to
|
||||
a Boost.Serialization archive with a version of Boost prior to Boost 1.84.
|
||||
|
||||
=== Typedefs
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::pointer pointer;
|
||||
----
|
||||
|
||||
`value_type*` if `allocator_type::pointer` is not defined.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::const_pointer const_pointer;
|
||||
----
|
||||
|
||||
`boost::pointer_to_other<pointer, value_type>::type` if `allocator_type::const_pointer` is not defined.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ size_type;
|
||||
----
|
||||
|
||||
An unsigned integral type.
|
||||
|
||||
`size_type` can represent any non-negative value of `difference_type`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ difference_type;
|
||||
----
|
||||
|
||||
A signed integral type.
|
||||
|
||||
Is identical to the difference type of `iterator` and `const_iterator`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ iterator;
|
||||
@@ -464,10 +431,7 @@ The move constructor.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; This is implemented using Boost.Move.
|
||||
Requires:;; `value_type` is move-constructible. +
|
||||
+
|
||||
On compilers without rvalue reference support the emulation does not support moving without calling `boost::move` if `value_type` is not copyable.
|
||||
So, for example, you can't return the container from a function.
|
||||
Requires:;; `value_type` is move-constructible.
|
||||
|
||||
---
|
||||
|
||||
@@ -666,7 +630,6 @@ The move assignment operator.
|
||||
If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; On compilers without rvalue references, this is emulated using Boost.Move. Note that on some compilers the copy assignment operator may be used in some circumstances.
|
||||
Requires:;; `value_type` is move constructible.
|
||||
|
||||
---
|
||||
@@ -775,11 +738,7 @@ Returns:;; An iterator pointing to the 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -800,11 +759,7 @@ 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -1486,9 +1441,7 @@ template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
Return `true` if `x.size() == y.size()` and for every equivalent key group in `x`, there is a group in `y` for the same key, which is a permutation (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1502,9 +1455,7 @@ template<class Key, class T, class Hash, class Pred, class Alloc>
|
||||
Return `false` if `x.size() == y.size()` and for every equivalent key group in `x`, there is a group in `y` for the same key, which is a permutation (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1552,4 +1503,59 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_multimap``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_multimap to an archive
|
||||
|
||||
Saves all the elements of an `unordered_multimap` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `std::remove_const<key_type>::type` and `std::remove_const<mapped_type>::type`
|
||||
are serializable (XML serializable), and they do support Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_multimap from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_multimap` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_multimap` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^]
|
||||
from `(std::remove_const<key_type>::type&&, std::remove_const<mapped_type>::type&&)`.
|
||||
`x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
Note:;; If the archive was saved using a release of Boost prior to Boost 1.84,
|
||||
the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
has to be globally defined for this operation to succeed; otherwise, an exception is thrown.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_multimap` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_multimap` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -24,12 +24,12 @@ namespace boost {
|
||||
using hasher = Hash;
|
||||
using key_equal = Pred;
|
||||
using allocator_type = Allocator;
|
||||
using pointer = typename boost::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename boost::allocator_traits<Allocator>::const_pointer;
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = _implementation-defined_;
|
||||
using difference_type = _implementation-defined_;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = _implementation-defined_;
|
||||
using const_iterator = _implementation-defined_;
|
||||
@@ -271,6 +271,7 @@ namespace boost {
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -278,50 +279,15 @@ The elements are organized into buckets. Keys with the same hash code are stored
|
||||
|
||||
The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash.
|
||||
|
||||
---
|
||||
=== Configuration macros
|
||||
|
||||
==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
|
||||
Globally define this macro to support loading of ``unordered_multiset``s saved to
|
||||
a Boost.Serialization archive with a version of Boost prior to Boost 1.84.
|
||||
|
||||
=== Typedefs
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::pointer pointer;
|
||||
----
|
||||
|
||||
`value_type*` if `allocator_type::pointer` is not defined.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::const_pointer const_pointer;
|
||||
----
|
||||
|
||||
`boost::pointer_to_other<pointer, value_type>::type` if `allocator_type::const_pointer` is not defined.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ size_type;
|
||||
----
|
||||
|
||||
An unsigned integral type.
|
||||
|
||||
`size_type` can represent any non-negative value of `difference_type`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ difference_type;
|
||||
----
|
||||
|
||||
A signed integral type.
|
||||
|
||||
Is identical to the difference type of `iterator` and `const_iterator`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ iterator;
|
||||
@@ -453,10 +419,7 @@ The move constructor.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; This is implemented using Boost.Move.
|
||||
Requires:;; `value_type` is move-constructible. +
|
||||
+
|
||||
On compilers without rvalue reference support the emulation does not support moving without calling `boost::move` if `value_type` is not copyable.
|
||||
So, for example, you can't return the container from a function.
|
||||
Requires:;; `value_type` is move-constructible.
|
||||
|
||||
---
|
||||
|
||||
@@ -656,7 +619,6 @@ The move assignment operator.
|
||||
If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; On compilers without rvalue references, this is emulated using Boost.Move. Note that on some compilers the copy assignment operator may be used in some circumstances.
|
||||
Requires:;; `value_type` is move constructible.
|
||||
|
||||
---
|
||||
@@ -767,11 +729,7 @@ Returns:;; An iterator pointing to the 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -792,11 +750,7 @@ 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -1419,9 +1373,7 @@ template<class Key, class Hash, class Pred, class Alloc>
|
||||
Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1435,9 +1387,7 @@ template<class Key, class Hash, class Pred, class Alloc>
|
||||
Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1485,4 +1435,58 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_multiset``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_multiset to an archive
|
||||
|
||||
Saves all the elements of an `unordered_multiset` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type`
|
||||
is serializable (XML serializable), and it supports Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_multiset from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_multiset` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_multiset` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
`x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
Note:;; If the archive was saved using a release of Boost prior to Boost 1.84,
|
||||
the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
has to be globally defined for this operation to succeed; otherwise, an exception is thrown.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_multiset` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_multiset` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -95,9 +95,10 @@ namespace boost {
|
||||
const allocator_type& a);
|
||||
xref:#unordered_node_map_destructor[~unordered_node_map]();
|
||||
unordered_node_map& xref:#unordered_node_map_copy_assignment[operator++=++](const unordered_node_map& other);
|
||||
unordered_node_map& xref:#unordered_node_map_move_assignment[operator++=++](unordered_node_map&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
unordered_node_map& xref:#unordered_node_map_move_assignment[operator++=++](unordered_node_map&& other) ++noexcept(
|
||||
(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);++
|
||||
unordered_node_map& xref:#unordered_node_map_initializer_list_assignment[operator++=++](std::initializer_list<value_type>);
|
||||
allocator_type xref:#unordered_node_map_get_allocator[get_allocator]() const noexcept;
|
||||
|
||||
@@ -314,8 +315,7 @@ https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the contain
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
`std::allocator_traits<Allocator>::pointer` and `std::allocator_traits<Allocator>::const_pointer`
|
||||
must be convertible to/from `value_type*` and `const value_type*`, respectively.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -649,8 +649,9 @@ Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInse
|
||||
==== Move Assignment
|
||||
```c++
|
||||
unordered_node_map& operator=(unordered_node_map&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
noexcept((boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);
|
||||
```
|
||||
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`.
|
||||
@@ -961,13 +962,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#unordered_node_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -1006,13 +1007,13 @@ 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)...))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)...))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<Args>(args)...))
|
||||
```
|
||||
|
||||
unlike xref:#unordered_node_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor.
|
||||
@@ -1037,19 +1038,19 @@ template<class K, class M>
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
[horizontal]
|
||||
@@ -1075,19 +1076,19 @@ template<class K, class M>
|
||||
|
||||
Inserts a new element into the container or updates an existing one by assigning to the contained value.
|
||||
|
||||
If there is an element with key `k`, then it is updated by assigning `boost::forward<M>(obj)`.
|
||||
If there is an element with key `k`, then it is updated by assigning `std::forward<M>(obj)`.
|
||||
|
||||
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)))
|
||||
std::forward_as_tuple(std::forward<Key>(k)),
|
||||
std::forward_as_tuple(std::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)))
|
||||
std::forward_as_tuple(std::forward<K>(k)),
|
||||
std::forward_as_tuple(std::forward<M>(obj)))
|
||||
```
|
||||
|
||||
`hint` is a suggestion to where the element should be inserted. This implementation ignores it.
|
||||
@@ -1406,7 +1407,7 @@ void rehash(size_type n);
|
||||
|
||||
Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed.
|
||||
|
||||
Invalidates iterators and changes the order of elements.
|
||||
|
||||
@@ -1545,4 +1546,57 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_node_map``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_node_map to an archive
|
||||
|
||||
Saves all the elements of an `unordered_node_map` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `std::remove_const<key_type>::type` and `std::remove_const<mapped_type>::type`
|
||||
are serializable (XML serializable), and they do support Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_node_map from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_node_map` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_node_map` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `key_type` and `mapped_type` are constructible from
|
||||
`std::remove_const<key_type>::type&&` and `std::remove_const<mapped_type>::type&&`,
|
||||
respectively.
|
||||
`x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_node_map` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_node_map` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -90,9 +90,10 @@ namespace boost {
|
||||
const allocator_type& a);
|
||||
xref:#unordered_node_set_destructor[~unordered_node_set]();
|
||||
unordered_node_set& xref:#unordered_node_set_copy_assignment[operator++=++](const unordered_node_set& other);
|
||||
unordered_node_set& xref:#unordered_node_set_move_assignment[operator++=++](unordered_node_set&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
unordered_node_set& xref:#unordered_node_set_move_assignment[operator++=++](unordered_node_set&& other) ++noexcept(
|
||||
(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);++
|
||||
unordered_node_set& xref:#unordered_node_set_initializer_list_assignment[operator++=++](std::initializer_list<value_type>);
|
||||
allocator_type xref:#unordered_node_set_get_allocator[get_allocator]() const noexcept;
|
||||
|
||||
@@ -264,8 +265,7 @@ namespace boost {
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
`std::allocator_traits<Allocator>::pointer` and `std::allocator_traits<Allocator>::const_pointer`
|
||||
must be convertible to/from `value_type*` and `const value_type*`, respectively.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -602,8 +602,9 @@ Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInse
|
||||
==== Move Assignment
|
||||
```c++
|
||||
unordered_node_set& operator=(unordered_node_set&& other)
|
||||
noexcept(boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value);
|
||||
noexcept((boost::allocator_traits<Allocator>::is_always_equal::value ||
|
||||
boost::allocator_traits<Allocator>::propagate_on_container_move_assignment::value) &&
|
||||
std::is_same<pointer, value_type*>::value);
|
||||
```
|
||||
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`.
|
||||
@@ -1188,7 +1189,7 @@ void rehash(size_type n);
|
||||
|
||||
Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container.
|
||||
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array.
|
||||
When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed.
|
||||
|
||||
Invalidates iterators and changes the order of elements.
|
||||
|
||||
@@ -1302,4 +1303,55 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_node_set``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_node_set to an archive
|
||||
|
||||
Saves all the elements of an `unordered_node_set` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type`
|
||||
is serializable (XML serializable), and it supports Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_node_set from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_node_set` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_node_set` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
`x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_node_set` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_node_set` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -24,12 +24,12 @@ namespace boost {
|
||||
using hasher = Hash;
|
||||
using key_equal = Pred;
|
||||
using allocator_type = Allocator;
|
||||
using pointer = typename boost::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename boost::allocator_traits<Allocator>::const_pointer;
|
||||
using pointer = typename std::allocator_traits<Allocator>::pointer;
|
||||
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
|
||||
using reference = value_type&;
|
||||
using const_reference = const value_type&;
|
||||
using size_type = _implementation-defined_;
|
||||
using difference_type = _implementation-defined_;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
|
||||
using iterator = _implementation-defined_;
|
||||
using const_iterator = _implementation-defined_;
|
||||
@@ -272,6 +272,7 @@ namespace boost {
|
||||
|
||||
|_Allocator_
|
||||
|An allocator whose value type is the same as the container's value type.
|
||||
Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported.
|
||||
|
||||
|===
|
||||
|
||||
@@ -279,51 +280,15 @@ The elements are organized into buckets. Keys with the same hash code are stored
|
||||
|
||||
The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash.
|
||||
|
||||
---
|
||||
=== Configuration macros
|
||||
|
||||
==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
|
||||
Globally define this macro to support loading of ``unordered_set``s saved to
|
||||
a Boost.Serialization archive with a version of Boost prior to Boost 1.84.
|
||||
|
||||
=== Typedefs
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::pointer pointer;
|
||||
----
|
||||
|
||||
`value_type*` if `allocator_type::pointer` is not defined.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef typename allocator_type::const_pointer const_pointer;
|
||||
----
|
||||
|
||||
`boost::pointer_to_other<pointer, value_type>::type` if `allocator_type::const_pointer` is not defined.
|
||||
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ size_type;
|
||||
----
|
||||
|
||||
An unsigned integral type.
|
||||
|
||||
`size_type` can represent any non-negative value of `difference_type`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ difference_type;
|
||||
----
|
||||
|
||||
A signed integral type.
|
||||
|
||||
Is identical to the difference type of `iterator` and `const_iterator`.
|
||||
|
||||
---
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
typedef _implementation-defined_ iterator;
|
||||
@@ -375,7 +340,8 @@ A const_local_iterator object can be used to iterate through a single bucket.
|
||||
typedef _implementation-defined_ node_type;
|
||||
----
|
||||
|
||||
See node_handle_set for details.
|
||||
A class for holding extracted container elements, modelling
|
||||
https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle].
|
||||
|
||||
---
|
||||
|
||||
@@ -384,7 +350,20 @@ See node_handle_set for details.
|
||||
typedef _implementation-defined_ insert_return_type;
|
||||
----
|
||||
|
||||
Structure returned by inserting node_type.
|
||||
A specialization of an internal class template:
|
||||
|
||||
[source,c++,subs=+quotes]
|
||||
----
|
||||
template<class Iterator, class NodeType>
|
||||
struct _insert_return_type_ // name is exposition only
|
||||
{
|
||||
Iterator position;
|
||||
bool inserted;
|
||||
NodeType node;
|
||||
};
|
||||
----
|
||||
|
||||
with `Iterator` = `iterator` and `NodeType` = `node_type`.
|
||||
|
||||
---
|
||||
|
||||
@@ -464,10 +443,7 @@ The move constructor.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; This is implemented using Boost.Move.
|
||||
Requires:;; `value_type` is move-constructible. +
|
||||
+
|
||||
On compilers without rvalue reference support the emulation does not support moving without calling `boost::move` if `value_type` is not copyable.
|
||||
So, for example, you can't return the container from a function.
|
||||
Requires:;; `value_type` is move-constructible.
|
||||
|
||||
---
|
||||
|
||||
@@ -667,7 +643,6 @@ The move assignment operator.
|
||||
If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator.
|
||||
|
||||
[horizontal]
|
||||
Notes:;; On compilers without rvalue references, this is emulated using Boost.Move. Note that on some compilers the copy assignment operator may be used in some circumstances.
|
||||
Requires:;; `value_type` is move constructible.
|
||||
|
||||
---
|
||||
@@ -780,11 +755,7 @@ 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -805,11 +776,7 @@ 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. +
|
||||
+
|
||||
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`.
|
||||
Pointers and references to elements are never invalidated.
|
||||
|
||||
---
|
||||
|
||||
@@ -1484,9 +1451,7 @@ template<class Key, class Hash, class Pred, class Alloc>
|
||||
Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1500,9 +1465,7 @@ template<class Key, class Hash, class Pred, class Alloc>
|
||||
Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types).
|
||||
|
||||
[horizontal]
|
||||
Notes:;; The behavior of this function was changed to match the C++11 standard in Boost 1.48. +
|
||||
+
|
||||
Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates.
|
||||
|
||||
---
|
||||
|
||||
@@ -1550,4 +1513,58 @@ for (auto i = c.begin(), last = c.end(); i != last; ) {
|
||||
return original_size - c.size();
|
||||
```
|
||||
|
||||
=== Serialization
|
||||
|
||||
``unordered_set``s can be archived/retrieved by means of
|
||||
link:../../../serialization/index.html[Boost.Serialization^] using the API provided
|
||||
by this library. Both regular and XML archives are supported.
|
||||
|
||||
==== Saving an unordered_set to an archive
|
||||
|
||||
Saves all the elements of an `unordered_set` `x` to an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type`
|
||||
is serializable (XML serializable), and it supports Boost.Serialization
|
||||
`save_construct_data`/`load_construct_data` protocol (automatically suported by
|
||||
https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]
|
||||
types).
|
||||
|
||||
---
|
||||
|
||||
==== Loading an unordered_set from an archive
|
||||
|
||||
Deletes all preexisting elements of an `unordered_set` `x` and inserts
|
||||
from an archive (XML archive) `ar` restored copies of the elements of the
|
||||
original `unordered_set` `other` saved to the storage read by `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^].
|
||||
`x.key_equal()` is functionally equivalent to `other.key_equal()`.
|
||||
Note:;; If the archive was saved using a release of Boost prior to Boost 1.84,
|
||||
the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0`
|
||||
has to be globally defined for this operation to succeed; otherwise, an exception is thrown.
|
||||
|
||||
---
|
||||
|
||||
==== Saving an iterator/const_iterator to an archive
|
||||
|
||||
Saves the positional information of an `iterator` (`const_iterator`) `it`
|
||||
to an archive (XML archive) `ar`. `it` can be and `end()` iterator.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; The `unordered_set` `x` pointed to by `it` has been previously saved to `ar`,
|
||||
and no modifying operations have been issued on `x` between saving of `x` and
|
||||
saving of `it`.
|
||||
|
||||
---
|
||||
|
||||
==== Loading an iterator/const_iterator from an archive
|
||||
|
||||
Makes an `iterator` (`const_iterator`) `it` point to the restored position of
|
||||
the original `iterator` (`const_iterator`) saved to the storage read by
|
||||
an archive (XML archive) `ar`.
|
||||
|
||||
[horizontal]
|
||||
Requires:;; If `x` is the `unordered_set` `it` points to, no modifying operations
|
||||
have been issued on `x` between loading of `x` and loading of `it`.
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
#define BOOST_HASH_EXAMPLES_CASE_INSENSITIVE_HEADER
|
||||
|
||||
#include <boost/algorithm/string/predicate.hpp>
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
|
||||
namespace hash_examples
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
/* Fast open-addressing concurrent hash table.
|
||||
/* Fast open-addressing concurrent hashmap.
|
||||
*
|
||||
* Copyright 2023 Christian Mazakas.
|
||||
* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
@@ -12,71 +13,20 @@
|
||||
#define BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP
|
||||
|
||||
#include <boost/unordered/concurrent_flat_map_fwd.hpp>
|
||||
#include <boost/unordered/detail/concurrent_static_asserts.hpp>
|
||||
#include <boost/unordered/detail/foa/concurrent_table.hpp>
|
||||
#include <boost/unordered/detail/foa/flat_map_types.hpp>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
#include <boost/unordered/unordered_flat_map_fwd.hpp>
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
#include <boost/type_traits/type_identity.hpp>
|
||||
#include <boost/core/serialization.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \
|
||||
static_assert(boost::unordered::detail::is_invocable<F, value_type&>::value, \
|
||||
"The provided Callable must be invocable with value_type&");
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) \
|
||||
static_assert( \
|
||||
boost::unordered::detail::is_invocable<F, value_type const&>::value, \
|
||||
"The provided Callable must be invocable with value_type const&");
|
||||
|
||||
#if BOOST_CXX_VERSION >= 202002L
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \
|
||||
static_assert(!std::is_base_of<std::execution::parallel_unsequenced_policy, \
|
||||
ExecPolicy>::value, \
|
||||
"ExecPolicy must be sequenced."); \
|
||||
static_assert( \
|
||||
!std::is_base_of<std::execution::unsequenced_policy, ExecPolicy>::value, \
|
||||
"ExecPolicy must be sequenced.");
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \
|
||||
static_assert(!std::is_base_of<std::execution::parallel_unsequenced_policy, \
|
||||
ExecPolicy>::value, \
|
||||
"ExecPolicy must be sequenced.");
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_COMMA ,
|
||||
|
||||
#define BOOST_UNORDERED_LAST_ARG(Arg, Args) \
|
||||
mp11::mp_back<mp11::mp_list<Arg BOOST_UNORDERED_COMMA Args> >
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(BOOST_UNORDERED_LAST_ARG(Arg, Args))
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \
|
||||
BOOST_UNORDERED_LAST_ARG(Arg, Args))
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <class F, class... Args>
|
||||
struct is_invocable
|
||||
: std::is_constructible<std::function<void(Args...)>,
|
||||
std::reference_wrapper<typename std::remove_reference<F>::type> >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class Key, class T, class Hash, class Pred, class Allocator>
|
||||
class concurrent_flat_map
|
||||
{
|
||||
@@ -84,10 +34,16 @@ namespace boost {
|
||||
template <class Key2, class T2, class Hash2, class Pred2,
|
||||
class Allocator2>
|
||||
friend class concurrent_flat_map;
|
||||
template <class Key2, class T2, class Hash2, class Pred2,
|
||||
class Allocator2>
|
||||
friend class unordered_flat_map;
|
||||
|
||||
using type_policy = detail::foa::flat_map_types<Key, T>;
|
||||
|
||||
detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator> table_;
|
||||
using table_type =
|
||||
detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
|
||||
|
||||
table_type table_;
|
||||
|
||||
template <class K, class V, class H, class KE, class A>
|
||||
bool friend operator==(concurrent_flat_map<K, V, H, KE, A> const& lhs,
|
||||
@@ -97,6 +53,11 @@ namespace boost {
|
||||
friend typename concurrent_flat_map<K, V, H, KE, A>::size_type erase_if(
|
||||
concurrent_flat_map<K, V, H, KE, A>& set, Predicate pred);
|
||||
|
||||
template<class Archive, class K, class V, class H, class KE, class A>
|
||||
friend void serialize(
|
||||
Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c,
|
||||
unsigned int version);
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
@@ -104,14 +65,15 @@ namespace boost {
|
||||
using init_type = typename type_policy::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<Pred>::type;
|
||||
using allocator_type = typename boost::type_identity<Allocator>::type;
|
||||
using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
|
||||
using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
|
||||
using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = typename boost::allocator_pointer<allocator_type>::type;
|
||||
using const_pointer =
|
||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||
static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
|
||||
|
||||
concurrent_flat_map()
|
||||
: concurrent_flat_map(detail::foa::default_bucket_count)
|
||||
@@ -223,6 +185,13 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
concurrent_flat_map(
|
||||
unordered_flat_map<Key, T, Hash, Pred, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
{
|
||||
}
|
||||
|
||||
~concurrent_flat_map() = default;
|
||||
|
||||
concurrent_flat_map& operator=(concurrent_flat_map const& rhs)
|
||||
@@ -231,10 +200,8 @@ namespace boost {
|
||||
return *this;
|
||||
}
|
||||
|
||||
concurrent_flat_map& operator=(concurrent_flat_map&& rhs)
|
||||
noexcept(boost::allocator_is_always_equal<Allocator>::type::value ||
|
||||
boost::allocator_propagate_on_container_move_assignment<
|
||||
Allocator>::type::value)
|
||||
concurrent_flat_map& operator=(concurrent_flat_map&& rhs) noexcept(
|
||||
noexcept(std::declval<table_type&>() = std::declval<table_type&&>()))
|
||||
{
|
||||
table_ = std::move(rhs.table_);
|
||||
return *this;
|
||||
@@ -305,6 +272,33 @@ namespace boost {
|
||||
return table_.visit(std::forward<K>(k), f);
|
||||
}
|
||||
|
||||
template<class FwdIterator, class F>
|
||||
BOOST_FORCEINLINE
|
||||
size_t visit(FwdIterator first, FwdIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
return table_.visit(first, last, f);
|
||||
}
|
||||
|
||||
template<class FwdIterator, class F>
|
||||
BOOST_FORCEINLINE
|
||||
size_t visit(FwdIterator first, FwdIterator last, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(first, last, f);
|
||||
}
|
||||
|
||||
template<class FwdIterator, class F>
|
||||
BOOST_FORCEINLINE
|
||||
size_t cvisit(FwdIterator first, FwdIterator last, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(first, last, f);
|
||||
}
|
||||
|
||||
template <class F> size_type visit_all(F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
@@ -355,6 +349,56 @@ namespace boost {
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class F> bool visit_while(F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
return table_.visit_while(f);
|
||||
}
|
||||
|
||||
template <class F> bool visit_while(F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit_while(f);
|
||||
}
|
||||
|
||||
template <class F> bool cvisit_while(F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.cvisit_while(f);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
bool>::type
|
||||
visit_while(ExecPolicy&& p, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
return table_.visit_while(p, f);
|
||||
}
|
||||
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
bool>::type
|
||||
visit_while(ExecPolicy&& p, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
return table_.visit_while(p, f);
|
||||
}
|
||||
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
bool>::type
|
||||
cvisit_while(ExecPolicy&& p, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
return table_.cvisit_while(p, f);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Modifiers
|
||||
///
|
||||
|
||||
@@ -411,6 +455,7 @@ namespace boost {
|
||||
BOOST_FORCEINLINE auto insert_or_visit(Ty&& value, F f)
|
||||
-> decltype(table_.insert_or_visit(std::forward<Ty>(value), f))
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F)
|
||||
return table_.insert_or_visit(std::forward<Ty>(value), f);
|
||||
}
|
||||
|
||||
@@ -465,7 +510,7 @@ namespace boost {
|
||||
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_visit(ilist.begin(), ilist.end(), f);
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
@@ -662,7 +707,7 @@ namespace boost {
|
||||
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(); }
|
||||
|
||||
@@ -711,6 +756,13 @@ namespace boost {
|
||||
return c.table_.erase_if(pred);
|
||||
}
|
||||
|
||||
template<class Archive, class K, class V, class H, class KE, class A>
|
||||
void serialize(
|
||||
Archive& ar, concurrent_flat_map<K, V, H, KE, A>& c, unsigned int)
|
||||
{
|
||||
ar & core::make_nvp("table",c.table_);
|
||||
}
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
|
||||
template <class InputIterator,
|
||||
@@ -720,10 +772,10 @@ namespace boost {
|
||||
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> > >
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(InputIterator, InputIterator,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
@@ -733,21 +785,21 @@ namespace boost {
|
||||
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 Hash = boost::hash<std::remove_const_t<Key> >,
|
||||
class Pred = std::equal_to<std::remove_const_t<Key> >,
|
||||
class Allocator = std::allocator<std::pair<const Key, T> >,
|
||||
class = 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> > >
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(std::initializer_list<std::pair<Key, T> >,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> concurrent_flat_map<boost::remove_const_t<Key>, T, Hash, Pred,
|
||||
-> concurrent_flat_map<std::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> > >
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(InputIterator, InputIterator, std::size_t, Allocator)
|
||||
-> concurrent_flat_map<
|
||||
boost::unordered::detail::iter_key_t<InputIterator>,
|
||||
@@ -757,8 +809,8 @@ namespace boost {
|
||||
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> > >
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(InputIterator, InputIterator, Allocator)
|
||||
-> concurrent_flat_map<
|
||||
boost::unordered::detail::iter_key_t<InputIterator>,
|
||||
@@ -768,9 +820,9 @@ namespace boost {
|
||||
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> > >
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(
|
||||
InputIterator, InputIterator, std::size_t, Hash, Allocator)
|
||||
-> concurrent_flat_map<
|
||||
@@ -780,25 +832,25 @@ namespace boost {
|
||||
Allocator>;
|
||||
|
||||
template <class Key, class T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
|
||||
Allocator) -> concurrent_flat_map<boost::remove_const_t<Key>, T,
|
||||
boost::hash<boost::remove_const_t<Key> >,
|
||||
std::equal_to<boost::remove_const_t<Key> >, Allocator>;
|
||||
Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
|
||||
boost::hash<std::remove_const_t<Key> >,
|
||||
std::equal_to<std::remove_const_t<Key> >, Allocator>;
|
||||
|
||||
template <class Key, class T, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, Allocator)
|
||||
-> concurrent_flat_map<boost::remove_const_t<Key>, T,
|
||||
boost::hash<boost::remove_const_t<Key> >,
|
||||
std::equal_to<boost::remove_const_t<Key> >, Allocator>;
|
||||
-> concurrent_flat_map<std::remove_const_t<Key>, T,
|
||||
boost::hash<std::remove_const_t<Key> >,
|
||||
std::equal_to<std::remove_const_t<Key> >, Allocator>;
|
||||
|
||||
template <class Key, class T, class Hash, class Allocator,
|
||||
class = boost::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = boost::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_map(std::initializer_list<std::pair<Key, T> >, std::size_t,
|
||||
Hash, Allocator) -> concurrent_flat_map<boost::remove_const_t<Key>, T,
|
||||
Hash, std::equal_to<boost::remove_const_t<Key> >, Allocator>;
|
||||
Hash, Allocator) -> concurrent_flat_map<std::remove_const_t<Key>, T,
|
||||
Hash, std::equal_to<std::remove_const_t<Key> >, Allocator>;
|
||||
|
||||
#endif
|
||||
|
||||
@@ -807,12 +859,4 @@ namespace boost {
|
||||
using unordered::concurrent_flat_map;
|
||||
} // namespace boost
|
||||
|
||||
#undef BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE
|
||||
#undef BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE
|
||||
#undef BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY
|
||||
#undef BOOST_UNORDERED_COMMA
|
||||
#undef BOOST_UNORDERED_LAST_ARG
|
||||
#undef BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE
|
||||
#undef BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE
|
||||
|
||||
#endif // BOOST_UNORDERED_CONCURRENT_FLAT_MAP_HPP
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
/* Fast open-addressing concurrent hash table.
|
||||
/* Fast open-addressing concurrent hashmap.
|
||||
*
|
||||
* Copyright 2023 Christian Mazakas.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
/* Fast open-addressing concurrent hashset.
|
||||
*
|
||||
* Copyright 2023 Christian Mazakas.
|
||||
* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
|
||||
#define BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
|
||||
|
||||
#include <boost/unordered/concurrent_flat_set_fwd.hpp>
|
||||
#include <boost/unordered/detail/concurrent_static_asserts.hpp>
|
||||
#include <boost/unordered/detail/foa/concurrent_table.hpp>
|
||||
#include <boost/unordered/detail/foa/flat_set_types.hpp>
|
||||
#include <boost/unordered/detail/type_traits.hpp>
|
||||
#include <boost/unordered/unordered_flat_set_fwd.hpp>
|
||||
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/core/allocator_access.hpp>
|
||||
#include <boost/core/serialization.hpp>
|
||||
|
||||
#include <utility>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
template <class Key, class Hash, class Pred, class Allocator>
|
||||
class concurrent_flat_set
|
||||
{
|
||||
private:
|
||||
template <class Key2, class Hash2, class Pred2, class Allocator2>
|
||||
friend class concurrent_flat_set;
|
||||
template <class Key2, class Hash2, class Pred2, class Allocator2>
|
||||
friend class unordered_flat_set;
|
||||
|
||||
using type_policy = detail::foa::flat_set_types<Key>;
|
||||
|
||||
using table_type =
|
||||
detail::foa::concurrent_table<type_policy, Hash, Pred, Allocator>;
|
||||
|
||||
table_type table_;
|
||||
|
||||
template <class K, class H, class KE, class A>
|
||||
bool friend operator==(concurrent_flat_set<K, H, KE, A> const& lhs,
|
||||
concurrent_flat_set<K, H, KE, A> const& rhs);
|
||||
|
||||
template <class K, class H, class KE, class A, class Predicate>
|
||||
friend typename concurrent_flat_set<K, H, KE, A>::size_type erase_if(
|
||||
concurrent_flat_set<K, H, KE, A>& set, Predicate pred);
|
||||
|
||||
template<class Archive, class K, class H, class KE, class A>
|
||||
friend void serialize(
|
||||
Archive& ar, concurrent_flat_set<K, H, KE, A>& c,
|
||||
unsigned int version);
|
||||
|
||||
public:
|
||||
using key_type = Key;
|
||||
using value_type = typename type_policy::value_type;
|
||||
using init_type = typename type_policy::init_type;
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using hasher = typename boost::unordered::detail::type_identity<Hash>::type;
|
||||
using key_equal = typename boost::unordered::detail::type_identity<Pred>::type;
|
||||
using allocator_type = typename boost::unordered::detail::type_identity<Allocator>::type;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = typename boost::allocator_pointer<allocator_type>::type;
|
||||
using const_pointer =
|
||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||
static constexpr size_type bulk_visit_size = table_type::bulk_visit_size;
|
||||
|
||||
concurrent_flat_set()
|
||||
: concurrent_flat_set(detail::foa::default_bucket_count)
|
||||
{
|
||||
}
|
||||
|
||||
explicit concurrent_flat_set(size_type n, const hasher& hf = hasher(),
|
||||
const key_equal& eql = key_equal(),
|
||||
const allocator_type& a = allocator_type())
|
||||
: table_(n, hf, eql, a)
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
concurrent_flat_set(InputIterator f, InputIterator l,
|
||||
size_type n = detail::foa::default_bucket_count,
|
||||
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||
const allocator_type& a = allocator_type())
|
||||
: table_(n, hf, eql, a)
|
||||
{
|
||||
this->insert(f, l);
|
||||
}
|
||||
|
||||
concurrent_flat_set(concurrent_flat_set const& rhs)
|
||||
: table_(rhs.table_,
|
||||
boost::allocator_select_on_container_copy_construction(
|
||||
rhs.get_allocator()))
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(concurrent_flat_set&& rhs)
|
||||
: table_(std::move(rhs.table_))
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
concurrent_flat_set(
|
||||
InputIterator f, InputIterator l, allocator_type const& a)
|
||||
: concurrent_flat_set(f, l, 0, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
explicit concurrent_flat_set(allocator_type const& a)
|
||||
: table_(detail::foa::default_bucket_count, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(
|
||||
concurrent_flat_set const& rhs, allocator_type const& a)
|
||||
: table_(rhs.table_, a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(concurrent_flat_set&& rhs, allocator_type const& a)
|
||||
: table_(std::move(rhs.table_), a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(std::initializer_list<value_type> il,
|
||||
size_type n = detail::foa::default_bucket_count,
|
||||
const hasher& hf = hasher(), const key_equal& eql = key_equal(),
|
||||
const allocator_type& a = allocator_type())
|
||||
: concurrent_flat_set(n, hf, eql, a)
|
||||
{
|
||||
this->insert(il.begin(), il.end());
|
||||
}
|
||||
|
||||
concurrent_flat_set(size_type n, const allocator_type& a)
|
||||
: concurrent_flat_set(n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(
|
||||
size_type n, const hasher& hf, const allocator_type& a)
|
||||
: concurrent_flat_set(n, hf, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InputIterator>
|
||||
concurrent_flat_set(
|
||||
InputIterator f, InputIterator l, size_type n, const allocator_type& a)
|
||||
: concurrent_flat_set(f, l, n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename InputIterator>
|
||||
concurrent_flat_set(InputIterator f, InputIterator l, size_type n,
|
||||
const hasher& hf, const allocator_type& a)
|
||||
: concurrent_flat_set(f, l, n, hf, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(
|
||||
std::initializer_list<value_type> il, const allocator_type& a)
|
||||
: concurrent_flat_set(
|
||||
il, detail::foa::default_bucket_count, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(std::initializer_list<value_type> il, size_type n,
|
||||
const allocator_type& a)
|
||||
: concurrent_flat_set(il, n, hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
concurrent_flat_set(std::initializer_list<value_type> il, size_type n,
|
||||
const hasher& hf, const allocator_type& a)
|
||||
: concurrent_flat_set(il, n, hf, key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
concurrent_flat_set(
|
||||
unordered_flat_set<Key, Hash, Pred, Allocator>&& other)
|
||||
: table_(std::move(other.table_))
|
||||
{
|
||||
}
|
||||
|
||||
~concurrent_flat_set() = default;
|
||||
|
||||
concurrent_flat_set& operator=(concurrent_flat_set const& rhs)
|
||||
{
|
||||
table_ = rhs.table_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
concurrent_flat_set& operator=(concurrent_flat_set&& rhs)
|
||||
noexcept(boost::allocator_is_always_equal<Allocator>::type::value ||
|
||||
boost::allocator_propagate_on_container_move_assignment<
|
||||
Allocator>::type::value)
|
||||
{
|
||||
table_ = std::move(rhs.table_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
concurrent_flat_set& operator=(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
table_ = ilist;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/// Capacity
|
||||
///
|
||||
|
||||
size_type size() const noexcept { return table_.size(); }
|
||||
size_type max_size() const noexcept { return table_.max_size(); }
|
||||
|
||||
BOOST_ATTRIBUTE_NODISCARD bool empty() const noexcept
|
||||
{
|
||||
return size() == 0;
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE size_type visit(key_type const& k, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(k, f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE size_type cvisit(key_type const& k, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(k, f);
|
||||
}
|
||||
|
||||
template <class K, class F>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
visit(K&& k, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(std::forward<K>(k), f);
|
||||
}
|
||||
|
||||
template <class K, class F>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
cvisit(K&& k, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(std::forward<K>(k), f);
|
||||
}
|
||||
|
||||
template<class FwdIterator, class F>
|
||||
BOOST_FORCEINLINE
|
||||
size_t visit(FwdIterator first, FwdIterator last, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(first, last, f);
|
||||
}
|
||||
|
||||
template<class FwdIterator, class F>
|
||||
BOOST_FORCEINLINE
|
||||
size_t cvisit(FwdIterator first, FwdIterator last, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(FwdIterator)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit(first, last, f);
|
||||
}
|
||||
|
||||
template <class F> size_type visit_all(F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit_all(f);
|
||||
}
|
||||
|
||||
template <class F> size_type cvisit_all(F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.cvisit_all(f);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
void>::type
|
||||
visit_all(ExecPolicy&& p, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
table_.visit_all(p, f);
|
||||
}
|
||||
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
void>::type
|
||||
cvisit_all(ExecPolicy&& p, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
table_.cvisit_all(p, f);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class F> bool visit_while(F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.visit_while(f);
|
||||
}
|
||||
|
||||
template <class F> bool cvisit_while(F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.cvisit_while(f);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
bool>::type
|
||||
visit_while(ExecPolicy&& p, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
return table_.visit_while(p, f);
|
||||
}
|
||||
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
bool>::type
|
||||
cvisit_while(ExecPolicy&& p, F f) const
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
return table_.cvisit_while(p, f);
|
||||
}
|
||||
#endif
|
||||
|
||||
/// Modifiers
|
||||
///
|
||||
|
||||
BOOST_FORCEINLINE bool insert(value_type const& obj)
|
||||
{
|
||||
return table_.insert(obj);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool insert(value_type&& obj)
|
||||
{
|
||||
return table_.insert(std::move(obj));
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert(K&& k)
|
||||
{
|
||||
return table_.try_emplace(std::forward<K>(k));
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator begin, InputIterator end)
|
||||
{
|
||||
for (auto pos = begin; pos != end; ++pos) {
|
||||
table_.emplace(*pos);
|
||||
}
|
||||
}
|
||||
|
||||
void insert(std::initializer_list<value_type> ilist)
|
||||
{
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE bool insert_or_visit(value_type const& obj, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.insert_or_cvisit(obj, f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE bool insert_or_visit(value_type&& obj, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.insert_or_cvisit(std::move(obj), f);
|
||||
}
|
||||
|
||||
template <class K, class F>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert_or_visit(K&& k, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_visit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_or_cvisit(*first, f);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_visit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE bool insert_or_cvisit(value_type const& obj, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.insert_or_cvisit(obj, f);
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE bool insert_or_cvisit(value_type&& obj, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.insert_or_cvisit(std::move(obj), f);
|
||||
}
|
||||
|
||||
template <class K, class F>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value,
|
||||
bool >::type
|
||||
insert_or_cvisit(K&& k, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
return table_.try_emplace_or_cvisit(std::forward<K>(k), f);
|
||||
}
|
||||
|
||||
template <class InputIterator, class F>
|
||||
void insert_or_cvisit(InputIterator first, InputIterator last, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
for (; first != last; ++first) {
|
||||
table_.emplace_or_cvisit(*first, f);
|
||||
}
|
||||
}
|
||||
|
||||
template <class F>
|
||||
void insert_or_cvisit(std::initializer_list<value_type> ilist, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F)
|
||||
this->insert_or_cvisit(ilist.begin(), ilist.end(), f);
|
||||
}
|
||||
|
||||
template <class... Args> BOOST_FORCEINLINE bool emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_or_visit(Arg&& arg, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||
return table_.emplace_or_cvisit(
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class Arg, class... Args>
|
||||
BOOST_FORCEINLINE bool emplace_or_cvisit(Arg&& arg, Args&&... args)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args...)
|
||||
return table_.emplace_or_cvisit(
|
||||
std::forward<Arg>(arg), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& k)
|
||||
{
|
||||
return table_.erase(k);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
erase(K&& k)
|
||||
{
|
||||
return table_.erase(std::forward<K>(k));
|
||||
}
|
||||
|
||||
template <class F>
|
||||
BOOST_FORCEINLINE size_type erase_if(key_type const& k, F f)
|
||||
{
|
||||
return table_.erase_if(k, f);
|
||||
}
|
||||
|
||||
template <class K, class F>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value &&
|
||||
!detail::is_execution_policy<K>::value,
|
||||
size_type>::type
|
||||
erase_if(K&& k, F f)
|
||||
{
|
||||
return table_.erase_if(std::forward<K>(k), f);
|
||||
}
|
||||
|
||||
#if defined(BOOST_UNORDERED_PARALLEL_ALGORITHMS)
|
||||
template <class ExecPolicy, class F>
|
||||
typename std::enable_if<detail::is_execution_policy<ExecPolicy>::value,
|
||||
void>::type
|
||||
erase_if(ExecPolicy&& p, F f)
|
||||
{
|
||||
BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(ExecPolicy)
|
||||
table_.erase_if(p, f);
|
||||
}
|
||||
#endif
|
||||
|
||||
template <class F> size_type erase_if(F f) { return table_.erase_if(f); }
|
||||
|
||||
void swap(concurrent_flat_set& other) noexcept(
|
||||
boost::allocator_is_always_equal<Allocator>::type::value ||
|
||||
boost::allocator_propagate_on_container_swap<Allocator>::type::value)
|
||||
{
|
||||
return table_.swap(other.table_);
|
||||
}
|
||||
|
||||
void clear() noexcept { table_.clear(); }
|
||||
|
||||
template <typename H2, typename P2>
|
||||
size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>& x)
|
||||
{
|
||||
BOOST_ASSERT(get_allocator() == x.get_allocator());
|
||||
return table_.merge(x.table_);
|
||||
}
|
||||
|
||||
template <typename H2, typename P2>
|
||||
size_type merge(concurrent_flat_set<Key, H2, P2, Allocator>&& x)
|
||||
{
|
||||
return merge(x);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE size_type count(key_type const& k) const
|
||||
{
|
||||
return table_.count(k);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, size_type>::type
|
||||
count(K const& k)
|
||||
{
|
||||
return table_.count(k);
|
||||
}
|
||||
|
||||
BOOST_FORCEINLINE bool contains(key_type const& k) const
|
||||
{
|
||||
return table_.contains(k);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::are_transparent<K, hasher, key_equal>::value, bool>::type
|
||||
contains(K const& k) const
|
||||
{
|
||||
return table_.contains(k);
|
||||
}
|
||||
|
||||
/// Hash Policy
|
||||
///
|
||||
size_type bucket_count() const noexcept { return table_.capacity(); }
|
||||
|
||||
float load_factor() const noexcept { return table_.load_factor(); }
|
||||
float max_load_factor() const noexcept
|
||||
{
|
||||
return table_.max_load_factor();
|
||||
}
|
||||
void max_load_factor(float) {}
|
||||
size_type max_load() const noexcept { return table_.max_load(); }
|
||||
|
||||
void rehash(size_type n) { table_.rehash(n); }
|
||||
void reserve(size_type n) { table_.reserve(n); }
|
||||
|
||||
/// Observers
|
||||
///
|
||||
allocator_type get_allocator() const noexcept
|
||||
{
|
||||
return table_.get_allocator();
|
||||
}
|
||||
|
||||
hasher hash_function() const { return table_.hash_function(); }
|
||||
key_equal key_eq() const { return table_.key_eq(); }
|
||||
};
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return lhs.table_ == rhs.table_;
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
|
||||
template <class Key, class Hash, class Pred, class Alloc>
|
||||
void swap(concurrent_flat_set<Key, Hash, Pred, Alloc>& x,
|
||||
concurrent_flat_set<Key, Hash, Pred, Alloc>& y)
|
||||
noexcept(noexcept(x.swap(y)))
|
||||
{
|
||||
x.swap(y);
|
||||
}
|
||||
|
||||
template <class K, class H, class P, class A, class Predicate>
|
||||
typename concurrent_flat_set<K, H, P, A>::size_type erase_if(
|
||||
concurrent_flat_set<K, H, P, A>& c, Predicate pred)
|
||||
{
|
||||
return c.table_.erase_if(pred);
|
||||
}
|
||||
|
||||
template<class Archive, class K, class H, class KE, class A>
|
||||
void serialize(
|
||||
Archive& ar, concurrent_flat_set<K, H, KE, A>& c, unsigned int)
|
||||
{
|
||||
ar & core::make_nvp("table",c.table_);
|
||||
}
|
||||
|
||||
#if BOOST_UNORDERED_TEMPLATE_DEDUCTION_GUIDES
|
||||
|
||||
template <class InputIterator,
|
||||
class Hash =
|
||||
boost::hash<typename std::iterator_traits<InputIterator>::value_type>,
|
||||
class Pred =
|
||||
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
|
||||
class Allocator = std::allocator<
|
||||
typename std::iterator_traits<InputIterator>::value_type>,
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(InputIterator, InputIterator,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> concurrent_flat_set<
|
||||
typename std::iterator_traits<InputIterator>::value_type, Hash, Pred,
|
||||
Allocator>;
|
||||
|
||||
template <class T, class Hash = boost::hash<T>,
|
||||
class Pred = std::equal_to<T>, class Allocator = std::allocator<T>,
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_pred_v<Pred> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(std::initializer_list<T>,
|
||||
std::size_t = boost::unordered::detail::foa::default_bucket_count,
|
||||
Hash = Hash(), Pred = Pred(), Allocator = Allocator())
|
||||
-> concurrent_flat_set< T, Hash, Pred, Allocator>;
|
||||
|
||||
template <class InputIterator, class Allocator,
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(InputIterator, InputIterator, std::size_t, Allocator)
|
||||
-> concurrent_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 InputIterator, class Allocator,
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(InputIterator, InputIterator, Allocator)
|
||||
-> concurrent_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 InputIterator, class Hash, class Allocator,
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_input_iterator_v<InputIterator> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(
|
||||
InputIterator, InputIterator, std::size_t, Hash, Allocator)
|
||||
-> concurrent_flat_set<
|
||||
typename std::iterator_traits<InputIterator>::value_type, Hash,
|
||||
std::equal_to<typename std::iterator_traits<InputIterator>::value_type>,
|
||||
Allocator>;
|
||||
|
||||
template <class T, class Allocator,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(std::initializer_list<T>, std::size_t, Allocator)
|
||||
-> concurrent_flat_set<T, boost::hash<T>,std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class T, class Allocator,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(std::initializer_list<T >, Allocator)
|
||||
-> concurrent_flat_set<T, boost::hash<T>, std::equal_to<T>, Allocator>;
|
||||
|
||||
template <class T, class Hash, class Allocator,
|
||||
class = std::enable_if_t<detail::is_hash_v<Hash> >,
|
||||
class = std::enable_if_t<detail::is_allocator_v<Allocator> > >
|
||||
concurrent_flat_set(std::initializer_list<T >, std::size_t,Hash, Allocator)
|
||||
-> concurrent_flat_set<T, Hash, std::equal_to<T>, Allocator>;
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace unordered
|
||||
|
||||
using unordered::concurrent_flat_set;
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_HPP
|
||||
@@ -0,0 +1,55 @@
|
||||
/* Fast open-addressing concurrent hashset.
|
||||
*
|
||||
* Copyright 2023 Christian Mazakas.
|
||||
* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_CONCURRENT_FLAT_SET_FWD_HPP
|
||||
#define BOOST_UNORDERED_CONCURRENT_FLAT_SET_FWD_HPP
|
||||
|
||||
#include <boost/container_hash/hash_fwd.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
|
||||
template <class Key, class Hash = boost::hash<Key>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key> >
|
||||
class concurrent_flat_set;
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator==(
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs);
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
bool operator!=(
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& lhs,
|
||||
concurrent_flat_set<Key, Hash, KeyEqual, Allocator> const& rhs);
|
||||
|
||||
template <class Key, class Hash, class Pred, class Alloc>
|
||||
void swap(concurrent_flat_set<Key, Hash, Pred, Alloc>& x,
|
||||
concurrent_flat_set<Key, Hash, Pred, Alloc>& y)
|
||||
noexcept(noexcept(x.swap(y)));
|
||||
|
||||
template <class K, class H, class P, class A, class Predicate>
|
||||
typename concurrent_flat_set<K, H, P, A>::size_type erase_if(
|
||||
concurrent_flat_set<K, H, P, A>& c, Predicate pred);
|
||||
|
||||
} // namespace unordered
|
||||
|
||||
using boost::unordered::concurrent_flat_set;
|
||||
using boost::unordered::swap;
|
||||
using boost::unordered::operator==;
|
||||
using boost::unordered::operator!=;
|
||||
} // namespace boost
|
||||
|
||||
#endif // BOOST_UNORDERED_CONCURRENT_FLAT_SET_FWD_HPP
|
||||
@@ -0,0 +1,71 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_ARCHIVE_CONSTRUCTED_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_ARCHIVE_CONSTRUCTED_HPP
|
||||
|
||||
#include <boost/unordered/detail/opt_storage.hpp>
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/core/no_exceptions_support.hpp>
|
||||
#include <boost/core/noncopyable.hpp>
|
||||
#include <boost/core/serialization.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
|
||||
/* constructs a stack-based object from a serialization archive */
|
||||
|
||||
template<typename T>
|
||||
struct archive_constructed:private noncopyable
|
||||
{
|
||||
template<class Archive>
|
||||
archive_constructed(const char* name,Archive& ar,unsigned int version)
|
||||
{
|
||||
core::load_construct_data_adl(ar,std::addressof(get()),version);
|
||||
BOOST_TRY{
|
||||
ar>>core::make_nvp(name,get());
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
get().~T();
|
||||
BOOST_RETHROW;
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
}
|
||||
|
||||
~archive_constructed()
|
||||
{
|
||||
get().~T();
|
||||
}
|
||||
|
||||
#if defined(BOOST_GCC)&&(BOOST_GCC>=4*10000+6*100)
|
||||
#define BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING
|
||||
#endif
|
||||
|
||||
#if defined(BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING)
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wstrict-aliasing"
|
||||
#endif
|
||||
|
||||
T& get(){return *space.address();}
|
||||
|
||||
#if defined(BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING)
|
||||
#pragma GCC diagnostic pop
|
||||
#undef BOOST_UNORDERED_IGNORE_WSTRICT_ALIASING
|
||||
#endif
|
||||
|
||||
private:
|
||||
opt_storage<T> space;
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,27 @@
|
||||
/* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_BAD_ARCHIVE_EXCEPTION_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_BAD_ARCHIVE_EXCEPTION_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
namespace detail{
|
||||
|
||||
struct bad_archive_exception:std::runtime_error
|
||||
{
|
||||
bad_archive_exception():std::runtime_error("Invalid or corrupted archive"){}
|
||||
};
|
||||
|
||||
} /* namespace detail */
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,105 @@
|
||||
/* Copyright 2023 Christian Mazakas.
|
||||
* Copyright 2023 Joaquin M Lopez Munoz.
|
||||
* Distributed under the Boost Software License, Version 1.0.
|
||||
* (See accompanying file LICENSE_1_0.txt or copy at
|
||||
* http://www.boost.org/LICENSE_1_0.txt)
|
||||
*
|
||||
* See https://www.boost.org/libs/unordered for library home page.
|
||||
*/
|
||||
|
||||
#ifndef BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP
|
||||
#define BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP
|
||||
|
||||
#include <boost/config.hpp>
|
||||
#include <boost/mp11/algorithm.hpp>
|
||||
#include <boost/mp11/list.hpp>
|
||||
|
||||
#include <functional>
|
||||
#include <iterator>
|
||||
#include <type_traits>
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE(F) \
|
||||
static_assert(boost::unordered::detail::is_invocable<F, value_type&>::value, \
|
||||
"The provided Callable must be invocable with value_type&");
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE(F) \
|
||||
static_assert( \
|
||||
boost::unordered::detail::is_invocable<F, value_type const&>::value, \
|
||||
"The provided Callable must be invocable with value_type const&");
|
||||
|
||||
#if BOOST_CXX_VERSION >= 202002L
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \
|
||||
static_assert(!std::is_base_of<std::execution::parallel_unsequenced_policy, \
|
||||
ExecPolicy>::value, \
|
||||
"ExecPolicy must be sequenced."); \
|
||||
static_assert( \
|
||||
!std::is_base_of<std::execution::unsequenced_policy, ExecPolicy>::value, \
|
||||
"ExecPolicy must be sequenced.");
|
||||
|
||||
#else
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_EXEC_POLICY(P) \
|
||||
static_assert(!std::is_base_of<std::execution::parallel_unsequenced_policy, \
|
||||
ExecPolicy>::value, \
|
||||
"ExecPolicy must be sequenced.");
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_DETAIL_COMMA ,
|
||||
|
||||
#define BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args) \
|
||||
mp11::mp_back<mp11::mp_list<Arg BOOST_UNORDERED_DETAIL_COMMA Args> >
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_INVOCABLE(Arg, Args) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_INVOCABLE( \
|
||||
BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args))
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_LAST_ARG_CONST_INVOCABLE(Arg, Args) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_CONST_INVOCABLE( \
|
||||
BOOST_UNORDERED_DETAIL_LAST_ARG(Arg, Args))
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
namespace detail {
|
||||
template <class F, class... Args>
|
||||
struct is_invocable
|
||||
: std::is_constructible<std::function<void(Args...)>,
|
||||
std::reference_wrapper<typename std::remove_reference<F>::type> >
|
||||
{
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
} // namespace unordered
|
||||
|
||||
} // namespace boost
|
||||
|
||||
#if defined(BOOST_NO_CXX20_HDR_CONCEPTS)
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_FWD_ITERATOR(Iterator) \
|
||||
static_assert( \
|
||||
std::is_base_of< \
|
||||
std::forward_iterator_tag, \
|
||||
typename std::iterator_traits<Iterator>::iterator_category>::value, \
|
||||
"The provided iterator must be at least forward");
|
||||
#else
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_FWD_ITERATOR(Iterator) \
|
||||
static_assert(std::forward_iterator<Iterator>, \
|
||||
"The provided iterator must be at least forward");
|
||||
|
||||
#endif
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_KEY_COMPATIBLE_ITERATOR(Iterator) \
|
||||
static_assert( \
|
||||
std::is_same< \
|
||||
typename std::iterator_traits<Iterator>::value_type, \
|
||||
key_type>::value || \
|
||||
detail::are_transparent< \
|
||||
typename std::iterator_traits<Iterator>::value_type, \
|
||||
hasher, key_equal>::value, \
|
||||
"The provided iterator must dereference to a compatible key value");
|
||||
|
||||
#define BOOST_UNORDERED_STATIC_ASSERT_BULK_VISIT_ITERATOR(Iterator) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_FWD_ITERATOR(Iterator) \
|
||||
BOOST_UNORDERED_STATIC_ASSERT_KEY_COMPATIBLE_ITERATOR(Iterator)
|
||||
|
||||
#endif // BOOST_UNORDERED_DETAIL_CONCURRENT_STATIC_ASSERTS_HPP
|
||||