mirror of
https://github.com/boostorg/unordered.git
synced 2025-07-29 19:07:15 +02:00
Merge branch 'develop' into feature/foa_rc_docs
This commit is contained in:
@ -42,7 +42,12 @@ environment:
|
||||
|
||||
- FLAVOR: Visual Studio 2017
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
B2_CXXSTD: 14,17,latest
|
||||
B2_CXXSTD: 14,17
|
||||
B2_TOOLSET: msvc-14.1
|
||||
|
||||
- FLAVOR: Visual Studio 2017
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||
B2_CXXSTD: latest
|
||||
B2_TOOLSET: msvc-14.1
|
||||
|
||||
- FLAVOR: cygwin (32-bit)
|
||||
@ -63,7 +68,7 @@ environment:
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 03,11
|
||||
B2_CXXSTD: 03
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
@ -71,14 +76,37 @@ environment:
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 14,1z
|
||||
B2_CXXSTD: 11
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 14
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: cygwin (64-bit, latest)
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||
ADDPATH: C:\cygwin64\bin;
|
||||
B2_ADDRESS_MODEL: 64
|
||||
B2_CXXSTD: 1z
|
||||
B2_TOOLSET: gcc
|
||||
B2_FLAGS: "include=libs/unordered/test/unordered include=libs/unordered/test/exception"
|
||||
|
||||
- FLAVOR: mingw-w64, 32 bit
|
||||
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,11,14,17,2a
|
||||
B2_CXXSTD: 03,11,14
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 32
|
||||
|
||||
- FLAVOR: mingw-w64, 32 bit
|
||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
||||
B2_CXXSTD: 17,2a
|
||||
B2_TOOLSET: gcc
|
||||
B2_ADDRESS_MODEL: 32
|
||||
|
||||
|
234
.drone.jsonnet
234
.drone.jsonnet
@ -138,31 +138,217 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64 32",
|
||||
"Linux 16.04 GCC 5* 32/64",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,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' },
|
||||
"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' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 GCC 8 32/64",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
|
||||
"g++-8-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* ARM64 64",
|
||||
"Linux 20.04 GCC 9* S390x",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '64' },
|
||||
arch="arm64",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* S390x 32",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32' },
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
|
||||
arch="s390x",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 GCC 9* S390x 64",
|
||||
"cppalliance/droneubuntu2004:multiarch",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '64' },
|
||||
arch="s390x",
|
||||
"Linux 20.04 GCC 10 32/64",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,20', ADDRMD: '32,64' },
|
||||
"g++-10-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 11* 32/64",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32 ASAN (03,11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14', ADDRMD: '32' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 32 ASAN (17,20,2b)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20,2b', ADDRMD: '32' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 ASAN (03,11,14)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14', ADDRMD: '64' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 GCC 12 64 ASAN (17,20,2b)",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20,2b', ADDRMD: '64' } + asan,
|
||||
"g++-12-multilib",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.5",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '03,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' },
|
||||
"clang-3.6",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 16.04 Clang 3.7",
|
||||
"cppalliance/droneubuntu1604:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '03,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' },
|
||||
"clang-3.8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 18.04 Clang 3.9",
|
||||
"cppalliance/droneubuntu1804:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '03,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' },
|
||||
"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' },
|
||||
"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' },
|
||||
"clang-6.0",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 7",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '03,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' },
|
||||
"clang-8",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 9",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '03,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' },
|
||||
"clang-10",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 20.04 Clang 11",
|
||||
"cppalliance/droneubuntu2004:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '03,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' },
|
||||
"clang-12",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 13",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '03,11,14,17,20' },
|
||||
"clang-13",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 UBSAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + ubsan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 14 ASAN",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + asan,
|
||||
"clang-14",
|
||||
),
|
||||
|
||||
linux_pipeline(
|
||||
"Linux 22.04 Clang 15",
|
||||
"cppalliance/droneubuntu2204:1",
|
||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '03,11,14,17,20,2b' },
|
||||
"clang-15",
|
||||
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
|
||||
),
|
||||
|
||||
macos_pipeline(
|
||||
@ -176,9 +362,27 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
|
||||
xcode_version = "13.4.1", osx_version = "monterey",
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2015 msvc-14.0",
|
||||
"cppalliance/dronevs2015",
|
||||
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2017 msvc-14.1",
|
||||
"cppalliance/dronevs2017",
|
||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2019 msvc-14.2",
|
||||
"cppalliance/dronevs2019",
|
||||
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
|
||||
windows_pipeline(
|
||||
"Windows VS2022 msvc-14.3",
|
||||
"cppalliance/dronevs2022:1",
|
||||
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
|
||||
),
|
||||
]
|
||||
|
66
.github/workflows/ci.yml
vendored
66
.github/workflows/ci.yml
vendored
@ -42,45 +42,37 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
# Linux, gcc
|
||||
- { compiler: gcc-4.8, cxxstd: '03,11', os: ubuntu-18.04, install: 'g++-4.8-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-4.9, cxxstd: '03,11', os: ubuntu-20.04, container: 'ubuntu:16.04' }
|
||||
- { compiler: gcc-5, cxxstd: '03,11,14,1z', os: ubuntu-18.04, install: 'g++-5-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-6, cxxstd: '03,11,14,17', os: ubuntu-18.04, install: 'g++-6-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-7, cxxstd: '03,11,14,17', os: ubuntu-18.04, install: 'g++-7-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-8, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04, install: 'g++-8-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-9, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04, install: 'g++-9-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, install: 'g++-10-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-11, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, install: 'g++-11-multilib', address-model: '32,64' }
|
||||
- { compiler: gcc-12, cxxstd: '03,11,14,17,20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '32,64' }
|
||||
- { name: GCC w/ sanitizers, sanitize: yes,
|
||||
compiler: gcc-12, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||
- { 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" }
|
||||
- { name: Collect coverage, coverage: yes,
|
||||
compiler: gcc-8, cxxstd: '03,11', os: ubuntu-20.04, install: 'g++-8-multilib', address-model: '32,64' }
|
||||
compiler: gcc-8, cxxstd: '03,11', os: ubuntu-20.04, install: 'g++-8-multilib', address-model: '32,64', ccache_key: "cov" }
|
||||
|
||||
# Linux, clang
|
||||
- { compiler: clang-3.7, cxxstd: '03,11,14', os: ubuntu-20.04, container: 'ubuntu:16.04' }
|
||||
- { compiler: clang-3.8, cxxstd: '03,11,14', os: ubuntu-20.04, container: 'ubuntu:16.04' }
|
||||
- { compiler: clang-3.9, cxxstd: '03,11,14', os: ubuntu-18.04 }
|
||||
- { compiler: clang-4.0, cxxstd: '03,11,14', os: ubuntu-18.04 }
|
||||
- { compiler: clang-5.0, cxxstd: '03,11,14,1z', os: ubuntu-18.04 }
|
||||
- { compiler: clang-6.0, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||
- { compiler: clang-8, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||
- { compiler: clang-9, cxxstd: '03,11,14,17,2a', os: ubuntu-20.04 }
|
||||
- { compiler: clang-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||
- { compiler: clang-11, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||
- { compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||
- { compiler: clang-13, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||
- { compiler: clang-14, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||
|
||||
# libc++
|
||||
- { compiler: clang-6.0, cxxstd: '03,11,14', os: ubuntu-18.04, stdlib: libc++, install: 'clang-6.0 libc++-dev libc++abi-dev' }
|
||||
- { compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev' }
|
||||
- { name: Clang w/ sanitizers, sanitize: yes,
|
||||
compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev' }
|
||||
# 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' }
|
||||
# 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" }
|
||||
|
||||
# OSX, clang
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, sanitize: yes }
|
||||
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, sanitize: yes }
|
||||
|
||||
timeout-minutes: 120
|
||||
runs-on: ${{matrix.os}}
|
||||
@ -119,8 +111,8 @@ jobs:
|
||||
if: env.B2_USE_CCACHE
|
||||
with:
|
||||
path: ~/.ccache
|
||||
key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}}
|
||||
restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-
|
||||
key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{matrix.ccache_key}}-${{github.sha}}
|
||||
restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{matrix.ccache_key}}-
|
||||
|
||||
- name: Fetch Boost.CI
|
||||
uses: actions/checkout@v3
|
||||
|
@ -5,6 +5,7 @@
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
@ -294,6 +295,9 @@ template<class K, class V> using std_unordered_map =
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
@ -366,7 +370,10 @@ template<> struct fnv1a_hash_impl<64>
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
template<class K, class V> using std_unordered_map_fnv1a =
|
||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
@ -374,6 +381,9 @@ std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
@ -418,10 +428,11 @@ int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@ -449,6 +460,7 @@ int main()
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@ -476,7 +488,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 31 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 35 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
@ -295,6 +296,9 @@ template<class K, class V> using std_unordered_map =
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
@ -367,7 +371,10 @@ template<> struct fnv1a_hash_impl<64>
|
||||
}
|
||||
};
|
||||
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits > {};
|
||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
||||
{
|
||||
using is_avalanching = void;
|
||||
};
|
||||
|
||||
template<class K, class V> using std_unordered_map_fnv1a =
|
||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
@ -375,6 +382,9 @@ std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
@ -419,10 +429,11 @@ int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
#if 0
|
||||
#if 1
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@ -450,6 +461,7 @@ int main()
|
||||
|
||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
||||
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@ -477,7 +489,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 31 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 35 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -5,6 +5,7 @@
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
@ -311,6 +312,9 @@ template<class K, class V> using std_unordered_map =
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
@ -347,6 +351,7 @@ int main()
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@ -374,7 +379,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 25 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 27 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#include <fxa_unordered/foa_unordered_rc.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
@ -313,28 +312,8 @@ template<class K, class V> using std_unordered_map =
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template <typename Key, typename Value> struct map_types
|
||||
{
|
||||
using key_type = Key;
|
||||
using value_type = std::pair<const Key, Value>;
|
||||
static auto& extract(const value_type& x) { return x.first; }
|
||||
};
|
||||
|
||||
template <class Key, class Value>
|
||||
using boost_unordered_detail_foa_table =
|
||||
boost::unordered::detail::foa::table<map_types<Key, Value>,
|
||||
absl::container_internal::hash_default_hash<Key>, std::equal_to<Key>,
|
||||
allocator_for<Key, Value> >;
|
||||
|
||||
template <typename Key, typename Value>
|
||||
using boost_unordered_flat_map = boost::unordered::unordered_flat_map<Key,
|
||||
Value, absl::container_internal::hash_default_hash<Key>, std::equal_to<Key>,
|
||||
allocator_for<Key, Value> >;
|
||||
|
||||
template <typename Key, typename Value>
|
||||
using rc15_flat_map = foa_unordered_rc_map<Key, Value,
|
||||
absl::container_internal::hash_default_hash<Key>, std::equal_to<Key>,
|
||||
allocator_for<Key, Value> >;
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
@ -372,9 +351,7 @@ int main()
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_detail_foa_table>( "boost_unordered_detail_foa_table" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<rc15_flat_map>( "rc15_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
@ -402,7 +379,7 @@ int main()
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 34 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
std::cout << std::setw( 27 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
402
benchmark/uuid.cpp
Normal file
402
benchmark/uuid.cpp
Normal file
@ -0,0 +1,402 @@
|
||||
// Copyright 2021, 2022 Peter Dimov.
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||
|
||||
#include <boost/unordered_map.hpp>
|
||||
#include <boost/unordered/unordered_flat_map.hpp>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/member.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/core/detail/splitmix64.hpp>
|
||||
#include <boost/container_hash/hash.hpp>
|
||||
#include <boost/config.hpp>
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/node_hash_map.h"
|
||||
# include "absl/container/flat_hash_map.h"
|
||||
#endif
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint64_t s, std::size_t size )
|
||||
{
|
||||
auto t2 = std::chrono::steady_clock::now();
|
||||
|
||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
||||
|
||||
t1 = t2;
|
||||
}
|
||||
|
||||
constexpr unsigned N = 2'000'000;
|
||||
constexpr int K = 10;
|
||||
|
||||
struct uuid
|
||||
{
|
||||
unsigned char data[ 16 ];
|
||||
|
||||
uuid(): data()
|
||||
{
|
||||
}
|
||||
|
||||
uuid( std::uint64_t low, std::uint64_t high ) noexcept
|
||||
{
|
||||
boost::endian::store_little_u64( data + 0, low );
|
||||
boost::endian::store_little_u64( data + 8, high );
|
||||
}
|
||||
|
||||
inline friend std::size_t hash_value( uuid const& u ) noexcept
|
||||
{
|
||||
std::uint64_t low = boost::endian::load_little_u64( u.data + 0 );
|
||||
std::uint64_t high = boost::endian::load_little_u64( u.data + 8 );
|
||||
|
||||
std::size_t r = 0;
|
||||
|
||||
boost::hash_combine( r, low );
|
||||
boost::hash_combine( r, high );
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
inline friend bool operator==( uuid const& u1, uuid const& u2 ) noexcept
|
||||
{
|
||||
return std::memcmp( u1.data, u2.data, 16 ) == 0;
|
||||
}
|
||||
};
|
||||
|
||||
namespace std
|
||||
{
|
||||
|
||||
template<> struct hash< ::uuid >
|
||||
{
|
||||
std::size_t operator()( uuid const& u ) const noexcept
|
||||
{
|
||||
return hash_value( u );
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace std
|
||||
|
||||
static std::vector< uuid > indices1, indices2, indices3;
|
||||
|
||||
static void init_indices()
|
||||
{
|
||||
indices1.push_back( {} );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices1.push_back( { i, 0 } );
|
||||
}
|
||||
|
||||
indices2.push_back( {} );
|
||||
|
||||
{
|
||||
boost::detail::splitmix64 rng;
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
indices2.push_back( { rng(), rng() } );
|
||||
}
|
||||
}
|
||||
|
||||
indices3.push_back( {} );
|
||||
|
||||
for( unsigned i = 1; i <= N*2; ++i )
|
||||
{
|
||||
uuid k( i, 0 );
|
||||
std::reverse( k.data + 0, k.data + 16 );
|
||||
|
||||
indices3.push_back( k );
|
||||
}
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices1[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices2[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Random insert", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.insert( { indices3[ i ], i } );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed insert", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
std::uint64_t s;
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices1[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices2[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Random lookup", s, map.size() );
|
||||
|
||||
s = 0;
|
||||
|
||||
for( int j = 0; j < K; ++j )
|
||||
{
|
||||
for( unsigned i = 1; i <= N * 2; ++i )
|
||||
{
|
||||
auto it = map.find( indices3[ i ] );
|
||||
if( it != map.end() ) s += it->second;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed lookup", s, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
auto it = map.begin();
|
||||
|
||||
while( it != map.end() )
|
||||
{
|
||||
if( it->second & 1 )
|
||||
{
|
||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
||||
{
|
||||
map.erase( it++ );
|
||||
}
|
||||
else
|
||||
{
|
||||
it = map.erase( it );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
++it;
|
||||
}
|
||||
}
|
||||
|
||||
print_time( t1, "Iterate and erase odd elements", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::steady_clock::time_point & t1 )
|
||||
{
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices1[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices2[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Random erase", 0, map.size() );
|
||||
|
||||
for( unsigned i = 1; i <= N; ++i )
|
||||
{
|
||||
map.erase( indices3[ i ] );
|
||||
}
|
||||
|
||||
print_time( t1, "Consecutive reversed erase", 0, map.size() );
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
// counting allocator
|
||||
|
||||
static std::size_t s_alloc_bytes = 0;
|
||||
static std::size_t s_alloc_count = 0;
|
||||
|
||||
template<class T> struct allocator
|
||||
{
|
||||
using value_type = T;
|
||||
|
||||
allocator() = default;
|
||||
|
||||
template<class U> allocator( allocator<U> const & ) noexcept
|
||||
{
|
||||
}
|
||||
|
||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate( std::size_t n ) const
|
||||
{
|
||||
s_alloc_bytes += n * sizeof(T);
|
||||
s_alloc_count++;
|
||||
|
||||
return std::allocator<T>().allocate( n );
|
||||
}
|
||||
|
||||
void deallocate( T* p, std::size_t n ) const noexcept
|
||||
{
|
||||
s_alloc_bytes -= n * sizeof(T);
|
||||
s_alloc_count--;
|
||||
|
||||
std::allocator<T>().deallocate( p, n );
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
|
||||
struct record
|
||||
{
|
||||
std::string label_;
|
||||
long long time_;
|
||||
std::size_t bytes_;
|
||||
std::size_t count_;
|
||||
};
|
||||
|
||||
static std::vector<record> times;
|
||||
|
||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
||||
{
|
||||
std::cout << label << ":\n\n";
|
||||
|
||||
s_alloc_bytes = 0;
|
||||
s_alloc_count = 0;
|
||||
|
||||
Map<uuid, std::uint64_t> map;
|
||||
|
||||
auto t0 = std::chrono::steady_clock::now();
|
||||
auto t1 = t0;
|
||||
|
||||
test_insert( map, t1 );
|
||||
|
||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
||||
|
||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
||||
|
||||
test_lookup( map, t1 );
|
||||
test_iteration( map, t1 );
|
||||
test_lookup( map, t1 );
|
||||
test_erase( map, t1 );
|
||||
|
||||
auto tN = std::chrono::steady_clock::now();
|
||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
||||
|
||||
rec.time_ = ( tN - t0 ) / 1ms;
|
||||
times.push_back( rec );
|
||||
}
|
||||
|
||||
// multi_index emulation of unordered_map
|
||||
|
||||
template<class K, class V> struct pair
|
||||
{
|
||||
K first;
|
||||
mutable V second;
|
||||
};
|
||||
|
||||
using namespace boost::multi_index;
|
||||
|
||||
template<class K, class V> using multi_index_map = multi_index_container<
|
||||
pair<K, V>,
|
||||
indexed_by<
|
||||
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first> >
|
||||
>,
|
||||
::allocator< pair<K, V> >
|
||||
>;
|
||||
|
||||
// aliases using the counting allocator
|
||||
|
||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
||||
|
||||
template<class K, class V> using std_unordered_map =
|
||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_map =
|
||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using boost_unordered_flat_map =
|
||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
template<class K, class V> using absl_node_hash_map =
|
||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
template<class K, class V> using absl_flat_hash_map =
|
||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
||||
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
init_indices();
|
||||
|
||||
test<std_unordered_map>( "std::unordered_map" );
|
||||
test<boost_unordered_map>( "boost::unordered_map" );
|
||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
||||
test<multi_index_map>( "multi_index_map" );
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
|
||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||
|
||||
#endif
|
||||
|
||||
std::cout << "---\n\n";
|
||||
|
||||
for( auto const& x: times )
|
||||
{
|
||||
std::cout << std::setw( 27 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_ABSEIL
|
||||
# include "absl/container/internal/raw_hash_set.cc"
|
||||
# include "absl/hash/internal/hash.cc"
|
||||
# include "absl/hash/internal/low_level_hash.cc"
|
||||
# include "absl/hash/internal/city.cc"
|
||||
#endif
|
@ -114,7 +114,8 @@ namespace foa{
|
||||
* bits for signalling overflow makes it very likely that we stop at the
|
||||
* current group (this happens when no element with the same (h%8) value
|
||||
* has overflowed in the group), saving us an additional group check even
|
||||
* under high-load/high-erase conditions.
|
||||
* under high-load/high-erase conditions. It is critical that hash
|
||||
* reduction is invariant under modulo 8 (see maybe_caused_overflow).
|
||||
*
|
||||
* When looking for an element with hash value h, match(h) returns a bitmask
|
||||
* signalling which slots have the same reduced hash value. If available,
|
||||
@ -186,9 +187,20 @@ struct group15
|
||||
|
||||
inline void mark_overflow(std::size_t hash)
|
||||
{
|
||||
#if BOOST_WORKAROUND(BOOST_GCC, >= 50000 && BOOST_GCC < 60000)
|
||||
overflow() = static_cast<unsigned char>( overflow() | static_cast<unsigned char>(1<<(hash%8)) );
|
||||
#else
|
||||
overflow()|=static_cast<unsigned char>(1<<(hash%8));
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool maybe_caused_overflow(unsigned char* pc)
|
||||
{
|
||||
std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
|
||||
group15 *pg=reinterpret_cast<group15*>(pc-pos);
|
||||
return !pg->is_not_overflowed(*pc);
|
||||
};
|
||||
|
||||
inline int match_available()const
|
||||
{
|
||||
return _mm_movemask_epi8(
|
||||
@ -213,7 +225,7 @@ private:
|
||||
{
|
||||
static constexpr boost::uint32_t word[]=
|
||||
{
|
||||
0x02020202u,0x03030303u,0x02020202u,0x03030303u,0x04040404u,0x05050505u,0x06060606u,0x07070707u,
|
||||
0x08080808u,0x09090909u,0x02020202u,0x03030303u,0x04040404u,0x05050505u,0x06060606u,0x07070707u,
|
||||
0x08080808u,0x09090909u,0x0A0A0A0Au,0x0B0B0B0Bu,0x0C0C0C0Cu,0x0D0D0D0Du,0x0E0E0E0Eu,0x0F0F0F0Fu,
|
||||
0x10101010u,0x11111111u,0x12121212u,0x13131313u,0x14141414u,0x15151515u,0x16161616u,0x17171717u,
|
||||
0x18181818u,0x19191919u,0x1A1A1A1Au,0x1B1B1B1Bu,0x1C1C1C1Cu,0x1D1D1D1Du,0x1E1E1E1Eu,0x1F1F1F1Fu,
|
||||
@ -305,7 +317,7 @@ struct group15
|
||||
inline bool is_sentinel(std::size_t pos)const
|
||||
{
|
||||
BOOST_ASSERT(pos<N);
|
||||
return at(pos)==sentinel_;
|
||||
return pos==N-1&&at(N-1)==sentinel_;
|
||||
}
|
||||
|
||||
inline void reset(std::size_t pos)
|
||||
@ -337,6 +349,13 @@ struct group15
|
||||
overflow()|=static_cast<unsigned char>(1<<(hash%8));
|
||||
}
|
||||
|
||||
static inline bool maybe_caused_overflow(unsigned char* pc)
|
||||
{
|
||||
std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
|
||||
group15 *pg=reinterpret_cast<group15*>(pc-pos);
|
||||
return !pg->is_not_overflowed(*pc);
|
||||
};
|
||||
|
||||
inline int match_available()const
|
||||
{
|
||||
return simde_mm_movemask_epi8(vceqq_s8(m,vdupq_n_s8(0)))&0x7FFF;
|
||||
@ -360,7 +379,7 @@ private:
|
||||
inline static unsigned char reduced_hash(std::size_t hash)
|
||||
{
|
||||
static constexpr unsigned char table[]={
|
||||
2,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
||||
8,9,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
||||
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
|
||||
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
|
||||
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
|
||||
@ -491,6 +510,15 @@ struct group15
|
||||
reinterpret_cast<boost::uint16_t*>(m)[hash%8]|=0x8000u;
|
||||
}
|
||||
|
||||
static inline bool maybe_caused_overflow(unsigned char* pc)
|
||||
{
|
||||
std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
|
||||
group15 *pg=reinterpret_cast<group15*>(pc-pos);
|
||||
boost::uint64_t x=((pg->m[0])>>pos)&0x000100010001ull;
|
||||
boost::uint32_t y=static_cast<boost::uint32_t>(x|(x>>15)|(x>>30));
|
||||
return !pg->is_not_overflowed(y);
|
||||
};
|
||||
|
||||
inline int match_available()const
|
||||
{
|
||||
boost::uint64_t x=~(m[0]|m[1]);
|
||||
@ -519,7 +547,7 @@ private:
|
||||
inline static unsigned char reduced_hash(std::size_t hash)
|
||||
{
|
||||
static constexpr unsigned char table[]={
|
||||
2,3,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
||||
8,9,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
|
||||
16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
|
||||
32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
|
||||
48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
|
||||
@ -721,7 +749,7 @@ inline unsigned int unchecked_countr_zero(int x)
|
||||
_BitScanForward(&r,(unsigned long)x);
|
||||
return (unsigned int)r;
|
||||
#else
|
||||
BOOST_UNORDERED_ASSUME(x);
|
||||
BOOST_UNORDERED_ASSUME(x!=0);
|
||||
return (unsigned int)boost::core::countr_zero((unsigned int)x);
|
||||
#endif
|
||||
}
|
||||
@ -1105,7 +1133,7 @@ public:
|
||||
const Allocator& al_=Allocator()):
|
||||
hash_base{empty_init,h_},pred_base{empty_init,pred_},
|
||||
allocator_base{empty_init,al_},size_{0},arrays(new_arrays(n)),
|
||||
ml{max_load()}
|
||||
ml{initial_max_load()}
|
||||
{}
|
||||
|
||||
table(const table& x):
|
||||
@ -1123,7 +1151,7 @@ public:
|
||||
{
|
||||
x.size_=0;
|
||||
x.arrays=x.new_arrays(0);
|
||||
x.ml=x.max_load();
|
||||
x.ml=x.initial_max_load();
|
||||
}
|
||||
|
||||
table(const table& x,const Allocator& al_):
|
||||
@ -1299,14 +1327,15 @@ public:
|
||||
>
|
||||
void erase(iterator pos)noexcept{return erase(const_iterator(pos));}
|
||||
|
||||
BOOST_FORCEINLINE
|
||||
void erase(const_iterator pos)noexcept
|
||||
{
|
||||
destroy_element(pos.p);
|
||||
group_type::reset(pos.pc);
|
||||
--size_;
|
||||
recover_slot(pos.pc);
|
||||
}
|
||||
|
||||
template<typename Key>
|
||||
BOOST_FORCEINLINE
|
||||
auto erase(Key&& x) -> typename std::enable_if<
|
||||
!std::is_convertible<Key,iterator>::value&&
|
||||
!std::is_convertible<Key,const_iterator>::value, std::size_t>::type
|
||||
@ -1359,6 +1388,7 @@ public:
|
||||
}
|
||||
arrays.groups[arrays.groups_size_mask].set_sentinel();
|
||||
size_=0;
|
||||
ml=initial_max_load();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1405,6 +1435,8 @@ public:
|
||||
|
||||
float max_load_factor()const noexcept{return mlf;}
|
||||
|
||||
std::size_t max_load()const noexcept{return ml;}
|
||||
|
||||
void rehash(std::size_t n)
|
||||
{
|
||||
auto m=size_t(std::ceil(float(size())/mlf));
|
||||
@ -1470,7 +1502,23 @@ private:
|
||||
value_type *p;
|
||||
};
|
||||
|
||||
std::size_t max_load()const
|
||||
void recover_slot(unsigned char* pc)
|
||||
{
|
||||
/* If this slot potentially caused overflow, we decrease the maximum load so
|
||||
* that average probe length won't increase unboundedly in repeated
|
||||
* insert/erase cycles (drift).
|
||||
*/
|
||||
ml-=group_type::maybe_caused_overflow(pc);
|
||||
group_type::reset(pc);
|
||||
--size_;
|
||||
}
|
||||
|
||||
void recover_slot(group_type* pg,std::size_t pos)
|
||||
{
|
||||
recover_slot(reinterpret_cast<unsigned char*>(pg)+pos);
|
||||
}
|
||||
|
||||
std::size_t initial_max_load()const
|
||||
{
|
||||
static constexpr std::size_t small_capacity=2*N-1;
|
||||
|
||||
@ -1593,24 +1641,10 @@ private:
|
||||
};
|
||||
}
|
||||
else{
|
||||
/* strong exception guarantee -> try insertion before rehash */
|
||||
auto new_arrays_=new_arrays(
|
||||
std::size_t(std::ceil(static_cast<float>(size_+1)/mlf)));
|
||||
BOOST_TRY{
|
||||
it=nosize_unchecked_emplace_at(
|
||||
new_arrays_,position_for(hash,new_arrays_),
|
||||
hash,std::forward<Args>(args)...);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
delete_arrays(new_arrays_);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
/* new_arrays_ lifetime taken care of by unchecked_rehash */
|
||||
unchecked_rehash(new_arrays_);
|
||||
++size_;
|
||||
return {it,true};
|
||||
return {
|
||||
unchecked_emplace_with_rehash(hash,std::forward<Args>(args)...),
|
||||
true
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1619,6 +1653,41 @@ private:
|
||||
return size_policy::size(size_index_for<group_type,size_policy>(n))*N-1;
|
||||
}
|
||||
|
||||
template<typename... Args>
|
||||
BOOST_NOINLINE iterator
|
||||
unchecked_emplace_with_rehash(std::size_t hash,Args&&... args)
|
||||
{
|
||||
/* Due to the anti-drift mechanism (see recover_slot), new_arrays_ may be
|
||||
* of the same size as the old arrays; in the limit, erasing one element at
|
||||
* full load and then inserting could bring us back to the same capacity
|
||||
* after a costly rehash. To avoid this, we jump to the next capacity level
|
||||
* when the number of erased elements is <= 10% of total elements at full
|
||||
* load, which is implemented by requesting additional F*size elements,
|
||||
* with F = P * 10% / (1 - P * 10%), where P is the probability of an
|
||||
* element having caused overflow; P has been measured as ~0.162 under
|
||||
* ideal conditions, yielding F ~ 0.0165 ~ 1/61.
|
||||
*/
|
||||
auto new_arrays_=new_arrays(std::size_t(
|
||||
std::ceil(static_cast<float>(size_+size_/61+1)/mlf)));
|
||||
iterator it;
|
||||
BOOST_TRY{
|
||||
/* strong exception guarantee -> try insertion before rehash */
|
||||
it=nosize_unchecked_emplace_at(
|
||||
new_arrays_,position_for(hash,new_arrays_),
|
||||
hash,std::forward<Args>(args)...);
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
delete_arrays(new_arrays_);
|
||||
BOOST_RETHROW
|
||||
}
|
||||
BOOST_CATCH_END
|
||||
|
||||
/* new_arrays_ lifetime taken care of by unchecked_rehash */
|
||||
unchecked_rehash(new_arrays_);
|
||||
++size_;
|
||||
return it;
|
||||
}
|
||||
|
||||
BOOST_NOINLINE void unchecked_rehash(std::size_t n)
|
||||
{
|
||||
auto new_arrays_=new_arrays(n);
|
||||
@ -1635,12 +1704,11 @@ private:
|
||||
}
|
||||
BOOST_CATCH(...){
|
||||
if(num_destroyed){
|
||||
size_-=num_destroyed;
|
||||
for(auto pg=arrays.groups;;++pg){
|
||||
auto mask=pg->match_occupied();
|
||||
while(mask){
|
||||
auto nz=unchecked_countr_zero(mask);
|
||||
pg->reset(nz);
|
||||
recover_slot(pg,nz);
|
||||
if(!(--num_destroyed))goto continue_;
|
||||
mask&=mask-1;
|
||||
}
|
||||
@ -1664,7 +1732,7 @@ private:
|
||||
}
|
||||
delete_arrays(arrays);
|
||||
arrays=new_arrays_;
|
||||
ml=max_load();
|
||||
ml=initial_max_load();
|
||||
}
|
||||
|
||||
void noshrink_reserve(std::size_t n)
|
||||
@ -1680,7 +1748,7 @@ private:
|
||||
auto new_arrays_=new_arrays(n);
|
||||
delete_arrays(arrays);
|
||||
arrays=new_arrays_;
|
||||
ml=max_load();
|
||||
ml=initial_max_load();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1736,37 +1804,6 @@ private:
|
||||
return res;
|
||||
}
|
||||
|
||||
#if 0
|
||||
template<typename... Args>
|
||||
iterator nosize_unchecked_emplace_at(
|
||||
const arrays_type& arrays_,std::size_t pos0,std::size_t hash,
|
||||
Args&&... args)
|
||||
{
|
||||
auto pn=insert_position(arrays_,pos0,hash);
|
||||
auto &pos=pn.first;
|
||||
auto &n=pn.second;
|
||||
auto pg=arrays_.groups+pos;
|
||||
auto p=arrays_.elements+pos*N+n;
|
||||
construct_element(p,std::forward<Args>(args)...);
|
||||
pg->set(n,hash);
|
||||
return {pg,n,p};
|
||||
}
|
||||
|
||||
std::pair<std::size_t,std::size_t>
|
||||
static insert_position(
|
||||
const arrays_type& arrays_,std::size_t pos0,std::size_t hash)
|
||||
{
|
||||
for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){
|
||||
auto pos=pb.get();
|
||||
auto pg=arrays_.groups+pos;
|
||||
auto mask=pg->match_available();
|
||||
if(BOOST_LIKELY(mask!=0)){
|
||||
return {pos,unchecked_countr_zero(mask)};
|
||||
}
|
||||
else pg->mark_overflow(hash);
|
||||
}
|
||||
}
|
||||
#else
|
||||
template<typename... Args>
|
||||
iterator nosize_unchecked_emplace_at(
|
||||
const arrays_type& arrays_,std::size_t pos0,std::size_t hash,
|
||||
@ -1786,7 +1823,6 @@ private:
|
||||
else pg->mark_overflow(hash);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
template<typename Predicate>
|
||||
std::size_t erase_if_impl(Predicate pr)
|
||||
|
@ -3411,8 +3411,8 @@ namespace boost {
|
||||
template <typename Types>
|
||||
inline void table<Types>::rehash(std::size_t num_buckets)
|
||||
{
|
||||
num_buckets = (std::max)(
|
||||
min_buckets(size_, mlf_), buckets_.bucket_count_for(num_buckets));
|
||||
num_buckets = buckets_.bucket_count_for(
|
||||
(std::max)(min_buckets(size_, mlf_), num_buckets));
|
||||
|
||||
if (num_buckets != this->bucket_count()) {
|
||||
this->rehash_impl(num_buckets);
|
||||
|
@ -12,7 +12,7 @@
|
||||
#define BOOST_UNORDERED_HASH_TRAITS_HPP
|
||||
|
||||
#include <boost/type_traits/make_void.hpp>
|
||||
#include <type_traits>
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
namespace boost{
|
||||
namespace unordered{
|
||||
@ -20,11 +20,12 @@ namespace unordered{
|
||||
namespace detail{
|
||||
|
||||
template<typename Hash,typename=void>
|
||||
struct hash_is_avalanching_impl:std::false_type{};
|
||||
struct hash_is_avalanching_impl: boost::false_type{};
|
||||
|
||||
template<typename Hash>
|
||||
struct hash_is_avalanching_impl<Hash,void_t<typename Hash::is_avalanching>>:
|
||||
std::true_type{};
|
||||
struct hash_is_avalanching_impl<Hash,
|
||||
typename boost::make_void<typename Hash::is_avalanching>::type>:
|
||||
boost::true_type{};
|
||||
|
||||
} /* namespace detail */
|
||||
|
||||
@ -32,11 +33,11 @@ struct hash_is_avalanching_impl<Hash,void_t<typename Hash::is_avalanching>>:
|
||||
* when actual characterization differs from default.
|
||||
*/
|
||||
|
||||
/* Derived from std::true_type if the type Hash::is_avalanching is present,
|
||||
* derived from std::false_type otherwise.
|
||||
/* hash_is_avalanching<Hash>::value is true when the type Hash::is_avalanching
|
||||
* is present, false otherwise.
|
||||
*/
|
||||
template<typename Hash>
|
||||
struct hash_is_avalanching:detail::hash_is_avalanching_impl<Hash>::type{};
|
||||
struct hash_is_avalanching: detail::hash_is_avalanching_impl<Hash>::type{};
|
||||
|
||||
} /* namespace unordered */
|
||||
} /* namespace boost */
|
||||
|
@ -26,6 +26,12 @@
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
template <class Key, class T, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_flat_map
|
||||
{
|
||||
@ -75,6 +81,9 @@ namespace boost {
|
||||
using allocator_type = Allocator;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = typename boost::allocator_pointer<allocator_type>::type;
|
||||
using const_pointer =
|
||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||
using iterator = typename table_type::iterator;
|
||||
using const_iterator = typename table_type::const_iterator;
|
||||
|
||||
@ -97,6 +106,13 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_flat_map(
|
||||
InputIterator f, InputIterator l, allocator_type const& a)
|
||||
: unordered_flat_map(f, l, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
explicit unordered_flat_map(allocator_type const& a)
|
||||
: unordered_flat_map(0, a)
|
||||
{
|
||||
@ -156,6 +172,12 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
unordered_flat_map(
|
||||
std::initializer_list<value_type> il, allocator_type const& a)
|
||||
: unordered_flat_map(il, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_flat_map(std::initializer_list<value_type> init, size_type n,
|
||||
allocator_type const& a)
|
||||
: unordered_flat_map(init, n, hasher(), key_equal(), a)
|
||||
@ -217,29 +239,31 @@ namespace boost {
|
||||
void clear() noexcept { table_.clear(); }
|
||||
|
||||
template <class Ty>
|
||||
auto insert(Ty&& value)
|
||||
BOOST_FORCEINLINE auto insert(Ty&& value)
|
||||
-> decltype(table_.insert(std::forward<Ty>(value)))
|
||||
{
|
||||
return table_.insert(std::forward<Ty>(value));
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(init_type&& value)
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> insert(init_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator, value_type const& value)
|
||||
template <class Ty>
|
||||
BOOST_FORCEINLINE auto insert(const_iterator, Ty&& value)
|
||||
-> decltype(table_.insert(std::forward<Ty>(value)).first)
|
||||
{
|
||||
return table_.insert(value).first;
|
||||
return table_.insert(std::forward<Ty>(value)).first;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator, value_type&& value)
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, init_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value)).first;
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
void insert(InputIterator first, InputIterator last)
|
||||
BOOST_FORCEINLINE void insert(InputIterator first, InputIterator last)
|
||||
{
|
||||
for (auto pos = first; pos != last; ++pos) {
|
||||
table_.emplace(*pos);
|
||||
@ -287,44 +311,52 @@ namespace boost {
|
||||
.first;
|
||||
}
|
||||
|
||||
template <class... Args> std::pair<iterator, bool> emplace(Args&&... args)
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator, Args&&... args)
|
||||
BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return this->emplace(std::forward<Args>(args)...).first;
|
||||
return table_.emplace(std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type const& key, Args&&... args)
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
|
||||
key_type const& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(key, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
std::pair<iterator, bool> try_emplace(key_type&& key, Args&&... args)
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> try_emplace(
|
||||
key_type&& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(std::move(key), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator try_emplace(const_iterator, key_type const& key, Args&&... args)
|
||||
BOOST_FORCEINLINE iterator try_emplace(
|
||||
const_iterator, key_type const& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(key, std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator try_emplace(const_iterator, key_type&& key, Args&&... args)
|
||||
BOOST_FORCEINLINE iterator try_emplace(
|
||||
const_iterator, key_type&& key, Args&&... args)
|
||||
{
|
||||
return table_.try_emplace(std::move(key), std::forward<Args>(args)...)
|
||||
.first;
|
||||
}
|
||||
|
||||
void erase(iterator pos) { table_.erase(pos); }
|
||||
void erase(const_iterator pos) { return table_.erase(pos); }
|
||||
BOOST_FORCEINLINE void erase(iterator pos) { table_.erase(pos); }
|
||||
BOOST_FORCEINLINE void erase(const_iterator pos)
|
||||
{
|
||||
return table_.erase(pos);
|
||||
}
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
while (first != last) {
|
||||
@ -333,10 +365,13 @@ namespace boost {
|
||||
return iterator{detail::foa::const_iterator_cast_tag{}, last};
|
||||
}
|
||||
|
||||
size_type erase(key_type const& key) { return table_.erase(key); }
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& key)
|
||||
{
|
||||
return table_.erase(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_flat_map>::value,
|
||||
size_type>::type
|
||||
erase(K const& key)
|
||||
@ -530,6 +565,8 @@ namespace boost {
|
||||
|
||||
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); }
|
||||
@ -586,6 +623,11 @@ namespace boost {
|
||||
{
|
||||
return erase_if(map.table_, pred);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#endif
|
||||
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
|
@ -24,6 +24,12 @@
|
||||
|
||||
namespace boost {
|
||||
namespace unordered {
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 4714) /* marked as __forceinline not inlined */
|
||||
#endif
|
||||
|
||||
template <class Key, class Hash, class KeyEqual, class Allocator>
|
||||
class unordered_flat_set
|
||||
{
|
||||
@ -57,6 +63,9 @@ namespace boost {
|
||||
using allocator_type = Allocator;
|
||||
using reference = value_type&;
|
||||
using const_reference = value_type const&;
|
||||
using pointer = typename boost::allocator_pointer<allocator_type>::type;
|
||||
using const_pointer =
|
||||
typename boost::allocator_const_pointer<allocator_type>::type;
|
||||
using iterator = typename table_type::iterator;
|
||||
using const_iterator = typename table_type::const_iterator;
|
||||
|
||||
@ -79,6 +88,13 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_flat_set(
|
||||
InputIterator f, InputIterator l, allocator_type const& a)
|
||||
: unordered_flat_set(f, l, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
explicit unordered_flat_set(allocator_type const& a)
|
||||
: unordered_flat_set(0, a)
|
||||
{
|
||||
@ -138,6 +154,12 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
unordered_flat_set(
|
||||
std::initializer_list<value_type> il, allocator_type const& a)
|
||||
: unordered_flat_set(il, size_type(0), hasher(), key_equal(), a)
|
||||
{
|
||||
}
|
||||
|
||||
unordered_flat_set(std::initializer_list<value_type> init, size_type n,
|
||||
allocator_type const& a)
|
||||
: unordered_flat_set(init, n, hasher(), key_equal(), a)
|
||||
@ -198,22 +220,23 @@ namespace boost {
|
||||
|
||||
void clear() noexcept { table_.clear(); }
|
||||
|
||||
std::pair<iterator, bool> insert(value_type const& value)
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> insert(
|
||||
value_type const& value)
|
||||
{
|
||||
return table_.insert(value);
|
||||
}
|
||||
|
||||
std::pair<iterator, bool> insert(value_type&& value)
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> insert(value_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value));
|
||||
}
|
||||
|
||||
iterator insert(const_iterator, value_type const& value)
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, value_type const& value)
|
||||
{
|
||||
return table_.insert(value).first;
|
||||
}
|
||||
|
||||
iterator insert(const_iterator, value_type&& value)
|
||||
BOOST_FORCEINLINE iterator insert(const_iterator, value_type&& value)
|
||||
{
|
||||
return table_.insert(std::move(value)).first;
|
||||
}
|
||||
@ -231,18 +254,22 @@ namespace boost {
|
||||
this->insert(ilist.begin(), ilist.end());
|
||||
}
|
||||
|
||||
template <class... Args> std::pair<iterator, bool> emplace(Args&&... args)
|
||||
template <class... Args>
|
||||
BOOST_FORCEINLINE std::pair<iterator, bool> emplace(Args&&... args)
|
||||
{
|
||||
return table_.emplace(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
template <class... Args>
|
||||
iterator emplace_hint(const_iterator, Args&&... args)
|
||||
BOOST_FORCEINLINE iterator emplace_hint(const_iterator, Args&&... args)
|
||||
{
|
||||
return this->emplace(std::forward<Args>(args)...).first;
|
||||
return table_.emplace(std::forward<Args>(args)...).first;
|
||||
}
|
||||
|
||||
void erase(const_iterator pos) { return table_.erase(pos); }
|
||||
BOOST_FORCEINLINE void erase(const_iterator pos)
|
||||
{
|
||||
return table_.erase(pos);
|
||||
}
|
||||
iterator erase(const_iterator first, const_iterator last)
|
||||
{
|
||||
while (first != last) {
|
||||
@ -251,10 +278,13 @@ namespace boost {
|
||||
return iterator{detail::foa::const_iterator_cast_tag{}, last};
|
||||
}
|
||||
|
||||
size_type erase(key_type const& key) { return table_.erase(key); }
|
||||
BOOST_FORCEINLINE size_type erase(key_type const& key)
|
||||
{
|
||||
return table_.erase(key);
|
||||
}
|
||||
|
||||
template <class K>
|
||||
typename std::enable_if<
|
||||
BOOST_FORCEINLINE typename std::enable_if<
|
||||
detail::transparent_non_iterable<K, unordered_flat_set>::value,
|
||||
size_type>::type
|
||||
erase(K const& key)
|
||||
@ -411,6 +441,8 @@ namespace boost {
|
||||
|
||||
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); }
|
||||
@ -466,6 +498,11 @@ namespace boost {
|
||||
{
|
||||
return erase_if(set.table_, pred);
|
||||
}
|
||||
|
||||
#if defined(BOOST_MSVC)
|
||||
#pragma warning(pop) /* C4714 */
|
||||
#endif
|
||||
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
|
@ -123,6 +123,9 @@ namespace boost {
|
||||
|
||||
explicit unordered_map(size_type, const hasher&, const allocator_type&);
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_map(InputIterator, InputIterator, const allocator_type&);
|
||||
|
||||
template <class InputIt>
|
||||
unordered_map(InputIt, InputIt, size_type, const allocator_type&);
|
||||
|
||||
@ -131,6 +134,8 @@ namespace boost {
|
||||
InputIt, InputIt, size_type, const hasher&, const allocator_type&);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
unordered_map(std::initializer_list<value_type>, const allocator_type&);
|
||||
|
||||
unordered_map(
|
||||
std::initializer_list<value_type>, size_type, const allocator_type&);
|
||||
|
||||
@ -1076,6 +1081,9 @@ namespace boost {
|
||||
explicit unordered_multimap(
|
||||
size_type, const hasher&, const allocator_type&);
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_multimap(InputIterator, InputIterator, const allocator_type&);
|
||||
|
||||
template <class InputIt>
|
||||
unordered_multimap(InputIt, InputIt, size_type, const allocator_type&);
|
||||
|
||||
@ -1084,6 +1092,9 @@ namespace boost {
|
||||
InputIt, InputIt, size_type, const hasher&, const allocator_type&);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
unordered_multimap(
|
||||
std::initializer_list<value_type>, const allocator_type&);
|
||||
|
||||
unordered_multimap(
|
||||
std::initializer_list<value_type>, size_type, const allocator_type&);
|
||||
|
||||
@ -1751,6 +1762,17 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class InputIterator>
|
||||
unordered_map<K, T, H, P, A>::unordered_map(
|
||||
InputIterator f, InputIterator l, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
f, l, detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(f, l);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class InputIt>
|
||||
unordered_map<K, T, H, P, A>::unordered_map(
|
||||
@ -1773,6 +1795,16 @@ namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_map<K, T, H, P, A>::unordered_map(
|
||||
std::initializer_list<value_type> list, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
list.begin(), list.end(), detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(list.begin(), list.end());
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_map<K, T, H, P, A>::unordered_map(
|
||||
std::initializer_list<value_type> list, size_type n,
|
||||
@ -2234,6 +2266,17 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class InputIterator>
|
||||
unordered_multimap<K, T, H, P, A>::unordered_multimap(
|
||||
InputIterator f, InputIterator l, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
f, l, detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(f, l);
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
template <class InputIt>
|
||||
unordered_multimap<K, T, H, P, A>::unordered_multimap(
|
||||
@ -2256,6 +2299,16 @@ namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_multimap<K, T, H, P, A>::unordered_multimap(
|
||||
std::initializer_list<value_type> list, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
list.begin(), list.end(), detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(list.begin(), list.end());
|
||||
}
|
||||
|
||||
template <class K, class T, class H, class P, class A>
|
||||
unordered_multimap<K, T, H, P, A>::unordered_multimap(
|
||||
std::initializer_list<value_type> list, size_type n,
|
||||
|
@ -121,6 +121,9 @@ namespace boost {
|
||||
|
||||
explicit unordered_set(size_type, const hasher&, const allocator_type&);
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_set(InputIterator, InputIterator, const allocator_type&);
|
||||
|
||||
template <class InputIt>
|
||||
unordered_set(InputIt, InputIt, size_type, const allocator_type&);
|
||||
|
||||
@ -129,6 +132,8 @@ namespace boost {
|
||||
InputIt, InputIt, size_type, const hasher&, const allocator_type&);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
unordered_set(std::initializer_list<value_type>, const allocator_type&);
|
||||
|
||||
unordered_set(
|
||||
std::initializer_list<value_type>, size_type, const allocator_type&);
|
||||
|
||||
@ -739,6 +744,9 @@ namespace boost {
|
||||
explicit unordered_multiset(
|
||||
size_type, const hasher&, const allocator_type&);
|
||||
|
||||
template <class InputIterator>
|
||||
unordered_multiset(InputIterator, InputIterator, const allocator_type&);
|
||||
|
||||
template <class InputIt>
|
||||
unordered_multiset(InputIt, InputIt, size_type, const allocator_type&);
|
||||
|
||||
@ -747,6 +755,9 @@ namespace boost {
|
||||
InputIt, InputIt, size_type, const hasher&, const allocator_type&);
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
unordered_multiset(
|
||||
std::initializer_list<value_type>, const allocator_type&);
|
||||
|
||||
unordered_multiset(
|
||||
std::initializer_list<value_type>, size_type, const allocator_type&);
|
||||
|
||||
@ -1352,6 +1363,17 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
template <class InputIterator>
|
||||
unordered_set<T, H, P, A>::unordered_set(
|
||||
InputIterator f, InputIterator l, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
f, l, detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(f, l);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
template <class InputIt>
|
||||
unordered_set<T, H, P, A>::unordered_set(
|
||||
@ -1374,6 +1396,16 @@ namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_set<T, H, P, A>::unordered_set(
|
||||
std::initializer_list<value_type> list, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
list.begin(), list.end(), detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(list.begin(), list.end());
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_set<T, H, P, A>::unordered_set(
|
||||
std::initializer_list<value_type> list, size_type n,
|
||||
@ -1750,6 +1782,17 @@ namespace boost {
|
||||
{
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
template <class InputIterator>
|
||||
unordered_multiset<T, H, P, A>::unordered_multiset(
|
||||
InputIterator f, InputIterator l, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
f, l, detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(f, l);
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
template <class InputIt>
|
||||
unordered_multiset<T, H, P, A>::unordered_multiset(
|
||||
@ -1772,6 +1815,16 @@ namespace boost {
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_multiset<T, H, P, A>::unordered_multiset(
|
||||
std::initializer_list<value_type> list, const allocator_type& a)
|
||||
: table_(boost::unordered::detail::initial_size(
|
||||
list.begin(), list.end(), detail::default_bucket_count),
|
||||
hasher(), key_equal(), a)
|
||||
{
|
||||
this->insert(list.begin(), list.end());
|
||||
}
|
||||
|
||||
template <class T, class H, class P, class A>
|
||||
unordered_multiset<T, H, P, A>::unordered_multiset(
|
||||
std::initializer_list<value_type> list, size_type n,
|
||||
|
@ -97,9 +97,13 @@ run exception/merge_exception_tests.cpp ;
|
||||
|
||||
run quick.cpp ;
|
||||
|
||||
import ../../config/checks/config : requires ;
|
||||
|
||||
CPP11 = [ requires cxx11_constexpr cxx11_noexcept cxx11_decltype cxx11_alignas ] ;
|
||||
|
||||
rule build_foa ( name )
|
||||
{
|
||||
run unordered/$(name).cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_$(name) ;
|
||||
run unordered/$(name).cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_$(name) ;
|
||||
}
|
||||
|
||||
build_foa fwd_set_test ;
|
||||
@ -107,7 +111,7 @@ build_foa fwd_map_test ;
|
||||
build_foa compile_set ;
|
||||
build_foa compile_map ;
|
||||
build_foa noexcept_tests ;
|
||||
run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_link_test ;
|
||||
run unordered/link_test_1.cpp unordered/link_test_2.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_link_test ;
|
||||
build_foa incomplete_test ;
|
||||
build_foa simple_tests ;
|
||||
build_foa equivalent_keys_tests ;
|
||||
@ -127,20 +131,23 @@ build_foa load_factor_tests ;
|
||||
build_foa rehash_tests ;
|
||||
build_foa equality_tests ;
|
||||
build_foa swap_tests ;
|
||||
run unordered/scoped_allocator.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <toolset>msvc-14.0:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_scoped_allocator ;
|
||||
run unordered/scoped_allocator.cpp : : : $(CPP11) <toolset>msvc-14.0:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_scoped_allocator ;
|
||||
build_foa transparent_tests ;
|
||||
build_foa reserve_tests ;
|
||||
build_foa contains_tests ;
|
||||
build_foa erase_if ;
|
||||
build_foa scary_tests ;
|
||||
build_foa init_type_insert_tests ;
|
||||
build_foa max_load_tests ;
|
||||
|
||||
run exception/constructor_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ;
|
||||
run exception/copy_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ;
|
||||
run exception/assign_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_assign_exception_tests ;
|
||||
run exception/move_assign_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_move_assign_exception_tests ;
|
||||
run exception/insert_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_insert_exception_tests ;
|
||||
run exception/erase_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_erase_exception_tests ;
|
||||
run exception/rehash_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_rehash_exception_tests ;
|
||||
run exception/swap_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_swap_exception_tests ;
|
||||
run exception/merge_exception_tests.cpp : : : <cxxstd>98:<build>no <cxxstd>03:<build>no <cxxstd>0x:<build>no <define>BOOST_UNORDERED_FOA_TESTS : foa_merge_exception_tests ;
|
||||
run unordered/hash_is_avalanching_test.cpp ;
|
||||
|
||||
run exception/constructor_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_constructor_exception_tests ;
|
||||
run exception/copy_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_copy_exception_tests ;
|
||||
run exception/assign_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_assign_exception_tests ;
|
||||
run exception/move_assign_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_move_assign_exception_tests ;
|
||||
run exception/insert_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_insert_exception_tests ;
|
||||
run exception/erase_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_erase_exception_tests ;
|
||||
run exception/rehash_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_rehash_exception_tests ;
|
||||
run exception/swap_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_swap_exception_tests ;
|
||||
run exception/merge_exception_tests.cpp : : : $(CPP11) <define>BOOST_UNORDERED_FOA_TESTS : foa_merge_exception_tests ;
|
||||
|
@ -28,8 +28,7 @@ type_traits
|
||||
|
||||
# Secondary dependencies
|
||||
|
||||
detail
|
||||
integer
|
||||
describe
|
||||
static_assert
|
||||
winapi
|
||||
)
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
#include "./containers.hpp"
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2017-2018 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -12,7 +12,8 @@ namespace test {
|
||||
typedef enum {
|
||||
default_generator,
|
||||
generate_collisions,
|
||||
limited_range
|
||||
limited_range,
|
||||
sequential
|
||||
} random_generator;
|
||||
|
||||
int generate(int const*, random_generator);
|
||||
|
@ -12,7 +12,9 @@
|
||||
#define BOOST_UNORDERED_TEST_HELPERS_GENERATORS_HEADER
|
||||
|
||||
#include "./fwd.hpp"
|
||||
#include <boost/assert.hpp>
|
||||
#include <boost/type_traits/add_const.hpp>
|
||||
#include <climits>
|
||||
#include <cstdlib>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
@ -34,8 +36,18 @@ namespace test {
|
||||
return static_cast<std::size_t>(rand()) % max;
|
||||
}
|
||||
|
||||
static int origin = 0;
|
||||
|
||||
void reset_sequence() { origin = 0; }
|
||||
|
||||
inline int generate(int const*, random_generator g)
|
||||
{
|
||||
if (g == sequential) {
|
||||
BOOST_ASSERT_MSG(
|
||||
origin < INT_MAX, "test::reset_sequence() should be invoked");
|
||||
return origin++;
|
||||
}
|
||||
|
||||
using namespace std;
|
||||
int value = rand();
|
||||
if (g == limited_range) {
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -17,5 +17,6 @@
|
||||
#include <boost/unordered_map.hpp>
|
||||
#endif
|
||||
#include "postfix.hpp"
|
||||
// clang-format on
|
||||
|
||||
#endif
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2007-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2005-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
@ -75,6 +76,14 @@ template <class X, class T> void container_test(X& r, T const&)
|
||||
#endif
|
||||
|
||||
typedef typename X::allocator_type allocator_type;
|
||||
typedef typename X::pointer pointer;
|
||||
typedef typename X::const_pointer const_pointer;
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<pointer,
|
||||
typename boost::allocator_pointer<allocator_type>::type>::value));
|
||||
|
||||
BOOST_STATIC_ASSERT((boost::is_same<const_pointer,
|
||||
typename boost::allocator_const_pointer<allocator_type>::type>::value));
|
||||
|
||||
// value_type
|
||||
|
||||
@ -509,13 +518,11 @@ template <class X> void equality_test(X& r)
|
||||
|
||||
template <class X, class T> void unordered_unique_test(X& r, T const& t)
|
||||
{
|
||||
(void) r;
|
||||
(void) t;
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef typename X::iterator iterator;
|
||||
test::check_return_type<std::pair<iterator, bool> >::equals(r.insert(t));
|
||||
test::check_return_type<std::pair<iterator, bool> >::equals(r.emplace(t));
|
||||
|
||||
#ifndef BOOST_UNORDERED_FOA_TESTS
|
||||
typedef typename X::node_type node_type;
|
||||
typedef typename X::insert_return_type insert_return_type;
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
#include "../helpers/input_iterator.hpp"
|
||||
#include "../helpers/invariants.hpp"
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace constructor_tests {
|
||||
|
||||
test::seed_t initialize_seed(356730);
|
||||
@ -171,6 +173,16 @@ namespace constructor_tests {
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_equivalent_keys(x);
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Construct 12")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
test::random_values<T> v(1000, generator);
|
||||
T x(v.begin(), v.end(), al);
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, v);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@ -317,66 +329,206 @@ namespace constructor_tests {
|
||||
}
|
||||
|
||||
#if !defined(BOOST_NO_CXX11_HDR_INITIALIZER_LIST)
|
||||
std::initializer_list<typename T::value_type> list;
|
||||
typedef typename T::value_type value_type;
|
||||
|
||||
std::initializer_list<value_type> list;
|
||||
|
||||
test::random_values<T> v(3, generator);
|
||||
std::vector<value_type> vec(v.begin(), v.end());
|
||||
BOOST_ASSERT(vec.size() >= 3);
|
||||
|
||||
// create a new vector here because erase() requires assignability which is
|
||||
// deleted for some of the test types
|
||||
//
|
||||
std::vector<value_type> expected(vec.begin(), vec.begin() + 3);
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 1")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
{
|
||||
T x(list);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST_EQ(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
T x{vec[0], vec[1], vec[2]};
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 2")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
{
|
||||
T x(list, 1000);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
T x({vec[0], vec[1], vec[2]}, 1000);
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 1000);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 3")
|
||||
{
|
||||
test::check_instances check_;
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
T x(list, 10, hf1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x({vec[0], vec[1], vec[2]}, 10, hf1);
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 4")
|
||||
{
|
||||
test::check_instances check_;
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
T x(list, 10, hf1, eq1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x({vec[0], vec[1], vec[2]}, 10, hf1, eq1);
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 5")
|
||||
{
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x({vec[0], vec[1], vec[2]}, 10, hf1, eq1, al1);
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 6")
|
||||
{
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x({vec[0], vec[1], vec[2]}, 10, al1);
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 7")
|
||||
{
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x({vec[0], vec[1], vec[2]}, 10, hf1, al1);
|
||||
BOOST_TEST_NOT(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
|
||||
UNORDERED_SUB_TEST("Initializer list construct 8")
|
||||
{
|
||||
test::check_instances check_;
|
||||
|
||||
T x(list, 10, hf1, eq1, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(x.bucket_count() >= 10);
|
||||
BOOST_TEST(test::equivalent(x.hash_function(), hf1));
|
||||
BOOST_TEST(test::equivalent(x.key_eq(), eq1));
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
{
|
||||
T x(list, al1);
|
||||
BOOST_TEST(x.empty());
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
}
|
||||
|
||||
{
|
||||
T x({vec[0], vec[1], vec[2]}, al1);
|
||||
BOOST_TEST(test::equivalent(x.get_allocator(), al1));
|
||||
test::check_container(x, expected);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
// Copyright 2021 Christian Mazakas.
|
||||
// Copyright 2021-2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
//
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
48
test/unordered/hash_is_avalanching_test.cpp
Normal file
48
test/unordered/hash_is_avalanching_test.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
// Copyright 2022 Peter Dimov
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// https://www.boost.org/LICENSE_1_0.txt
|
||||
|
||||
// an imitation of a third-party header specializing hash_is_avalanching
|
||||
// (boost/container_hash/hash.hpp is an example doing that)
|
||||
|
||||
#include <boost/type_traits/integral_constant.hpp>
|
||||
|
||||
struct X3
|
||||
{
|
||||
};
|
||||
|
||||
namespace boost
|
||||
{
|
||||
namespace unordered
|
||||
{
|
||||
|
||||
template<class T> struct hash_is_avalanching;
|
||||
template<> struct hash_is_avalanching< ::X3 >: boost::true_type {};
|
||||
|
||||
} // namespace unordered
|
||||
} // namespace boost
|
||||
|
||||
//
|
||||
|
||||
#include <boost/unordered/hash_traits.hpp>
|
||||
#include <boost/core/lightweight_test_trait.hpp>
|
||||
|
||||
struct X1
|
||||
{
|
||||
};
|
||||
|
||||
struct X2
|
||||
{
|
||||
typedef void is_avalanching;
|
||||
};
|
||||
|
||||
int main()
|
||||
{
|
||||
using boost::unordered::hash_is_avalanching;
|
||||
|
||||
BOOST_TEST_TRAIT_FALSE((hash_is_avalanching<X1>));
|
||||
BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X2>));
|
||||
BOOST_TEST_TRAIT_TRUE((hash_is_avalanching<X3>));
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,3 +1,8 @@
|
||||
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#if !defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
#error "This test is only for the FOA-style conatiners"
|
||||
#endif
|
||||
@ -164,9 +169,76 @@ static void test_insert_tracking()
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size());
|
||||
}
|
||||
|
||||
static void test_insert_hint_tracking()
|
||||
{
|
||||
raii_tracker::reset_counts();
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 0u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
|
||||
|
||||
boost::unordered_flat_map<raii_tracker, raii_tracker,
|
||||
std::hash<raii_tracker> >
|
||||
map;
|
||||
|
||||
{
|
||||
std::pair<raii_tracker, raii_tracker> value{1, 2};
|
||||
|
||||
map.insert(map.begin(), value);
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 0u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker, raii_tracker> value{2, 3};
|
||||
|
||||
map.insert(std::move(value));
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 2u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker const, raii_tracker> value{3, 4};
|
||||
|
||||
map.insert(map.begin(), value);
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 4u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 2u);
|
||||
}
|
||||
|
||||
{
|
||||
std::pair<raii_tracker const, raii_tracker> value{4, 5};
|
||||
|
||||
map.insert(map.begin(), std::move(value));
|
||||
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 3u);
|
||||
}
|
||||
|
||||
{
|
||||
map.insert(map.begin(), std::make_pair(5, 6));
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 5u);
|
||||
}
|
||||
|
||||
{
|
||||
map.insert(map.begin(), {6, 7});
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u);
|
||||
}
|
||||
|
||||
BOOST_TEST_EQ(map.size(), 6u);
|
||||
|
||||
map.rehash(1024);
|
||||
BOOST_TEST_EQ(raii_tracker::copy_constructs, 5u);
|
||||
BOOST_TEST_EQ(raii_tracker::move_constructs, 7u + 2u * map.size());
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
test_move_only();
|
||||
test_insert_tracking();
|
||||
test_insert_hint_tracking();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
77
test/unordered/max_load_tests.cpp
Normal file
77
test/unordered/max_load_tests.cpp
Normal file
@ -0,0 +1,77 @@
|
||||
#if !defined(BOOST_UNORDERED_FOA_TESTS)
|
||||
#error "max_load_tests is currently only supported by open-addressed containers"
|
||||
#else
|
||||
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/helpers.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
template <class X> void max_load_tests(X*, test::random_generator generator)
|
||||
{
|
||||
typedef typename X::size_type size_type;
|
||||
|
||||
test::reset_sequence();
|
||||
|
||||
X x;
|
||||
size_type max_load = x.max_load();
|
||||
|
||||
BOOST_TEST_EQ(max_load, 0u);
|
||||
|
||||
x.reserve(1000);
|
||||
max_load = x.max_load();
|
||||
|
||||
size_type bucket_count = x.bucket_count();
|
||||
BOOST_TEST_GE(bucket_count, 1000u);
|
||||
|
||||
test::ordered<X> tracker;
|
||||
{
|
||||
test::random_values<X> v(max_load, generator);
|
||||
|
||||
x.insert(v.begin(), v.end());
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
BOOST_TEST_EQ(x.bucket_count(), bucket_count);
|
||||
BOOST_TEST_EQ(x.max_load(), max_load);
|
||||
BOOST_TEST_EQ(x.size(), max_load);
|
||||
}
|
||||
|
||||
{
|
||||
test::random_values<X> v(100, generator);
|
||||
|
||||
x.insert(v.begin(), v.end());
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
BOOST_TEST_GT(x.bucket_count(), bucket_count);
|
||||
BOOST_TEST_GT(x.max_load(), max_load);
|
||||
BOOST_TEST_GT(x.size(), max_load);
|
||||
}
|
||||
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
using test::default_generator;
|
||||
using test::generate_collisions;
|
||||
using test::limited_range;
|
||||
using test::sequential;
|
||||
|
||||
boost::unordered_flat_set<int>* int_set_ptr;
|
||||
boost::unordered_flat_map<test::movable, test::movable, test::hash,
|
||||
test::equal_to, test::allocator2<test::movable> >* test_map_ptr;
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
test::allocator1<test::object> >* test_set_tracking;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_map_tracking;
|
||||
|
||||
UNORDERED_TEST(max_load_tests,
|
||||
((int_set_ptr)(test_map_ptr)(test_set_tracking)(test_map_tracking))(
|
||||
(sequential)))
|
||||
#endif
|
||||
|
||||
RUN_TESTS()
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2016 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2008-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or move at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2013 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,20 +1,53 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
#include "../helpers/unordered.hpp"
|
||||
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../helpers/metafunctions.hpp"
|
||||
#include "../helpers/random_values.hpp"
|
||||
#include "../helpers/test.hpp"
|
||||
#include "../helpers/tracker.hpp"
|
||||
#include "../objects/test.hpp"
|
||||
|
||||
namespace rehash_tests {
|
||||
|
||||
test::seed_t initialize_seed(2974);
|
||||
|
||||
static int count_allocations;
|
||||
template <class T> struct monotonic_allocator
|
||||
{
|
||||
typedef T value_type;
|
||||
monotonic_allocator() {}
|
||||
monotonic_allocator(monotonic_allocator const&) {}
|
||||
|
||||
template <class U> monotonic_allocator(monotonic_allocator<U> const&) {}
|
||||
|
||||
friend bool operator==(
|
||||
monotonic_allocator const&, monotonic_allocator const&)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
friend bool operator!=(
|
||||
monotonic_allocator const&, monotonic_allocator const&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
T* allocate(std::size_t n)
|
||||
{
|
||||
++count_allocations;
|
||||
return static_cast<T*>(::operator new(sizeof(T) * n));
|
||||
}
|
||||
|
||||
void deallocate(T* p, std::size_t) { ::operator delete(p); }
|
||||
};
|
||||
|
||||
void reset_counts() { count_allocations = 0; }
|
||||
|
||||
template <class X> bool postcondition(X const& x, typename X::size_type n)
|
||||
{
|
||||
return static_cast<double>(x.bucket_count()) >=
|
||||
@ -320,9 +353,10 @@ namespace rehash_tests {
|
||||
BOOST_TEST_GT(x.bucket_count(), 0u);
|
||||
|
||||
x.reserve(
|
||||
2 * (static_cast<size_type>(
|
||||
std::floor(static_cast<float>(x.size()) / x.max_load_factor()) +
|
||||
std::floor(static_cast<float>(x.size()) * x.max_load_factor()))));
|
||||
2 *
|
||||
(static_cast<size_type>(
|
||||
std::floor(static_cast<float>(x.size()) / x.max_load_factor()) +
|
||||
std::floor(static_cast<float>(x.size()) * x.max_load_factor()))));
|
||||
|
||||
BOOST_TEST_GT(x.bucket_count(), bucket_count);
|
||||
|
||||
@ -375,6 +409,34 @@ namespace rehash_tests {
|
||||
}
|
||||
}
|
||||
|
||||
template <class X> void rehash_stability(X*, test::random_generator generator)
|
||||
{
|
||||
reset_counts();
|
||||
|
||||
typedef typename X::size_type size_type;
|
||||
|
||||
size_type bucket_count = 100;
|
||||
X x(bucket_count);
|
||||
|
||||
size_type num_elems = x.bucket_count() - 1;
|
||||
|
||||
test::random_values<X> v(num_elems, generator);
|
||||
test::ordered<X> tracker;
|
||||
tracker.insert_range(v.begin(), v.end());
|
||||
|
||||
typename test::random_values<X>::iterator pos = v.begin();
|
||||
for (size_type i = 0; i < num_elems; ++i) {
|
||||
x.insert(*pos);
|
||||
++pos;
|
||||
}
|
||||
|
||||
int const old_count = count_allocations;
|
||||
x.rehash(0);
|
||||
|
||||
BOOST_TEST_EQ(count_allocations, old_count);
|
||||
tracker.compare(x);
|
||||
}
|
||||
|
||||
template <class X> void rehash_test1(X*, test::random_generator generator)
|
||||
{
|
||||
test::random_values<X> v(1000, generator);
|
||||
@ -512,6 +574,13 @@ namespace rehash_tests {
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_map_tracking;
|
||||
|
||||
boost::unordered_flat_set<test::object, test::hash, test::equal_to,
|
||||
monotonic_allocator<test::object> >* test_set_monotonic;
|
||||
boost::unordered_flat_map<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
monotonic_allocator<std::pair<test::object const, test::object> > >*
|
||||
test_map_monotonic;
|
||||
|
||||
UNORDERED_TEST(rehash_empty_test1, ((int_set_ptr)(test_map_ptr)))
|
||||
UNORDERED_TEST(rehash_empty_test2,
|
||||
((int_set_ptr)(test_map_ptr))(
|
||||
@ -533,9 +602,11 @@ namespace rehash_tests {
|
||||
UNORDERED_TEST(rehash_empty_tracking,
|
||||
((test_set_tracking)(test_map_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_nonempty_tracking,
|
||||
((test_set_tracking)(test_map_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(
|
||||
rehash_nonempty_tracking, ((test_set_tracking)(test_map_tracking))(
|
||||
(default_generator)(limited_range)))
|
||||
UNORDERED_TEST(rehash_stability, ((test_set_monotonic)(test_map_monotonic))(
|
||||
(default_generator)(limited_range)))
|
||||
#else
|
||||
boost::unordered_set<int>* int_set_ptr;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
@ -556,6 +627,18 @@ namespace rehash_tests {
|
||||
test::allocator1<std::pair<test::object const, test::object> > >*
|
||||
test_multimap_tracking;
|
||||
|
||||
boost::unordered_set<test::object, test::hash, test::equal_to,
|
||||
monotonic_allocator<test::object> >* test_set_monotonic;
|
||||
boost::unordered_multiset<test::object, test::hash, test::equal_to,
|
||||
monotonic_allocator<test::object> >* test_multiset_monotonic;
|
||||
boost::unordered_map<test::object, test::object, test::hash, test::equal_to,
|
||||
monotonic_allocator<std::pair<test::object const, test::object> > >*
|
||||
test_map_monotonic;
|
||||
boost::unordered_multimap<test::object, test::object, test::hash,
|
||||
test::equal_to,
|
||||
monotonic_allocator<std::pair<test::object const, test::object> > >*
|
||||
test_multimap_monotonic;
|
||||
|
||||
UNORDERED_TEST(rehash_empty_test1,
|
||||
((int_set_ptr)(test_multiset_ptr)(test_map_ptr)(int_multimap_ptr)))
|
||||
UNORDERED_TEST(rehash_empty_test2,
|
||||
@ -583,7 +666,10 @@ namespace rehash_tests {
|
||||
UNORDERED_TEST(rehash_nonempty_tracking,
|
||||
((test_set_tracking)(test_multiset_tracking)(test_map_tracking)(test_multimap_tracking))(
|
||||
(default_generator)(generate_collisions)(limited_range)))
|
||||
UNORDERED_TEST(rehash_stability,
|
||||
((test_set_monotonic)(test_multiset_monotonic)(test_map_monotonic)(test_multimap_monotonic))(
|
||||
(default_generator)(limited_range)))
|
||||
#endif
|
||||
}
|
||||
} // namespace rehash_tests
|
||||
|
||||
RUN_TESTS()
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
|
||||
// Copyright 2006-2009 Daniel James.
|
||||
// Copyright 2022 Christian Mazakas.
|
||||
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||
|
||||
|
Reference in New Issue
Block a user