Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f864ea3ade |
@@ -31,65 +31,106 @@ environment:
|
|||||||
B2_VARIANT: debug,release
|
B2_VARIANT: debug,release
|
||||||
|
|
||||||
matrix:
|
matrix:
|
||||||
- FLAVOR: MinGW-w64 (32 bit, C++11)
|
- FLAVOR: Visual Studio 2008, 2010, 2012
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
B2_TOOLSET: msvc-9.0,msvc-10.0,msvc-11.0
|
||||||
B2_CXXFLAGS: -g0 # Reduce compiler's memory consumption
|
B2_ADDRESS_MODEL: 32 # No 64bit support
|
||||||
B2_CXXSTD: 11
|
|
||||||
B2_TOOLSET: gcc
|
|
||||||
B2_ADDRESS_MODEL: 32
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (32 bit, C++14)
|
- FLAVOR: Visual Studio 2013, 2015
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
B2_TOOLSET: msvc-12.0,msvc-14.0
|
||||||
B2_CXXFLAGS: -g0 # Reduce compiler's memory consumption
|
|
||||||
B2_CXXSTD: 14
|
|
||||||
B2_TOOLSET: gcc
|
|
||||||
B2_ADDRESS_MODEL: 32
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (32 bit, C++17)
|
- FLAVOR: Visual Studio 2017 C++14/17
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
B2_CXXSTD: 14,17
|
||||||
B2_CXXFLAGS: -g0 # Reduce compiler's memory consumption
|
B2_TOOLSET: msvc-14.1
|
||||||
B2_CXXSTD: 17
|
|
||||||
B2_TOOLSET: gcc
|
|
||||||
B2_ADDRESS_MODEL: 32
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (32 bit, C++2a)
|
- FLAVOR: Visual Studio 2017 C++2a Strict
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
ADDPATH: C:\mingw-w64\i686-8.1.0-posix-dwarf-rt_v6-rev0\mingw32\bin;
|
B2_CXXFLAGS: -permissive-
|
||||||
B2_CXXFLAGS: -g0 # Reduce compiler's memory consumption
|
|
||||||
B2_CXXSTD: 2a
|
B2_CXXSTD: 2a
|
||||||
B2_TOOLSET: gcc
|
B2_TOOLSET: msvc-14.1
|
||||||
B2_ADDRESS_MODEL: 32
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (64 bit, C++11)
|
- FLAVOR: Visual Studio 2019
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
B2_CXXFLAGS: -permissive-
|
||||||
B2_CXXSTD: 11
|
B2_CXXSTD: 14,17
|
||||||
B2_TOOLSET: gcc
|
B2_TOOLSET: msvc-14.2
|
||||||
B2_ADDRESS_MODEL: 64
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (64 bit, C++14)
|
- FLAVOR: Visual Studio 2022
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
B2_CXXFLAGS: -permissive-
|
||||||
B2_CXXSTD: 14
|
B2_CXXSTD: 14,17
|
||||||
B2_TOOLSET: gcc
|
B2_TOOLSET: msvc-14.3
|
||||||
B2_ADDRESS_MODEL: 64
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (64 bit, C++17)
|
# C++20 Jobs split out from above due to build timeout
|
||||||
|
- FLAVOR: Visual Studio 2019 C++2a
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
B2_CXXFLAGS: -permissive-
|
||||||
B2_CXXSTD: 17
|
|
||||||
B2_TOOLSET: gcc
|
|
||||||
B2_ADDRESS_MODEL: 64
|
|
||||||
|
|
||||||
- FLAVOR: MinGW-w64 (64 bit, C++2a)
|
|
||||||
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
|
||||||
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
|
||||||
B2_CXXSTD: 2a
|
B2_CXXSTD: 2a
|
||||||
|
B2_TOOLSET: msvc-14.2
|
||||||
|
|
||||||
|
- FLAVOR: Visual Studio 2022 C++20
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||||
|
B2_CXXFLAGS: -permissive-
|
||||||
|
B2_CXXSTD: 20
|
||||||
|
B2_TOOLSET: msvc-14.3
|
||||||
|
|
||||||
|
- FLAVOR: clang-cl C++11, C++14
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
|
B2_CXXSTD: 11,14
|
||||||
|
B2_TOOLSET: clang-win
|
||||||
|
# Extra job as compilation takes to long
|
||||||
|
- FLAVOR: clang-cl C++17, C++latest
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
|
B2_CXXSTD: 17,latest
|
||||||
|
B2_TOOLSET: clang-win
|
||||||
|
|
||||||
|
- FLAVOR: cygwin (32-bit)
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
ADDPATH: C:\cygwin\bin;
|
||||||
|
B2_ADDRESS_MODEL: 32
|
||||||
|
B2_CXXSTD: 03,11,14,1z
|
||||||
B2_TOOLSET: gcc
|
B2_TOOLSET: gcc
|
||||||
|
|
||||||
|
- FLAVOR: cygwin (64-bit)
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
|
||||||
|
ADDPATH: C:\cygwin64\bin;
|
||||||
B2_ADDRESS_MODEL: 64
|
B2_ADDRESS_MODEL: 64
|
||||||
|
B2_CXXSTD: 03,11,14,1z
|
||||||
|
B2_TOOLSET: gcc
|
||||||
|
|
||||||
|
# (Currently) the images up to 2017 use an older Cygwin
|
||||||
|
# This tests that the library works with more recent versions
|
||||||
|
- FLAVOR: cygwin (64-bit, latest)
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2022
|
||||||
|
ADDPATH: C:\cygwin64\bin;
|
||||||
|
B2_ADDRESS_MODEL: 64
|
||||||
|
B2_CXXSTD: 03,11,14,1z
|
||||||
|
B2_TOOLSET: gcc
|
||||||
|
MAYFAIL: true
|
||||||
|
|
||||||
|
- FLAVOR: mingw32
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
|
||||||
|
B2_ADDRESS_MODEL: 32
|
||||||
|
ADDPATH: C:\mingw\bin;
|
||||||
|
B2_CXXSTD: 03,11,14,1z
|
||||||
|
B2_TOOLSET: gcc
|
||||||
|
MAYFAIL: true
|
||||||
|
|
||||||
|
- FLAVOR: mingw64
|
||||||
|
APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
|
ADDPATH: C:\mingw-w64\x86_64-8.1.0-posix-seh-rt_v6-rev0\mingw64\bin;
|
||||||
|
B2_ADDRESS_MODEL: 64
|
||||||
|
B2_CXXSTD: 03,11,14,17,2a
|
||||||
|
B2_TOOLSET: gcc
|
||||||
|
|
||||||
|
#- FLAVOR: CodeCov (VS 2019)
|
||||||
|
# APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
|
||||||
|
# B2_CXXFLAGS: -permissive-
|
||||||
|
# B2_CXXSTD: 14
|
||||||
|
# B2_TOOLSET: msvc-14.2
|
||||||
|
# COVERAGE: true
|
||||||
|
|
||||||
install:
|
install:
|
||||||
- git clone --depth 1 https://github.com/boostorg/boost-ci.git C:\boost-ci-cloned
|
- git clone --depth 1 https://github.com/boostorg/boost-ci.git C:\boost-ci-cloned
|
||||||
|
|||||||
@@ -1,513 +0,0 @@
|
|||||||
# Copyright 2022 Peter Dimov
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
local library = "unordered";
|
|
||||||
|
|
||||||
local triggers =
|
|
||||||
{
|
|
||||||
branch: [ "master", "develop", "feature/*", "bugfix/*", "fix/*", "pr/*" ]
|
|
||||||
};
|
|
||||||
|
|
||||||
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
|
|
||||||
local asan = { ASAN: '1' };
|
|
||||||
local tsan = { TSAN: '1' };
|
|
||||||
|
|
||||||
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
|
|
||||||
{
|
|
||||||
name: name,
|
|
||||||
kind: "pipeline",
|
|
||||||
type: "docker",
|
|
||||||
trigger: triggers,
|
|
||||||
platform:
|
|
||||||
{
|
|
||||||
os: "linux",
|
|
||||||
arch: arch
|
|
||||||
},
|
|
||||||
steps:
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name: "everything",
|
|
||||||
image: image,
|
|
||||||
environment: environment,
|
|
||||||
privileged: true,
|
|
||||||
commands:
|
|
||||||
[
|
|
||||||
'set -e',
|
|
||||||
'echo $DRONE_STAGE_MACHINE',
|
|
||||||
'uname -a',
|
|
||||||
'curl -sSL --retry 5 https://apt.llvm.org/llvm-snapshot.gpg.key | sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/llvm-snapshot.gpg',
|
|
||||||
] +
|
|
||||||
(if sources != [] then [ ('apt-add-repository "' + source + '"') for source in sources ] else []) +
|
|
||||||
(if packages != "" then [ 'apt-get update', 'apt-get -y install ' + packages ] else []) +
|
|
||||||
[
|
|
||||||
'export LIBRARY=' + library,
|
|
||||||
'./.drone/drone.sh',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
local macos_pipeline(name, environment, xcode_version = "12.2", osx_version = "catalina", arch = "amd64") =
|
|
||||||
{
|
|
||||||
name: name,
|
|
||||||
kind: "pipeline",
|
|
||||||
type: "exec",
|
|
||||||
trigger: triggers,
|
|
||||||
platform: {
|
|
||||||
"os": "darwin",
|
|
||||||
"arch": arch
|
|
||||||
},
|
|
||||||
node: {
|
|
||||||
"os": osx_version
|
|
||||||
},
|
|
||||||
steps: [
|
|
||||||
{
|
|
||||||
name: "everything",
|
|
||||||
environment: environment + { "DEVELOPER_DIR": "/Applications/Xcode-" + xcode_version + ".app/Contents/Developer" },
|
|
||||||
commands:
|
|
||||||
[
|
|
||||||
'echo $DRONE_STAGE_MACHINE',
|
|
||||||
'sw_vers',
|
|
||||||
'uname -a',
|
|
||||||
'export LIBRARY=' + library,
|
|
||||||
'./.drone/drone.sh',
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
local windows_pipeline(name, image, environment, arch = "amd64") =
|
|
||||||
{
|
|
||||||
name: name,
|
|
||||||
kind: "pipeline",
|
|
||||||
type: "docker",
|
|
||||||
trigger: triggers,
|
|
||||||
platform:
|
|
||||||
{
|
|
||||||
os: "windows",
|
|
||||||
arch: arch
|
|
||||||
},
|
|
||||||
"steps":
|
|
||||||
[
|
|
||||||
{
|
|
||||||
name: "everything",
|
|
||||||
image: image,
|
|
||||||
environment: environment,
|
|
||||||
commands:
|
|
||||||
[
|
|
||||||
'echo $env:DRONE_STAGE_MACHINE',
|
|
||||||
'cmd /C .drone\\\\drone.bat ' + library,
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
[
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 14.04 GCC 4.8* 32/64",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.8', CXXSTD: '11', ADDRMD: '32,64' },
|
|
||||||
"g++-4.8-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 14.04 GCC 4.9 32/64",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-4.9', CXXSTD: '11', ADDRMD: '32,64' },
|
|
||||||
"g++-4.9-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 16.04 GCC 5* 32/64",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 GCC 6 32/64",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-6', CXXSTD: '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: '11,14,17', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 GCC 8 32/64 (11)",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '11', ADDRMD: '32,64' },
|
|
||||||
"g++-8-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 GCC 8 32/64 (14,17)",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '14,17', ADDRMD: '32,64' },
|
|
||||||
"g++-8-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 9* 32/64 (11,14)",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 9* 32/64 (17,2a)",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 9* ARM64",
|
|
||||||
"cppalliance/droneubuntu2004:multiarch",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14,17,2a' },
|
|
||||||
arch="arm64",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 9* S390x (11,14)",
|
|
||||||
"cppalliance/droneubuntu2004:multiarch",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14' },
|
|
||||||
arch="s390x",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 9* S390x (17,2a)",
|
|
||||||
"cppalliance/droneubuntu2004:multiarch",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a' },
|
|
||||||
arch="s390x",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 10 32/64 (11,14)",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '11,14', ADDRMD: '32,64' },
|
|
||||||
"g++-10-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 GCC 10 32/64 (17,20)",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '17,20', ADDRMD: '32,64' },
|
|
||||||
"g++-10-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 11* 32/64 (11,14)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '11,14', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 11* 32/64 (17,2a)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 32 ASAN (11,14)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11', ADDRMD: '32' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 32 ASAN (14)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '14', ADDRMD: '32' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 32 ASAN (17)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17', ADDRMD: '32' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 32 ASAN (20)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '20', ADDRMD: '32' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 32 ASAN (2b)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '32' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 64 ASAN (11,14)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14', ADDRMD: '64' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 64 ASAN (17)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17', ADDRMD: '64' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 64 ASAN (20)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '20', ADDRMD: '64' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 64 ASAN (2b)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '64' } + asan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 GCC 12 64 TSAN (11,14,17,20,2b)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20,2b', ADDRMD: '64', TARGET: 'libs/unordered/test//cfoa_tests' } + tsan,
|
|
||||||
"g++-12-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 23.04 GCC 13 32/64 (11,14)",
|
|
||||||
"cppalliance/droneubuntu2404:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '11,14', ADDRMD: '32,64' },
|
|
||||||
"g++-13 g++-13-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 23.04 GCC 13 32/64 (17,20,2b)",
|
|
||||||
"cppalliance/droneubuntu2404:1",
|
|
||||||
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '17,20,2b', ADDRMD: '32,64' },
|
|
||||||
"g++-13 g++-13-multilib",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 16.04 Clang 3.5",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.5', CXXSTD: '11' },
|
|
||||||
"clang-3.5",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 16.04 Clang 3.6",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.6', CXXSTD: '11,14' },
|
|
||||||
"clang-3.6",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 16.04 Clang 3.7",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.7', CXXSTD: '11,14' },
|
|
||||||
"clang-3.7",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 16.04 Clang 3.8",
|
|
||||||
"cppalliance/droneubuntu1604:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.8', CXXSTD: '11,14' },
|
|
||||||
"clang-3.8",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 Clang 3.9",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-3.9', CXXSTD: '11,14' },
|
|
||||||
"clang-3.9",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 Clang 4.0",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-4.0', CXXSTD: '11,14' },
|
|
||||||
"clang-4.0",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 Clang 5.0",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-5.0', CXXSTD: '11,14,1z' },
|
|
||||||
"clang-5.0",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 18.04 Clang 6.0",
|
|
||||||
"cppalliance/droneubuntu1804:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-6.0', CXXSTD: '11,14,17' },
|
|
||||||
"clang-6.0",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 Clang 7",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-7', CXXSTD: '11,14,17' },
|
|
||||||
"clang-7",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 Clang 8",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-8', CXXSTD: '11,14,17' },
|
|
||||||
"clang-8",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 Clang 9",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-9', CXXSTD: '11,14,17,2a' },
|
|
||||||
"clang-9",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 Clang 10",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-10', CXXSTD: '11,14,17,2a' },
|
|
||||||
"clang-10",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 Clang 11",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-11', CXXSTD: '11,14,17,2a' },
|
|
||||||
"clang-11",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 20.04 Clang 12",
|
|
||||||
"cppalliance/droneubuntu2004:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-12', CXXSTD: '11,14,17,2a' },
|
|
||||||
"clang-12",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 13",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-13', CXXSTD: '11,14,17,20' },
|
|
||||||
"clang-13",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 14 UBSAN (11,14)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14' } + ubsan,
|
|
||||||
"clang-14",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 14 UBSAN (17,20)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '17,20' } + ubsan,
|
|
||||||
"clang-14",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 14 ASAN (11,14)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '11,14' } + asan,
|
|
||||||
"clang-14",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 14 ASAN (17,20)",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '17,20' } + asan,
|
|
||||||
"clang-14",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 14 libc++ 64 TSAN",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-14', ADDRMD: '64', TARGET: 'libs/unordered/test//cfoa_tests', CXXSTD: '11,14,17,20', STDLIB: 'libc++' } + tsan,
|
|
||||||
"clang-14 libc++-14-dev libc++abi-14-dev",
|
|
||||||
),
|
|
||||||
|
|
||||||
linux_pipeline(
|
|
||||||
"Linux 22.04 Clang 15",
|
|
||||||
"cppalliance/droneubuntu2204:1",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++-15', CXXSTD: '11,14,17,20,2b' },
|
|
||||||
"clang-15",
|
|
||||||
["deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-15 main"],
|
|
||||||
),
|
|
||||||
|
|
||||||
macos_pipeline(
|
|
||||||
"MacOS 10.15 Xcode 12.2 UBSAN (11)",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11' } + ubsan,
|
|
||||||
),
|
|
||||||
|
|
||||||
macos_pipeline(
|
|
||||||
"MacOS 10.15 Xcode 12.2 UBSAN (14)",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '14' } + ubsan,
|
|
||||||
),
|
|
||||||
|
|
||||||
macos_pipeline(
|
|
||||||
"MacOS 10.15 Xcode 12.2 UBSAN (1z)",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '1z' } + ubsan,
|
|
||||||
),
|
|
||||||
|
|
||||||
macos_pipeline(
|
|
||||||
"MacOS 12.4 Xcode 13.4.1 ASAN",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z' } + asan,
|
|
||||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
|
||||||
),
|
|
||||||
|
|
||||||
macos_pipeline(
|
|
||||||
"MacOS 12.4 Xcode 13.4.1 TSAN",
|
|
||||||
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z', TARGET: 'libs/unordered/test//cfoa_tests' } + tsan,
|
|
||||||
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2015 msvc-14.0",
|
|
||||||
"cppalliance/dronevs2015",
|
|
||||||
{ TOOLSET: 'msvc-14.0', CXXSTD: '14,latest', 'B2_DONT_EMBED_MANIFEST': 1 },
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2017 msvc-14.1",
|
|
||||||
"cppalliance/dronevs2017",
|
|
||||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17,latest', ADDRMD: '32,64' },
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2017 msvc-14.1 permissive-",
|
|
||||||
"cppalliance/dronevs2017",
|
|
||||||
{ TOOLSET: 'msvc-14.1', CXXSTD: '14,17', CXXFLAGS: '/permissive-' },
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2019 msvc-14.2",
|
|
||||||
"cppalliance/dronevs2019",
|
|
||||||
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17,20,latest' },
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2019 msvc-14.2 permissive-",
|
|
||||||
"cppalliance/dronevs2019",
|
|
||||||
{ TOOLSET: 'msvc-14.2', CXXSTD: '14,17', CXXFLAGS: '/permissive-' },
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2022 msvc-14.3",
|
|
||||||
"cppalliance/dronevs2022:1",
|
|
||||||
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17,20,latest' },
|
|
||||||
),
|
|
||||||
|
|
||||||
windows_pipeline(
|
|
||||||
"Windows VS2022 msvc-14.3 permissive-",
|
|
||||||
"cppalliance/dronevs2022:1",
|
|
||||||
{ TOOLSET: 'msvc-14.3', CXXSTD: '14,17', CXXFLAGS: '/permissive-' },
|
|
||||||
),
|
|
||||||
]
|
|
||||||
@@ -1,24 +0,0 @@
|
|||||||
@REM Copyright 2022 Peter Dimov
|
|
||||||
@REM Distributed under the Boost Software License, Version 1.0.
|
|
||||||
@REM https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
@ECHO ON
|
|
||||||
|
|
||||||
set LIBRARY=%1
|
|
||||||
set DRONE_BUILD_DIR=%CD%
|
|
||||||
|
|
||||||
set BOOST_BRANCH=develop
|
|
||||||
if "%DRONE_BRANCH%" == "master" set BOOST_BRANCH=master
|
|
||||||
cd ..
|
|
||||||
git clone -b %BOOST_BRANCH% --depth 1 https://github.com/boostorg/boost.git boost-root
|
|
||||||
cd boost-root
|
|
||||||
git submodule update --init tools/boostdep
|
|
||||||
xcopy /s /e /q %DRONE_BUILD_DIR% libs\%LIBRARY%\
|
|
||||||
python tools/boostdep/depinst/depinst.py %LIBRARY%
|
|
||||||
cmd /c bootstrap
|
|
||||||
b2 -d0 headers
|
|
||||||
|
|
||||||
if not "%CXXSTD%" == "" set CXXSTD=cxxstd=%CXXSTD%
|
|
||||||
if not "%ADDRMD%" == "" set ADDRMD=address-model=%ADDRMD%
|
|
||||||
if not "%CXXFLAGS%" == "" set CXXFLAGS=cxxflags=%CXXFLAGS%
|
|
||||||
b2 --abbreviate-paths -j3 libs/%LIBRARY%/test toolset=%TOOLSET% %CXXSTD% %ADDRMD% %CXXFLAGS% variant=debug,release embed-manifest-via=linker
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# Copyright 2022 Peter Dimov
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
export PATH=~/.local/bin:/usr/local/bin:$PATH
|
|
||||||
|
|
||||||
: ${TARGET:="libs/$LIBRARY/test"}
|
|
||||||
|
|
||||||
DRONE_BUILD_DIR=$(pwd)
|
|
||||||
|
|
||||||
BOOST_BRANCH=develop
|
|
||||||
if [ "$DRONE_BRANCH" = "master" ]; then BOOST_BRANCH=master; fi
|
|
||||||
|
|
||||||
if [[ $(uname) == "Linux" && ( "$TSAN" == 1 || "$ASAN" == 1 ) ]]; then
|
|
||||||
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
|
|
||||||
sudo sysctl vm.mmap_rnd_bits=28
|
|
||||||
fi
|
|
||||||
|
|
||||||
cd ..
|
|
||||||
git clone -b $BOOST_BRANCH --depth 1 https://github.com/boostorg/boost.git boost-root
|
|
||||||
cd boost-root
|
|
||||||
git submodule update --init tools/boostdep
|
|
||||||
cp -r $DRONE_BUILD_DIR/* libs/$LIBRARY
|
|
||||||
python tools/boostdep/depinst/depinst.py $LIBRARY
|
|
||||||
./bootstrap.sh
|
|
||||||
./b2 -d0 headers
|
|
||||||
|
|
||||||
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
|
|
||||||
./b2 -j3 $TARGET toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${STDLIB:+stdlib=$STDLIB} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${TSAN:+thread-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
|
|
||||||
@@ -32,16 +32,6 @@ env:
|
|||||||
CODECOV_NAME: Github Actions
|
CODECOV_NAME: Github Actions
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
runner-selection:
|
|
||||||
# runs-on: ubuntu-latest
|
|
||||||
runs-on: ${{ github.repository_owner == 'boostorg' && fromJSON('[ "self-hosted", "linux", "x64", "ubuntu-latest-aws" ]') || 'ubuntu-latest' }}
|
|
||||||
outputs:
|
|
||||||
labelmatrix: ${{ steps.aws_hosted_runners.outputs.labelmatrix }}
|
|
||||||
steps:
|
|
||||||
- name: AWS Hosted Runners
|
|
||||||
id: aws_hosted_runners
|
|
||||||
uses: cppalliance/aws-hosted-runners@v1.0.0
|
|
||||||
|
|
||||||
posix:
|
posix:
|
||||||
defaults:
|
defaults:
|
||||||
run:
|
run:
|
||||||
@@ -52,89 +42,49 @@ jobs:
|
|||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
# Linux, gcc
|
# Linux, gcc
|
||||||
- { compiler: gcc-7, cxxstd: '11,14,17', os: 'ubuntu-20.04', install: 'g++-7' }
|
- { compiler: gcc-4.8, cxxstd: '03,11', os: ubuntu-18.04 }
|
||||||
- { compiler: gcc-8, cxxstd: '11,14,17', os: 'ubuntu-20.04', install: 'g++-8' }
|
- { compiler: gcc-4.9, cxxstd: '03,11', os: ubuntu-20.04, container: 'ubuntu:16.04' }
|
||||||
- { compiler: gcc-9, cxxstd: '11,14,17', os: 'ubuntu-22.04', install: 'g++-9' }
|
- { compiler: gcc-5, cxxstd: '03,11,14,1z', os: ubuntu-18.04 }
|
||||||
- { compiler: gcc-10, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-10' }
|
- { compiler: gcc-6, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||||
- { compiler: gcc-11, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-11' }
|
- { compiler: gcc-7, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||||
- { compiler: gcc-12, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', install: 'g++-12' }
|
- { compiler: gcc-8, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04 }
|
||||||
- { compiler: gcc-13, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-13' }
|
- { compiler: gcc-9, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04 }
|
||||||
- { compiler: gcc-14, cxxstd: '11,14,17,20', os: 'ubuntu-24.04', install: 'g++-14' }
|
- { compiler: gcc-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||||
- { compiler: gcc-16, cxxstd: '11,14,17', container: 'ubuntu:26.04', os: 'ubuntu-latest', install: 'g++-16-multilib' }
|
- { compiler: gcc-11, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||||
- { compiler: gcc-16, cxxstd: '20,23,2c', container: 'ubuntu:26.04', os: 'ubuntu-latest', install: 'g++-16-multilib' }
|
- { compiler: gcc-12, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||||
|
- { name: GCC w/ sanitizers, sanitize: yes,
|
||||||
- { name: "gcc-14 w/ sanitizers (11)", sanitize: yes,
|
compiler: gcc-12, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||||
compiler: gcc-14, cxxstd: '11', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" }
|
|
||||||
- { name: "gcc-14 w/ sanitizers (14)", sanitize: yes,
|
|
||||||
compiler: gcc-14, cxxstd: '14', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san1" }
|
|
||||||
- { name: "gcc-14 w/ sanitizers (17)", sanitize: yes,
|
|
||||||
compiler: gcc-14, cxxstd: '17', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
|
|
||||||
- { name: "gcc-14 w/ sanitizers (20)", sanitize: yes,
|
|
||||||
compiler: gcc-14, cxxstd: '20', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
|
|
||||||
- { name: "gcc-14 w/ sanitizers (2b)", sanitize: yes,
|
|
||||||
compiler: gcc-14, cxxstd: '2b', os: 'ubuntu-24.04', install: 'g++-14', ccache_key: "san2" }
|
|
||||||
- { name: Collect coverage, coverage: yes,
|
- { name: Collect coverage, coverage: yes,
|
||||||
compiler: gcc-14, cxxstd: '20', os: 'ubuntu-24.04', install: 'g++-14 g++-14-multilib', address-model: '32,64', ccache_key: "cov" }
|
compiler: gcc-8, cxxstd: '03,11', os: ubuntu-20.04, install: 'g++-8-multilib', address-model: '32,64' }
|
||||||
- { name: "cfoa tsan (gcc-14)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-24.04', install: 'g++-14', compiler: gcc-14,
|
|
||||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes, ccache_key: "tsan" }
|
|
||||||
|
|
||||||
# Linux, clang, libc++
|
# Linux, clang
|
||||||
- { compiler: clang-7, cxxstd: '11,14,17', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
|
- { compiler: clang-3.7, cxxstd: '03,11,14', os: ubuntu-20.04, container: 'ubuntu:16.04' }
|
||||||
- { compiler: clang-10, cxxstd: '11,14,17,20', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-10 libc++-10-dev libc++abi-10-dev' }
|
- { compiler: clang-3.8, cxxstd: '03,11,14', os: ubuntu-20.04, container: 'ubuntu:16.04' }
|
||||||
- { compiler: clang-11, cxxstd: '11,14,17,20', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-11 libc++-11-dev libc++abi-11-dev' }
|
- { compiler: clang-3.9, cxxstd: '03,11,14', os: ubuntu-18.04 }
|
||||||
# clang-12 doesn't work on 'ubuntu-22.04', the linker can't find -lunwind for some reason
|
- { compiler: clang-4.0, cxxstd: '03,11,14', os: ubuntu-18.04 }
|
||||||
- { name: "clang-12 w/ sanitizers (11,14)", sanitize: yes,
|
- { compiler: clang-5.0, cxxstd: '03,11,14,1z', os: ubuntu-18.04 }
|
||||||
compiler: clang-12, cxxstd: '11,14', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san1" }
|
- { compiler: clang-6.0, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||||
- { name: "clang-12 w/ sanitizers (17)", sanitize: yes,
|
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-18.04 }
|
||||||
compiler: clang-12, cxxstd: '17', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
# Note: clang-8 does not fully support C++20, so it is not compatible with some libstdc++ versions in this mode
|
||||||
- { name: "clang-12 w/ sanitizers (20)", sanitize: yes,
|
- { compiler: clang-8, cxxstd: '03,11,14,17,2a', os: ubuntu-18.04, install: 'clang-8 g++-7', gcc_toolchain: 7 }
|
||||||
compiler: clang-12, cxxstd: '20', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
- { compiler: clang-9, cxxstd: '03,11,14,17,2a', os: ubuntu-20.04 }
|
||||||
- { name: "clang-12 w/ sanitizers (2b)", sanitize: yes,
|
- { compiler: clang-10, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||||
compiler: clang-12, cxxstd: '2b', os: 'ubuntu-20.04', stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
|
- { compiler: clang-11, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||||
- { compiler: 'clang-13', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
- { compiler: clang-12, cxxstd: '03,11,14,17,20', os: ubuntu-20.04 }
|
||||||
- { compiler: 'clang-13', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
|
- { compiler: clang-13, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||||
- { compiler: 'clang-14', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
- { compiler: clang-14, cxxstd: '03,11,14,17,20', os: ubuntu-22.04 }
|
||||||
- { compiler: 'clang-14', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
|
|
||||||
- { compiler: 'clang-15', cxxstd: '11,14', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
|
||||||
- { compiler: 'clang-15', cxxstd: '17,20,2b', os: 'ubuntu-22.04', stdlib: libc++, install: 'clang-15 libc++-15-dev libc++abi-15-dev' }
|
|
||||||
- { compiler: 'clang-16', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-16 libc++-16-dev libc++abi-16-dev' }
|
|
||||||
- { compiler: 'clang-16', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-16 libc++-16-dev libc++abi-16-dev' }
|
|
||||||
- { compiler: 'clang-17', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
|
|
||||||
- { compiler: 'clang-17', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-17 libc++-17-dev libc++abi-17-dev' }
|
|
||||||
- { compiler: 'clang-18', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
|
|
||||||
- { compiler: 'clang-18', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev' }
|
|
||||||
- { compiler: 'clang-19', cxxstd: '11,14', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
|
|
||||||
- { compiler: 'clang-19', cxxstd: '17,20,2b', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-19 libc++-19-dev libc++abi-19-dev' }
|
|
||||||
- { compiler: 'clang-20', cxxstd: '11,14,17', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
|
|
||||||
- { compiler: 'clang-20', cxxstd: '20,23,2c', os: 'ubuntu-24.04', stdlib: libc++, install: 'clang-20 libc++-20-dev libc++abi-20-dev' }
|
|
||||||
|
|
||||||
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
|
# libc++
|
||||||
- { name: "clang-18 w/ sanitizers (11,14)", sanitize: yes,
|
- { 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-18, cxxstd: '11,14', os: 'ubuntu-24.04', ccache_key: "san1" }
|
- { 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-18 w/ sanitizers (17)", sanitize: yes,
|
- { name: Clang w/ sanitizers, sanitize: yes,
|
||||||
compiler: clang-18, cxxstd: '17', os: 'ubuntu-24.04', ccache_key: "san2" }
|
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-18 w/ sanitizers (20)", sanitize: yes,
|
|
||||||
compiler: clang-18, cxxstd: '20', container: 'ubuntu:24.04', os: 'ubuntu-latest', ccache_key: "san2" }
|
|
||||||
- { name: "clang-18 w/ sanitizers (2b)", sanitize: yes,
|
|
||||||
compiler: clang-18, cxxstd: '2b', container: 'ubuntu:24.04', os: 'ubuntu-latest', ccache_key: "san2" }
|
|
||||||
|
|
||||||
- { name: "cfoa tsan (clang-18)", cxxstd: '11,14,17,20,2b', os: 'ubuntu-24.04', compiler: clang-18,
|
|
||||||
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
|
|
||||||
stdlib: libc++, install: 'clang-18 libc++-18-dev libc++abi-18-dev', ccache_key: "tsan" }
|
|
||||||
|
|
||||||
# OSX, clang
|
# OSX, clang
|
||||||
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', sanitize: yes, ccache: no, ccache_key: "san1" }
|
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-10.15, sanitize: yes }
|
||||||
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-latest', thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests', ccache: no, ccache_key: "tsan" }
|
|
||||||
|
|
||||||
- { compiler: clang, cxxstd: '11,14,17,20,2b', os: 'macos-14' }
|
timeout-minutes: 120
|
||||||
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-15' }
|
runs-on: ${{matrix.os}}
|
||||||
- { compiler: clang, cxxstd: '11,14,17,20,23,2c', os: 'macos-26' }
|
|
||||||
|
|
||||||
timeout-minutes: 360
|
|
||||||
# posix (gcc-12 w/ sanitizers is taking longer than 210 minutes
|
|
||||||
# timeout-minutes: 210
|
|
||||||
needs: [runner-selection]
|
|
||||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
|
|
||||||
container: ${{matrix.container}}
|
container: ${{matrix.container}}
|
||||||
env: {B2_USE_CCACHE: 1}
|
env: {B2_USE_CCACHE: 1}
|
||||||
|
|
||||||
@@ -147,7 +97,12 @@ jobs:
|
|||||||
fi
|
fi
|
||||||
if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then
|
if [ -n "${{matrix.container}}" ] && [ -f "/etc/debian_version" ]; then
|
||||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||||
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common git g++
|
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y sudo software-properties-common
|
||||||
|
# Need (newer) git, and the older Ubuntu container may require requesting the key manually using port 80
|
||||||
|
apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys E1DD270288B4E6030699E45FA1715D88E1DF1F24
|
||||||
|
for i in {1..${NET_RETRY_COUNT:-3}}; do sudo -E add-apt-repository -y ppa:git-core/ppa && break || sleep 10; done
|
||||||
|
apt-get -o Acquire::Retries=$NET_RETRY_COUNT update
|
||||||
|
apt-get -o Acquire::Retries=$NET_RETRY_COUNT install -y g++ python libpython-dev git
|
||||||
fi
|
fi
|
||||||
# For jobs not compatible with ccache, use "ccache: no" in the matrix
|
# For jobs not compatible with ccache, use "ccache: no" in the matrix
|
||||||
if [[ "${{ matrix.ccache }}" == "no" ]]; then
|
if [[ "${{ matrix.ccache }}" == "no" ]]; then
|
||||||
@@ -165,8 +120,8 @@ jobs:
|
|||||||
if: env.B2_USE_CCACHE
|
if: env.B2_USE_CCACHE
|
||||||
with:
|
with:
|
||||||
path: ~/.ccache
|
path: ~/.ccache
|
||||||
key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{matrix.ccache_key}}-${{github.sha}}
|
key: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{github.sha}}
|
||||||
restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-${{matrix.ccache_key}}-
|
restore-keys: ${{matrix.os}}-${{matrix.container}}-${{matrix.compiler}}-
|
||||||
|
|
||||||
- name: Fetch Boost.CI
|
- name: Fetch Boost.CI
|
||||||
uses: actions/checkout@v3
|
uses: actions/checkout@v3
|
||||||
@@ -237,8 +192,6 @@ jobs:
|
|||||||
B2_COMPILER: ${{matrix.compiler}}
|
B2_COMPILER: ${{matrix.compiler}}
|
||||||
B2_CXXSTD: ${{matrix.cxxstd}}
|
B2_CXXSTD: ${{matrix.cxxstd}}
|
||||||
B2_SANITIZE: ${{matrix.sanitize}}
|
B2_SANITIZE: ${{matrix.sanitize}}
|
||||||
B2_TSAN: ${{matrix.thread-sanitize}}
|
|
||||||
B2_TARGETS: ${{matrix.targets}}
|
|
||||||
B2_STDLIB: ${{matrix.stdlib}}
|
B2_STDLIB: ${{matrix.stdlib}}
|
||||||
# More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys.
|
# More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys.
|
||||||
# B2_DEFINES: ${{matrix.defines}}
|
# B2_DEFINES: ${{matrix.defines}}
|
||||||
@@ -252,18 +205,11 @@ jobs:
|
|||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
if: '!matrix.coverity'
|
if: '!matrix.coverity'
|
||||||
run: |
|
run: ci/build.sh
|
||||||
if [[ ${B2_TSAN} == "yes" ]] && [[ $(uname) == "Linux" ]]; then
|
|
||||||
echo 0 | sudo tee /proc/sys/kernel/randomize_va_space
|
|
||||||
sudo sysctl vm.mmap_rnd_bits=28
|
|
||||||
fi
|
|
||||||
B2_TARGETS=${{matrix.targets}} ci/build.sh
|
|
||||||
|
|
||||||
- name: Upload coverage
|
- name: Upload coverage
|
||||||
if: matrix.coverage
|
if: matrix.coverage
|
||||||
run: ci/codecov.sh "upload"
|
run: ci/codecov.sh "upload"
|
||||||
env:
|
|
||||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
|
||||||
|
|
||||||
- name: Run coverity
|
- name: Run coverity
|
||||||
if: matrix.coverity && github.event_name == 'push' && (github.ref_name == 'develop' || github.ref_name == 'master')
|
if: matrix.coverity && github.event_name == 'push' && (github.ref_name == 'develop' || github.ref_name == 'master')
|
||||||
@@ -280,20 +226,13 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { toolset: msvc-14.0, cxxstd: '14,latest', addrmd: '32,64', os: 'windows-2019', variant: 'debug,release' }
|
- { toolset: msvc-14.0, cxxstd: '14,latest', addrmd: '32,64', os: windows-2019 }
|
||||||
- { toolset: msvc-14.2, cxxstd: '14,17', addrmd: '32,64', os: 'windows-2019', variant: 'debug,release' }
|
- { toolset: msvc-14.2, cxxstd: '14,17,20', addrmd: '32,64', os: windows-2019 }
|
||||||
- { toolset: msvc-14.2, cxxstd: '20,latest', addrmd: '32,64', os: 'windows-2019', variant: 'debug,release' }
|
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest',addrmd: '32,64', os: windows-2022 }
|
||||||
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest', addrmd: '32,64', os: 'windows-2022', variant: 'debug,release' }
|
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: windows-2022 }
|
||||||
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '64', os: 'windows-2022', variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '/RTCc' }
|
- { toolset: gcc, cxxstd: '03,11,14,17,2a', addrmd: '64', os: windows-2019 }
|
||||||
- { toolset: msvc-14.3, cxxstd: '14', addrmd: '32', os: 'windows-2022', variant: 'debug', defines: '_ALLOW_RTCc_IN_STL', cxxflags: '"/RTCc /arch:IA32"' }
|
|
||||||
- { toolset: msvc-14.3, cxxstd: '14,17', addrmd: '32,64', os: 'windows-2022', variant: 'debug,release', cxxflags: '/permissive-' }
|
|
||||||
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: 'windows-2022', variant: 'debug,release' }
|
|
||||||
- { toolset: clang-win, cxxstd: '14,17,latest', addrmd: '32,64', os: 'windows-2025', variant: 'debug,release' }
|
|
||||||
- { toolset: msvc-14.3, cxxstd: '14,17,20,latest', addrmd: '32,64', os: 'windows-2025', variant: 'debug,release' }
|
|
||||||
- { toolset: gcc, cxxstd: '11,14,17,2a', addrmd: '64', os: 'windows-2019', variant: 'debug,release' }
|
|
||||||
|
|
||||||
needs: [runner-selection]
|
runs-on: ${{matrix.os}}
|
||||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -320,9 +259,6 @@ jobs:
|
|||||||
B2_TOOLSET: ${{matrix.toolset}}
|
B2_TOOLSET: ${{matrix.toolset}}
|
||||||
B2_CXXSTD: ${{matrix.cxxstd}}
|
B2_CXXSTD: ${{matrix.cxxstd}}
|
||||||
B2_ADDRESS_MODEL: ${{matrix.addrmd}}
|
B2_ADDRESS_MODEL: ${{matrix.addrmd}}
|
||||||
B2_DEFINES: ${{matrix.defines}}
|
|
||||||
B2_VARIANT: ${{matrix.variant}}
|
|
||||||
B2_CXXFLAGS: ${{matrix.cxxflags}}
|
|
||||||
|
|
||||||
- name: Collect coverage
|
- name: Collect coverage
|
||||||
shell: powershell
|
shell: powershell
|
||||||
@@ -347,11 +283,10 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { sys: MINGW32, compiler: gcc, cxxstd: '11,17,20', variant: 'release', cxxflags: '--param ggc-min-expand=10 --param ggc-min-heapsize=16384' }
|
- { sys: MINGW32, compiler: gcc, cxxstd: '03,11,17,20' }
|
||||||
- { sys: MINGW64, compiler: gcc, cxxstd: '11,17,20', variant: 'debug,release' }
|
- { sys: MINGW64, compiler: gcc, cxxstd: '03,11,17,20' }
|
||||||
|
|
||||||
needs: [runner-selection]
|
runs-on: windows-latest
|
||||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['windows-latest'] }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
@@ -382,13 +317,9 @@ jobs:
|
|||||||
B2_CXXSTD: ${{matrix.cxxstd}}
|
B2_CXXSTD: ${{matrix.cxxstd}}
|
||||||
B2_SANITIZE: ${{matrix.sanitize}}
|
B2_SANITIZE: ${{matrix.sanitize}}
|
||||||
B2_STDLIB: ${{matrix.stdlib}}
|
B2_STDLIB: ${{matrix.stdlib}}
|
||||||
B2_VARIANT: ${{matrix.variant}}
|
|
||||||
B2_CXXFLAGS: ${{ matrix.cxxflags }}
|
|
||||||
run: ci/github/install.sh
|
run: ci/github/install.sh
|
||||||
|
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
env:
|
|
||||||
B2_VARIANT: ${{matrix.variant}}
|
|
||||||
run: ci/build.sh
|
run: ci/build.sh
|
||||||
|
|
||||||
# Run also the CMake tests to avoid having to setup another matrix for CMake on MSYS
|
# Run also the CMake tests to avoid having to setup another matrix for CMake on MSYS
|
||||||
@@ -409,12 +340,11 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { os: 'ubuntu-20.04', build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
|
- { os: ubuntu-20.04, build_shared: ON, build_type: Debug, generator: 'Unix Makefiles' }
|
||||||
- { os: 'windows-2019', build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
|
- { os: windows-2019, build_shared: ON, build_type: Debug, generator: 'Visual Studio 16 2019' }
|
||||||
|
|
||||||
timeout-minutes: 120
|
timeout-minutes: 120
|
||||||
needs: [runner-selection]
|
runs-on: ${{matrix.os}}
|
||||||
runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }}
|
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
/doc/html/
|
/doc/html/
|
||||||
/doc/pdf/
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
# Distributed under the Boost Software License, Version 1.0.
|
# Distributed under the Boost Software License, Version 1.0.
|
||||||
# https://www.boost.org/LICENSE_1_0.txt
|
# https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.8...3.20)
|
cmake_minimum_required(VERSION 3.5...3.20)
|
||||||
|
|
||||||
project(boost_unordered VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
project(boost_unordered VERSION "${BOOST_SUPERPROJECT_VERSION}" LANGUAGES CXX)
|
||||||
|
|
||||||
@@ -18,38 +18,16 @@ target_link_libraries(boost_unordered
|
|||||||
Boost::config
|
Boost::config
|
||||||
Boost::container_hash
|
Boost::container_hash
|
||||||
Boost::core
|
Boost::core
|
||||||
|
Boost::iterator
|
||||||
|
Boost::move
|
||||||
Boost::mp11
|
Boost::mp11
|
||||||
Boost::predef
|
Boost::predef
|
||||||
|
Boost::preprocessor
|
||||||
Boost::throw_exception
|
Boost::throw_exception
|
||||||
|
Boost::tuple
|
||||||
|
Boost::type_traits
|
||||||
)
|
)
|
||||||
|
|
||||||
# Add headers and .natvis to project, for better IDE integration
|
|
||||||
|
|
||||||
if(NOT CMAKE_VERSION VERSION_LESS 3.19)
|
|
||||||
|
|
||||||
# Using target_sources with PRIVATE or PUBLIC on INTERFACE targets requires 3.19
|
|
||||||
|
|
||||||
file(GLOB_RECURSE headers CONFIGURE_DEPENDS include/*.hpp)
|
|
||||||
target_sources(boost_unordered PRIVATE ${headers})
|
|
||||||
unset(headers)
|
|
||||||
|
|
||||||
if(MSVC)
|
|
||||||
|
|
||||||
# Only Visual Studio needs this, but the generator may also be Ninja
|
|
||||||
target_sources(boost_unordered PUBLIC extra/boost_unordered.natvis)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Make IDE project folders match directory structure
|
|
||||||
|
|
||||||
get_target_property(sources boost_unordered SOURCES)
|
|
||||||
source_group(TREE ${PROJECT_SOURCE_DIR} FILES ${sources})
|
|
||||||
unset(sources)
|
|
||||||
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_compile_features(boost_unordered INTERFACE cxx_std_11)
|
|
||||||
|
|
||||||
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
if(BUILD_TESTING AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/test/CMakeLists.txt")
|
||||||
|
|
||||||
add_subdirectory(test)
|
add_subdirectory(test)
|
||||||
|
|||||||
@@ -1,79 +1,49 @@
|
|||||||
# Boost.Unordered
|
# Boost.Unordered
|
||||||
|
|
||||||
[](https://github.com/boostorg/unordered/tree/master) [](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [](https://drone.cpp.al/boostorg/unordered) [](https://ci.appveyor.com/project/cppalliance/unordered/branch/master) [](https://codecov.io/gh/boostorg/unordered/branch/master) [](https://pdimov.github.io/boostdep-report/master/unordered.html) [](https://www.boost.org/doc/libs/master/libs/unordered/index.html) [](https://regression.boost.org/master/developer/unordered.html)<br/>
|
Part of collection of the [Boost C++ Libraries](http://github.com/boostorg).
|
||||||
[](https://github.com/boostorg/unordered/tree/develop) [](https://github.com/boostorg/unordered/actions/workflows/ci.yml) [](https://drone.cpp.al/boostorg/unordered) [](https://ci.appveyor.com/project/cppalliance/unordered/branch/develop) [](https://codecov.io/gh/boostorg/unordered/branch/develop) [](https://pdimov.github.io/boostdep-report/develop/unordered.html) [](https://www.boost.org/doc/libs/develop/libs/unordered/index.html) [](https://regression.boost.org/develop/developer/unordered.html)<br/>
|
|
||||||
[](https://www.boost.org/users/license.html) <img alt="C++11 required" src="https://img.shields.io/badge/standard-C%2b%2b11-blue.svg"> <img alt="Header-only library" src="https://img.shields.io/badge/build-header--only-blue.svg">
|
|
||||||
|
|
||||||
Boost.Unordered offers a catalog of hash containers with different standards compliance levels, performances and intented usage scenarios:
|
For accessing data based on key lookup, the C++ standard library offers `std::set`, `std::map`, `std::multiset` and `std::multimap`.
|
||||||
|
These are generally implemented using balanced binary trees so that lookup time has logarithmic complexity.
|
||||||
|
That is generally okay, but in many cases a hash table can perform better, as accessing data has constant complexity, on average.
|
||||||
|
The worst case complexity is linear, but that occurs rarely and with some care, can be avoided.
|
||||||
|
|
||||||
**`boost::unordered_set` `boost::unordered_map` `boost::unordered_multiset` `boost::unordered_multimap`**
|
Also, the existing containers require a 'less than' comparison object to order their elements.
|
||||||
|
For some data types this is impossible to implement or isn’t practical.
|
||||||
|
In contrast, a hash table only needs an equality function and a hash function for the key.
|
||||||
|
|
||||||
<ul>Fully conformant implementations of <code>std::unordered_[multi](set|map)</code>,
|
With this in mind, unordered associative containers were added to the C++ standard.
|
||||||
but faster and up to the latest revisions of the standard even if you're working in an older version of C++ (heterogeneous lookup,
|
This is an implementation of the containers described in C++11, with some deviations from the standard in order to work with non-C++11 compilers and libraries.
|
||||||
<code>try_emplace</code>, <code>contains</code>, etc.)</ul>
|
|
||||||
|
|
||||||
**`boost::unordered_flat_set` `boost::unordered_flat_map`**
|
|
||||||
|
|
||||||
<ul>The fastest of the lot. Based on open addressing, these containers slightly
|
### License
|
||||||
deviate from the standard in exchange for top performance.</ul>
|
|
||||||
|
|
||||||
**`boost::unordered_node_set` `boost::unordered_node_map`**
|
Distributed under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
|
||||||
|
|
||||||
<ul>Variations of <code>boost::unordered_flat_(set|map)</code> providing pointer stability.</ul>
|
### Properties
|
||||||
|
|
||||||
**`boost::concurrent_flat_set` `boost::concurrent_flat_map`**
|
* C++03
|
||||||
|
* Header-Only
|
||||||
|
|
||||||
<ul>High performance for multithreaded scenarios. Introducing a new non-standard, iterator-free API.</ul>
|
### Build Status
|
||||||
|
|
||||||
**`boost::concurrent_node_set` `boost::concurrent_node_map`**
|
Branch | GH Actions | Appveyor | codecov.io | Deps | Docs | Tests |
|
||||||
|
:-------------: | ---------- | -------- | ---------- | ---- | ---- | ----- |
|
||||||
|
[`master`](https://github.com/boostorg/unordered/tree/master) | [](https://github.com/boostorg/unordered/actions/workflows/ci.yml) | [](https://ci.appveyor.com/project/danieljames/unordered-qtwe6/branch/master) | [](https://codecov.io/gh/boostorg/unordered/branch/master) | [](https://pdimov.github.io/boostdep-report/master/unordered.html) | [](https://www.boost.org/doc/libs/master/libs/unordered/doc/html/unordered.html) | [](http://www.boost.org/development/tests/master/developer/unordered.html)
|
||||||
|
[`develop`](https://github.com/boostorg/unordered/tree/develop) | [](https://github.com/boostorg/unordered/actions/workflows/ci.yml) | [](https://ci.appveyor.com/project/danieljames/unordered-qtwe6/branch/develop) | [](https://codecov.io/gh/boostorg/unordered/branch/develop) | [](https://pdimov.github.io/boostdep-report/develop/unordered.html) | [](https://www.boost.org/doc/libs/develop/libs/unordered/doc/html/unordered.html) | [](http://www.boost.org/development/tests/develop/developer/unordered.html)
|
||||||
|
|
||||||
<ul>Variations of <code>boost::concurrent_flat_(set|map)</code> providing pointer stability.</ul>
|
### Directories
|
||||||
|
|
||||||
## Learn about Boost.Unordered
|
| Name | Purpose |
|
||||||
|
| ----------- | ------------------------------ |
|
||||||
|
| `doc` | documentation |
|
||||||
|
| `example` | examples |
|
||||||
|
| `include` | headers |
|
||||||
|
| `test` | unit tests |
|
||||||
|
|
||||||
* [Online documentation](https://boost.org/libs/unordered)
|
### More information
|
||||||
* [Some benchmarks](https://github.com/boostorg/boost_unordered_benchmarks)
|
|
||||||
* Technical articles on Boost.Unordered internal design:
|
|
||||||
* [Advancing the state of the art for `std::unordered_map` implementations](https://bannalia.blogspot.com/2022/06/advancing-state-of-art-for.html)
|
|
||||||
* [Inside `boost::unordered_flat_map`](https://bannalia.blogspot.com/2022/11/inside-boostunorderedflatmap.html)
|
|
||||||
* [Inside `boost::concurrent_flat_map`](https://bannalia.blogspot.com/2023/07/inside-boostconcurrentflatmap.html)
|
|
||||||
* [Bulk visitation in `boost::concurrent_flat_map`](https://bannalia.blogspot.com/2023/10/bulk-visitation-in-boostconcurrentflatm.html)
|
|
||||||
* Debugging visualizers for Boost.Unordered:
|
|
||||||
* [Natvis for boost::unordered_map, and how to use <Intrinsic> elements](https://blog.ganets.ky/NatvisForUnordered/)
|
|
||||||
* [Natvis for boost::concurrent_flat_map, and why fancy pointers are hard](https://blog.ganets.ky/NatvisForUnordered2/)
|
|
||||||
* [Visualizing boost::unordered_map in GDB, with pretty-printer customization points](https://blog.ganets.ky/PrettyPrinter/)
|
|
||||||
|
|
||||||
Boost.Unordered can be installed in a number of ways:
|
* [Ask questions](http://stackoverflow.com/questions/ask?tags=c%2B%2B,boost,boost-unordered)
|
||||||
|
* [Report bugs](https://github.com/boostorg/unordered/issues): Be sure to mention Boost version, platform and compiler you're using. A small compilable code sample to reproduce the problem is always good as well.
|
||||||
|
* Submit your patches as pull requests against **develop** branch. Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
|
||||||
|
* Discussions about the library are held on the [Boost developers mailing list](http://www.boost.org/community/groups.html#main). Be sure to read the [discussion policy](http://www.boost.org/community/policy.html) before posting and add the `[unordered]` tag at the beginning of the subject line.
|
||||||
|
|
||||||
* [Download Boost](https://www.boost.org/users/download/) and you're ready to go (this is a header-only library requiring no building).
|
|
||||||
* Using Conan 2: In case you don't have it yet, add an entry for Boost in your `conanfile.txt` (the example requires at least Boost 1.86):
|
|
||||||
```
|
|
||||||
[requires]
|
|
||||||
boost/[>=1.86.0]
|
|
||||||
```
|
|
||||||
<ul>If you're not using any compiled Boost library, the following will skip building altogether:</ul>
|
|
||||||
|
|
||||||
```
|
|
||||||
[options]
|
|
||||||
boost:header_only=True
|
|
||||||
```
|
|
||||||
* Using vcpkg: Execute the command
|
|
||||||
```
|
|
||||||
vcpkg install boost-unordered
|
|
||||||
```
|
|
||||||
* Using CMake: [Boost CMake support infrastructure](https://github.com/boostorg/cmake)
|
|
||||||
allows you to use CMake directly to download, build and consume all of Boost or
|
|
||||||
some specific libraries.
|
|
||||||
|
|
||||||
## Support
|
|
||||||
|
|
||||||
* Join the **#boost-unordered** discussion group at [cpplang.slack.com](https://cpplang.slack.com/)
|
|
||||||
([ask for an invite](https://cppalliance.org/slack/) if you’re not a member of this workspace yet)
|
|
||||||
* Ask in the [Boost Users mailing list](https://lists.boost.org/mailman/listinfo.cgi/boost-users)
|
|
||||||
(add the `[unordered]` tag at the beginning of the subject line)
|
|
||||||
* [File an issue](https://github.com/boostorg/unordered/issues)
|
|
||||||
|
|
||||||
## Contribute
|
|
||||||
|
|
||||||
* [Pull requests](https://github.com/boostorg/unordered/pulls) against **develop** branch are most welcome.
|
|
||||||
Note that by submitting patches you agree to license your modifications under the [Boost Software License, Version 1.0](http://www.boost.org/LICENSE_1_0.txt).
|
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
enwik8
|
|
||||||
enwik9
|
|
||||||
*.exe
|
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021 Peter Dimov.
|
||||||
// Copyright 2023-2024 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
#include <boost/multi_index_container.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/multi_index/hashed_index.hpp>
|
||||||
|
#include <boost/multi_index/member.hpp>
|
||||||
#include <boost/core/detail/splitmix64.hpp>
|
#include <boost/core/detail/splitmix64.hpp>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
# include "absl/container/node_hash_map.h"
|
# include "absl/container/node_hash_map.h"
|
||||||
# include "absl/container/flat_hash_map.h"
|
# include "absl/container/flat_hash_map.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -25,7 +21,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
@@ -142,14 +137,7 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
|
|||||||
{
|
{
|
||||||
if( it->second & 1 )
|
if( it->second & 1 )
|
||||||
{
|
{
|
||||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
map.erase( it++ );
|
||||||
{
|
|
||||||
map.erase( it++ );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = map.erase( it );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -171,9 +159,13 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
|
|
||||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||||
|
|
||||||
for( unsigned i = 1; i <= N; ++i )
|
|
||||||
{
|
{
|
||||||
map.erase( indices2[ i ] );
|
boost::detail::splitmix64 rng;
|
||||||
|
|
||||||
|
for( unsigned i = 1; i <= N; ++i )
|
||||||
|
{
|
||||||
|
map.erase( indices2[ i ] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Random erase", 0, map.size() );
|
print_time( t1, "Random erase", 0, map.size() );
|
||||||
@@ -265,6 +257,24 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
|||||||
times.push_back( rec );
|
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
|
// 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 allocator_for = ::allocator< std::pair<K const, V> >;
|
||||||
@@ -275,12 +285,6 @@ template<class K, class V> using std_unordered_map =
|
|||||||
template<class K, class V> using boost_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>>;
|
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map =
|
|
||||||
boost::unordered_node_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
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
template<class K, class V> using absl_node_hash_map =
|
||||||
@@ -291,13 +295,6 @@ template<class K, class V> using absl_flat_hash_map =
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// fnv1a_hash
|
// fnv1a_hash
|
||||||
|
|
||||||
template<int Bits> struct fnv1a_hash_impl;
|
template<int Bits> struct fnv1a_hash_impl;
|
||||||
@@ -340,10 +337,7 @@ 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 = std::true_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class K, class V> using std_unordered_map_fnv1a =
|
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>>;
|
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
@@ -351,11 +345,13 @@ 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 =
|
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>>;
|
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map_fnv1a =
|
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||||
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
pair<K, V>,
|
||||||
|
indexed_by<
|
||||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first>, fnv1a_hash >
|
||||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
>,
|
||||||
|
::allocator< pair<K, V> >
|
||||||
|
>;
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
@@ -367,47 +363,30 @@ template<class K, class V> using absl_flat_hash_map_fnv1a =
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
|
||||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
init_indices();
|
init_indices();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
test<std_unordered_map>( "std::unordered_map" );
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
test<boost_unordered_map>( "boost::unordered_map" );
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
test<multi_index_map>( "multi_index_map" );
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||||
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
|
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
@@ -420,7 +399,7 @@ int main()
|
|||||||
|
|
||||||
for( auto const& x: times )
|
for( auto const& x: times )
|
||||||
{
|
{
|
||||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,343 +0,0 @@
|
|||||||
// Copyright 2021 Peter Dimov.
|
|
||||||
// Copyright 2023-2024 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#define BOOST_UNORDERED_ENABLE_STATS
|
|
||||||
|
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
|
||||||
#include <boost/core/detail/splitmix64.hpp>
|
|
||||||
#include <boost/config.hpp>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <chrono>
|
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::uint32_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 = 50'000;
|
|
||||||
constexpr int K = 10;
|
|
||||||
|
|
||||||
static std::vector<std::string> indices1, indices2;
|
|
||||||
|
|
||||||
static std::string make_index( unsigned x )
|
|
||||||
{
|
|
||||||
char buffer[ 64 ];
|
|
||||||
std::snprintf( buffer, sizeof(buffer), "pfx_%u_sfx", x );
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::string make_random_index( unsigned x )
|
|
||||||
{
|
|
||||||
char buffer[ 64 ];
|
|
||||||
std::snprintf( buffer, sizeof(buffer), "pfx_%0*d_%u_sfx", x % 8 + 1, 0, x );
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void init_indices()
|
|
||||||
{
|
|
||||||
indices1.reserve( N*2+1 );
|
|
||||||
indices1.push_back( make_index( 0 ) );
|
|
||||||
|
|
||||||
for( unsigned i = 1; i <= N*2; ++i )
|
|
||||||
{
|
|
||||||
indices1.push_back( make_index( i ) );
|
|
||||||
}
|
|
||||||
|
|
||||||
indices2.reserve( N*2+1 );
|
|
||||||
indices2.push_back( make_index( 0 ) );
|
|
||||||
|
|
||||||
{
|
|
||||||
boost::detail::splitmix64 rng;
|
|
||||||
|
|
||||||
for( unsigned i = 1; i <= N*2; ++i )
|
|
||||||
{
|
|
||||||
indices2.push_back( make_random_index( static_cast<std::uint32_t>( rng() ) ) );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
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() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
std::uint32_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() );
|
|
||||||
|
|
||||||
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() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
// All Unordered container use the same struct
|
|
||||||
using stats = boost::unordered_flat_map<int, int>::stats;
|
|
||||||
|
|
||||||
struct record
|
|
||||||
{
|
|
||||||
std::string label_;
|
|
||||||
long long time_;
|
|
||||||
stats stats_;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<record> records;
|
|
||||||
|
|
||||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
|
||||||
{
|
|
||||||
std::cout << label << ":\n\n";
|
|
||||||
|
|
||||||
Map<std::string, std::uint32_t> map;
|
|
||||||
|
|
||||||
auto t0 = std::chrono::steady_clock::now();
|
|
||||||
auto t1 = t0;
|
|
||||||
|
|
||||||
test_insert( map, t1 );
|
|
||||||
|
|
||||||
record rec = { label, 0 };
|
|
||||||
|
|
||||||
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;
|
|
||||||
rec.stats_ = map.get_stats();
|
|
||||||
records.push_back( rec );
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map =
|
|
||||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>>;
|
|
||||||
|
|
||||||
// fnv1a_hash
|
|
||||||
|
|
||||||
template<int Bits> struct fnv1a_hash_impl;
|
|
||||||
|
|
||||||
template<> struct fnv1a_hash_impl<32>
|
|
||||||
{
|
|
||||||
std::size_t operator()( std::string const& s ) const
|
|
||||||
{
|
|
||||||
std::size_t h = 0x811C9DC5u;
|
|
||||||
|
|
||||||
char const * first = s.data();
|
|
||||||
char const * last = first + s.size();
|
|
||||||
|
|
||||||
for( ; first != last; ++first )
|
|
||||||
{
|
|
||||||
h ^= static_cast<unsigned char>( *first );
|
|
||||||
h *= 0x01000193ul;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct fnv1a_hash_impl<64>
|
|
||||||
{
|
|
||||||
std::size_t operator()( std::string const& s ) const
|
|
||||||
{
|
|
||||||
std::size_t h = 0xCBF29CE484222325ull;
|
|
||||||
|
|
||||||
char const * first = s.data();
|
|
||||||
char const * last = first + s.size();
|
|
||||||
|
|
||||||
for( ; first != last; ++first )
|
|
||||||
{
|
|
||||||
h ^= static_cast<unsigned char>( *first );
|
|
||||||
h *= 0x00000100000001B3ull;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
|
||||||
{
|
|
||||||
using is_avalanching = std::true_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
|
||||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>>;
|
|
||||||
|
|
||||||
// slightly bad hash
|
|
||||||
|
|
||||||
struct slightly_bad_hash
|
|
||||||
{
|
|
||||||
using is_avalanching = std::true_type;
|
|
||||||
|
|
||||||
std::size_t operator()( std::string const& s ) const
|
|
||||||
{
|
|
||||||
std::size_t h = s.size();
|
|
||||||
|
|
||||||
for( auto ch: s )
|
|
||||||
{
|
|
||||||
h *= 0x811C9DC4u; // multiplicative factor is even!
|
|
||||||
h += static_cast<std::size_t>( ch );
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map_slightly_bad_hash =
|
|
||||||
boost::unordered_flat_map<K, V, slightly_bad_hash, std::equal_to<K>>;
|
|
||||||
|
|
||||||
// bad hash
|
|
||||||
|
|
||||||
struct bad_hash
|
|
||||||
{
|
|
||||||
using is_avalanching = std::true_type;
|
|
||||||
|
|
||||||
std::size_t operator()( std::string const& s ) const
|
|
||||||
{
|
|
||||||
std::size_t h = s.size();
|
|
||||||
|
|
||||||
for( auto ch: s )
|
|
||||||
{
|
|
||||||
h *= 31;
|
|
||||||
h += static_cast<std::size_t>( ch );
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map_bad_hash =
|
|
||||||
boost::unordered_flat_map<K, V, bad_hash, std::equal_to<K>>;
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
init_indices();
|
|
||||||
|
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
|
||||||
test<boost_unordered_flat_map_slightly_bad_hash>( "boost::unordered_flat_map, slightly_bad_hash" );
|
|
||||||
test<boost_unordered_flat_map_bad_hash>( "boost::unordered_flat_map, bad_hash" );
|
|
||||||
|
|
||||||
std::cout << "---\n\n";
|
|
||||||
|
|
||||||
for( auto const& x: records )
|
|
||||||
{
|
|
||||||
std::cout << std::setw( 46 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms\n"
|
|
||||||
<< std::setw( 46 ) << "insertion: "
|
|
||||||
<< "probe length " << x.stats_.insertion.probe_length.average << "\n"
|
|
||||||
<< std::setw( 46 ) << "successful lookup: "
|
|
||||||
<< "probe length " << x.stats_.successful_lookup.probe_length.average
|
|
||||||
<< ", num comparisons " << x.stats_.successful_lookup.num_comparisons.average << "\n"
|
|
||||||
<< std::setw( 46 ) << "unsuccessful lookup: "
|
|
||||||
<< "probe length " << x.stats_.unsuccessful_lookup.probe_length.average
|
|
||||||
<< ", num comparisons " << x.stats_.unsuccessful_lookup.num_comparisons.average << "\n\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +1,19 @@
|
|||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021 Peter Dimov.
|
||||||
// Copyright 2023-2024 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
#include <boost/multi_index_container.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/multi_index/hashed_index.hpp>
|
||||||
|
#include <boost/multi_index/member.hpp>
|
||||||
#include <boost/core/detail/splitmix64.hpp>
|
#include <boost/core/detail/splitmix64.hpp>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
# include "absl/container/node_hash_map.h"
|
# include "absl/container/node_hash_map.h"
|
||||||
# include "absl/container/flat_hash_map.h"
|
# include "absl/container/flat_hash_map.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
@@ -26,7 +22,6 @@
|
|||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <type_traits>
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
|
|
||||||
@@ -143,14 +138,7 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
|
|||||||
{
|
{
|
||||||
if( it->second & 1 )
|
if( it->second & 1 )
|
||||||
{
|
{
|
||||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
map.erase( it++ );
|
||||||
{
|
|
||||||
map.erase( it++ );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = map.erase( it );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -172,9 +160,13 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
|
|
||||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||||
|
|
||||||
for( unsigned i = 1; i <= N; ++i )
|
|
||||||
{
|
{
|
||||||
map.erase( indices2[ i ] );
|
boost::detail::splitmix64 rng;
|
||||||
|
|
||||||
|
for( unsigned i = 1; i <= N; ++i )
|
||||||
|
{
|
||||||
|
map.erase( indices2[ i ] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Random erase", 0, map.size() );
|
print_time( t1, "Random erase", 0, map.size() );
|
||||||
@@ -266,6 +258,24 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
|||||||
times.push_back( rec );
|
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
|
// 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 allocator_for = ::allocator< std::pair<K const, V> >;
|
||||||
@@ -276,12 +286,6 @@ template<class K, class V> using std_unordered_map =
|
|||||||
template<class K, class V> using boost_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>>;
|
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map =
|
|
||||||
boost::unordered_node_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
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
template<class K, class V> using absl_node_hash_map =
|
||||||
@@ -292,13 +296,6 @@ template<class K, class V> using absl_flat_hash_map =
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// fnv1a_hash
|
// fnv1a_hash
|
||||||
|
|
||||||
template<int Bits> struct fnv1a_hash_impl;
|
template<int Bits> struct fnv1a_hash_impl;
|
||||||
@@ -341,10 +338,7 @@ 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 = std::true_type;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class K, class V> using std_unordered_map_fnv1a =
|
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>>;
|
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
@@ -352,11 +346,13 @@ 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 =
|
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>>;
|
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map_fnv1a =
|
template<class K, class V> using multi_index_map_fnv1a = multi_index_container<
|
||||||
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
pair<K, V>,
|
||||||
|
indexed_by<
|
||||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
hashed_unique< member<pair<K, V>, K, &pair<K, V>::first>, fnv1a_hash >
|
||||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
>,
|
||||||
|
::allocator< pair<K, V> >
|
||||||
|
>;
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
@@ -368,47 +364,30 @@ template<class K, class V> using absl_flat_hash_map_fnv1a =
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
|
||||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
//
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
init_indices();
|
init_indices();
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
test<std_unordered_map>( "std::unordered_map" );
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
test<boost_unordered_map>( "boost::unordered_map" );
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
test<multi_index_map>( "multi_index_map" );
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
test<absl_node_hash_map>( "absl::node_hash_map" );
|
||||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
||||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
||||||
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
|
test<multi_index_map_fnv1a>( "multi_index_map, FNV-1a" );
|
||||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
@@ -421,7 +400,7 @@ int main()
|
|||||||
|
|
||||||
for( auto const& x: times )
|
for( auto const& x: times )
|
||||||
{
|
{
|
||||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021 Peter Dimov.
|
||||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
#include <boost/multi_index_container.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/multi_index/hashed_index.hpp>
|
||||||
#include <boost/endian/conversion.hpp>
|
#include <boost/multi_index/member.hpp>
|
||||||
#include <boost/core/detail/splitmix64.hpp>
|
#include <boost/core/detail/splitmix64.hpp>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
# include "absl/container/node_hash_map.h"
|
# include "absl/container/node_hash_map.h"
|
||||||
# include "absl/container/flat_hash_map.h"
|
# include "absl/container/flat_hash_map.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -67,7 +62,7 @@ static void init_indices()
|
|||||||
|
|
||||||
for( unsigned i = 1; i <= N*2; ++i )
|
for( unsigned i = 1; i <= N*2; ++i )
|
||||||
{
|
{
|
||||||
indices3.push_back( boost::endian::endian_reverse( static_cast<std::uint32_t>( i ) ) );
|
indices3.push_back( (std::uint32_t)i << 11 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +87,7 @@ template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::stea
|
|||||||
map.insert( { indices3[ i ], i } );
|
map.insert( { indices3[ i ], i } );
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Consecutive reversed insert", 0, map.size() );
|
print_time( t1, "Consecutive shifted insert", 0, map.size() );
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -138,7 +133,7 @@ template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::stea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Consecutive reversed lookup", s, map.size() );
|
print_time( t1, "Consecutive shifted lookup", s, map.size() );
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -151,14 +146,7 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
|
|||||||
{
|
{
|
||||||
if( it->second & 1 )
|
if( it->second & 1 )
|
||||||
{
|
{
|
||||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
map.erase( it++ );
|
||||||
{
|
|
||||||
map.erase( it++ );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = map.erase( it );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -180,9 +168,13 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
|
|
||||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||||
|
|
||||||
for( unsigned i = 1; i <= N; ++i )
|
|
||||||
{
|
{
|
||||||
map.erase( indices2[ i ] );
|
boost::detail::splitmix64 rng;
|
||||||
|
|
||||||
|
for( unsigned i = 1; i <= N; ++i )
|
||||||
|
{
|
||||||
|
map.erase( indices2[ i ] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Random erase", 0, map.size() );
|
print_time( t1, "Random erase", 0, map.size() );
|
||||||
@@ -192,7 +184,7 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
map.erase( indices3[ i ] );
|
map.erase( indices3[ i ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Consecutive reversed erase", 0, map.size() );
|
print_time( t1, "Consecutive shifted erase", 0, map.size() );
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -281,6 +273,24 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
|||||||
times.push_back( rec );
|
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
|
// 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 allocator_for = ::allocator< std::pair<K const, V> >;
|
||||||
@@ -291,12 +301,6 @@ template<class K, class V> using std_unordered_map =
|
|||||||
template<class K, class V> using boost_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>>;
|
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map =
|
|
||||||
boost::unordered_node_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
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
template<class K, class V> using absl_node_hash_map =
|
||||||
@@ -307,27 +311,13 @@ template<class K, class V> using absl_flat_hash_map =
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
init_indices();
|
init_indices();
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
test<std_unordered_map>( "std::unordered_map" );
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
test<boost_unordered_map>( "boost::unordered_map" );
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
test<multi_index_map>( "multi_index_map" );
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
@@ -340,7 +330,7 @@ int main()
|
|||||||
|
|
||||||
for( auto const& x: times )
|
for( auto const& x: times )
|
||||||
{
|
{
|
||||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
std::cout << std::setw( 25 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,24 +1,19 @@
|
|||||||
// Copyright 2021 Peter Dimov.
|
// Copyright 2021 Peter Dimov.
|
||||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
// Distributed under the Boost Software License, Version 1.0.
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
// https://www.boost.org/LICENSE_1_0.txt
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
#include <boost/unordered_map.hpp>
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
#include <boost/multi_index_container.hpp>
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
#include <boost/multi_index/hashed_index.hpp>
|
||||||
#include <boost/endian/conversion.hpp>
|
#include <boost/multi_index/member.hpp>
|
||||||
#include <boost/core/detail/splitmix64.hpp>
|
#include <boost/core/detail/splitmix64.hpp>
|
||||||
#include <boost/config.hpp>
|
#include <boost/config.hpp>
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
# include "absl/container/node_hash_map.h"
|
# include "absl/container/node_hash_map.h"
|
||||||
# include "absl/container/flat_hash_map.h"
|
# include "absl/container/flat_hash_map.h"
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -67,7 +62,7 @@ static void init_indices()
|
|||||||
|
|
||||||
for( unsigned i = 1; i <= N*2; ++i )
|
for( unsigned i = 1; i <= N*2; ++i )
|
||||||
{
|
{
|
||||||
indices3.push_back( boost::endian::endian_reverse( static_cast<std::uint64_t>( i ) ) );
|
indices3.push_back( (std::uint64_t)i << 40 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,7 +87,7 @@ template<class Map> BOOST_NOINLINE void test_insert( Map& map, std::chrono::stea
|
|||||||
map.insert( { indices3[ i ], i } );
|
map.insert( { indices3[ i ], i } );
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Consecutive reversed insert", 0, map.size() );
|
print_time( t1, "Consecutive shifted insert", 0, map.size() );
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -138,7 +133,7 @@ template<class Map> BOOST_NOINLINE void test_lookup( Map& map, std::chrono::stea
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Consecutive reversed lookup", s, map.size() );
|
print_time( t1, "Consecutive shifted lookup", s, map.size() );
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -151,14 +146,7 @@ template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::s
|
|||||||
{
|
{
|
||||||
if( it->second & 1 )
|
if( it->second & 1 )
|
||||||
{
|
{
|
||||||
if constexpr( std::is_void_v< decltype( map.erase( it ) ) > )
|
map.erase( it++ );
|
||||||
{
|
|
||||||
map.erase( it++ );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = map.erase( it );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -180,9 +168,13 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
|
|
||||||
print_time( t1, "Consecutive erase", 0, map.size() );
|
print_time( t1, "Consecutive erase", 0, map.size() );
|
||||||
|
|
||||||
for( unsigned i = 1; i <= N; ++i )
|
|
||||||
{
|
{
|
||||||
map.erase( indices2[ i ] );
|
boost::detail::splitmix64 rng;
|
||||||
|
|
||||||
|
for( unsigned i = 1; i <= N; ++i )
|
||||||
|
{
|
||||||
|
map.erase( indices2[ i ] );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Random erase", 0, map.size() );
|
print_time( t1, "Random erase", 0, map.size() );
|
||||||
@@ -192,7 +184,7 @@ template<class Map> BOOST_NOINLINE void test_erase( Map& map, std::chrono::stead
|
|||||||
map.erase( indices3[ i ] );
|
map.erase( indices3[ i ] );
|
||||||
}
|
}
|
||||||
|
|
||||||
print_time( t1, "Consecutive reversed erase", 0, map.size() );
|
print_time( t1, "Consecutive shifted erase", 0, map.size() );
|
||||||
|
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
}
|
}
|
||||||
@@ -281,6 +273,24 @@ template<template<class...> class Map> BOOST_NOINLINE void test( char const* lab
|
|||||||
times.push_back( rec );
|
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
|
// 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 allocator_for = ::allocator< std::pair<K const, V> >;
|
||||||
@@ -291,12 +301,6 @@ template<class K, class V> using std_unordered_map =
|
|||||||
template<class K, class V> using boost_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>>;
|
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map =
|
|
||||||
boost::unordered_node_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
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
template<class K, class V> using absl_node_hash_map =
|
||||||
@@ -307,37 +311,13 @@ template<class K, class V> using absl_flat_hash_map =
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
init_indices();
|
init_indices();
|
||||||
|
|
||||||
#if defined(BOOST_LIBSTDCXX_VERSION) && __SIZE_WIDTH__ == 32
|
|
||||||
|
|
||||||
// Pathological behavior:
|
|
||||||
// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=104945
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
test<std_unordered_map>( "std::unordered_map" );
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
test<boost_unordered_map>( "boost::unordered_map" );
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
test<multi_index_map>( "multi_index_map" );
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
#ifdef HAVE_ABSEIL
|
||||||
|
|
||||||
@@ -350,7 +330,7 @@ int main()
|
|||||||
|
|
||||||
for( auto const& x: times )
|
for( auto const& x: times )
|
||||||
{
|
{
|
||||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
std::cout << std::setw( 25 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,403 +0,0 @@
|
|||||||
// Copyright 2021, 2022 Peter Dimov.
|
|
||||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
|
||||||
#include <boost/unordered/unordered_flat_map.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
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <chrono>
|
|
||||||
#include <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 );
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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_node_map =
|
|
||||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map =
|
|
||||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
|
||||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using absl_flat_hash_map =
|
|
||||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
init_indices();
|
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
|
||||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::cout << "---\n\n";
|
|
||||||
|
|
||||||
for( auto const& x: times )
|
|
||||||
{
|
|
||||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
# include "absl/container/internal/raw_hash_set.cc"
|
|
||||||
# include "absl/hash/internal/hash.cc"
|
|
||||||
# include "absl/hash/internal/low_level_hash.cc"
|
|
||||||
# include "absl/hash/internal/city.cc"
|
|
||||||
#endif
|
|
||||||
@@ -1,386 +0,0 @@
|
|||||||
// Copyright 2021, 2022 Peter Dimov.
|
|
||||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
|
||||||
#include <boost/regex.hpp>
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
# include "absl/container/node_hash_map.h"
|
|
||||||
# include "absl/container/flat_hash_map.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <chrono>
|
|
||||||
#include <fstream>
|
|
||||||
#include <string_view>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::size_t s, std::size_t size )
|
|
||||||
{
|
|
||||||
auto t2 = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
|
||||||
|
|
||||||
t1 = t2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::string> words;
|
|
||||||
|
|
||||||
static void init_words()
|
|
||||||
{
|
|
||||||
#if SIZE_MAX > UINT32_MAX
|
|
||||||
|
|
||||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
char const* fn = "enwik8"; // ditto
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto t1 = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
std::ifstream is( fn );
|
|
||||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
|
||||||
|
|
||||||
boost::regex re( "[a-zA-Z]+");
|
|
||||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
|
||||||
|
|
||||||
words.assign( it, end );
|
|
||||||
|
|
||||||
auto t2 = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_word_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
std::size_t s = 0;
|
|
||||||
|
|
||||||
for( auto const& word: words )
|
|
||||||
{
|
|
||||||
++map[ word ];
|
|
||||||
++s;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time( t1, "Word count", s, map.size() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_contains( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
std::size_t s = 0;
|
|
||||||
|
|
||||||
for( auto const& word: words )
|
|
||||||
{
|
|
||||||
std::string_view w2( word );
|
|
||||||
w2.remove_prefix( 1 );
|
|
||||||
|
|
||||||
s += map.contains( w2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time( t1, "Contains", s, map.size() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_count( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
std::size_t s = 0;
|
|
||||||
|
|
||||||
for( auto const& word: words )
|
|
||||||
{
|
|
||||||
std::string_view w2( word );
|
|
||||||
w2.remove_prefix( 1 );
|
|
||||||
|
|
||||||
s += map.count( w2 );
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time( t1, "Count", s, map.size() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
std::size_t max = 0;
|
|
||||||
std::string_view word;
|
|
||||||
|
|
||||||
for( auto const& x: map )
|
|
||||||
{
|
|
||||||
if( x.second > max )
|
|
||||||
{
|
|
||||||
word = x.first;
|
|
||||||
max = x.second;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time( t1, "Iterate and find max element", max, map.size() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// counting allocator
|
|
||||||
|
|
||||||
static std::size_t s_alloc_bytes = 0;
|
|
||||||
static std::size_t s_alloc_count = 0;
|
|
||||||
|
|
||||||
template<class T> struct allocator
|
|
||||||
{
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
allocator() = default;
|
|
||||||
|
|
||||||
template<class U> allocator( allocator<U> const & ) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* allocate( std::size_t n ) const
|
|
||||||
{
|
|
||||||
s_alloc_bytes += n * sizeof(T);
|
|
||||||
s_alloc_count++;
|
|
||||||
|
|
||||||
return std::allocator<T>().allocate( n );
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate( T* p, std::size_t n ) const noexcept
|
|
||||||
{
|
|
||||||
s_alloc_bytes -= n * sizeof(T);
|
|
||||||
s_alloc_count--;
|
|
||||||
|
|
||||||
std::allocator<T>().deallocate( p, n );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
struct record
|
|
||||||
{
|
|
||||||
std::string label_;
|
|
||||||
long long time_;
|
|
||||||
std::size_t bytes_;
|
|
||||||
std::size_t count_;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<record> times;
|
|
||||||
|
|
||||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
|
||||||
{
|
|
||||||
std::cout << label << ":\n\n";
|
|
||||||
|
|
||||||
s_alloc_bytes = 0;
|
|
||||||
s_alloc_count = 0;
|
|
||||||
|
|
||||||
Map<std::string_view, std::size_t> map;
|
|
||||||
|
|
||||||
auto t0 = std::chrono::steady_clock::now();
|
|
||||||
auto t1 = t0;
|
|
||||||
|
|
||||||
test_word_count( map, t1 );
|
|
||||||
|
|
||||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
|
||||||
|
|
||||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
|
||||||
|
|
||||||
test_contains( map, t1 );
|
|
||||||
test_count( map, t1 );
|
|
||||||
test_iteration( map, t1 );
|
|
||||||
|
|
||||||
auto tN = std::chrono::steady_clock::now();
|
|
||||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
|
||||||
|
|
||||||
rec.time_ = ( tN - t0 ) / 1ms;
|
|
||||||
times.push_back( rec );
|
|
||||||
}
|
|
||||||
|
|
||||||
// aliases using the counting allocator
|
|
||||||
|
|
||||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
|
||||||
|
|
||||||
template<class K, class V> using std_unordered_map =
|
|
||||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_map =
|
|
||||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map =
|
|
||||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map =
|
|
||||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
|
||||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using absl_flat_hash_map =
|
|
||||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// fnv1a_hash
|
|
||||||
|
|
||||||
template<int Bits> struct fnv1a_hash_impl;
|
|
||||||
|
|
||||||
template<> struct fnv1a_hash_impl<32>
|
|
||||||
{
|
|
||||||
std::size_t operator()( std::string_view const& s ) const
|
|
||||||
{
|
|
||||||
std::size_t h = 0x811C9DC5u;
|
|
||||||
|
|
||||||
char const * first = s.data();
|
|
||||||
char const * last = first + s.size();
|
|
||||||
|
|
||||||
for( ; first != last; ++first )
|
|
||||||
{
|
|
||||||
h ^= static_cast<unsigned char>( *first );
|
|
||||||
h *= 0x01000193ul;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<> struct fnv1a_hash_impl<64>
|
|
||||||
{
|
|
||||||
std::size_t operator()( std::string_view const& s ) const
|
|
||||||
{
|
|
||||||
std::size_t h = 0xCBF29CE484222325ull;
|
|
||||||
|
|
||||||
char const * first = s.data();
|
|
||||||
char const * last = first + s.size();
|
|
||||||
|
|
||||||
for( ; first != last; ++first )
|
|
||||||
{
|
|
||||||
h ^= static_cast<unsigned char>( *first );
|
|
||||||
h *= 0x00000100000001B3ull;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct fnv1a_hash: fnv1a_hash_impl< std::numeric_limits<std::size_t>::digits >
|
|
||||||
{
|
|
||||||
using is_avalanching = void;
|
|
||||||
};
|
|
||||||
|
|
||||||
template<class K, class V> using std_unordered_map_fnv1a =
|
|
||||||
std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_map_fnv1a =
|
|
||||||
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map_fnv1a =
|
|
||||||
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map_fnv1a =
|
|
||||||
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map_fnv1a =
|
|
||||||
absl::node_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using absl_flat_hash_map_fnv1a =
|
|
||||||
absl::flat_hash_map<K, V, fnv1a_hash, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map_fnv1a =
|
|
||||||
ankerl::unordered_dense::map<K, V, fnv1a_hash, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
init_words();
|
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
|
||||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
|
|
||||||
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
|
|
||||||
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
|
|
||||||
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map_fnv1a>( "ankerl::unordered_dense::map, FNV-1a" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
test<absl_node_hash_map_fnv1a>( "absl::node_hash_map, FNV-1a" );
|
|
||||||
test<absl_flat_hash_map_fnv1a>( "absl::flat_hash_map, FNV-1a" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::cout << "---\n\n";
|
|
||||||
|
|
||||||
for( auto const& x: times )
|
|
||||||
{
|
|
||||||
std::cout << std::setw( 38 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
# include "absl/container/internal/raw_hash_set.cc"
|
|
||||||
# include "absl/hash/internal/hash.cc"
|
|
||||||
# include "absl/hash/internal/low_level_hash.cc"
|
|
||||||
# include "absl/hash/internal/city.cc"
|
|
||||||
#endif
|
|
||||||
@@ -1,244 +0,0 @@
|
|||||||
// Copyright 2021, 2022 Peter Dimov.
|
|
||||||
// Copyright 2023 Joaquin M Lopez Munoz.
|
|
||||||
// Distributed under the Boost Software License, Version 1.0.
|
|
||||||
// https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
#define _SILENCE_CXX17_OLD_ALLOCATOR_MEMBERS_DEPRECATION_WARNING
|
|
||||||
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
|
|
||||||
|
|
||||||
#include <boost/unordered_map.hpp>
|
|
||||||
#include <boost/unordered/unordered_node_map.hpp>
|
|
||||||
#include <boost/unordered/unordered_flat_map.hpp>
|
|
||||||
#include <boost/regex.hpp>
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
# include "absl/container/node_hash_map.h"
|
|
||||||
# include "absl/container/flat_hash_map.h"
|
|
||||||
#endif
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
# include "ankerl/unordered_dense.h"
|
|
||||||
#endif
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <memory>
|
|
||||||
#include <cstdint>
|
|
||||||
#include <iostream>
|
|
||||||
#include <iomanip>
|
|
||||||
#include <chrono>
|
|
||||||
#include <fstream>
|
|
||||||
|
|
||||||
using namespace std::chrono_literals;
|
|
||||||
|
|
||||||
static void print_time( std::chrono::steady_clock::time_point & t1, char const* label, std::size_t s, std::size_t size )
|
|
||||||
{
|
|
||||||
auto t2 = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
std::cout << label << ": " << ( t2 - t1 ) / 1ms << " ms (s=" << s << ", size=" << size << ")\n";
|
|
||||||
|
|
||||||
t1 = t2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static std::vector<std::string> words;
|
|
||||||
|
|
||||||
static void init_words()
|
|
||||||
{
|
|
||||||
#if SIZE_MAX > UINT32_MAX
|
|
||||||
|
|
||||||
char const* fn = "enwik9"; // http://mattmahoney.net/dc/textdata
|
|
||||||
|
|
||||||
#else
|
|
||||||
|
|
||||||
char const* fn = "enwik8"; // ditto
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
auto t1 = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
std::ifstream is( fn );
|
|
||||||
std::string in( std::istreambuf_iterator<char>( is ), std::istreambuf_iterator<char>{} );
|
|
||||||
|
|
||||||
boost::regex re( "[a-zA-Z]+");
|
|
||||||
boost::sregex_token_iterator it( in.begin(), in.end(), re, 0 ), end;
|
|
||||||
|
|
||||||
words.assign( it, end );
|
|
||||||
|
|
||||||
auto t2 = std::chrono::steady_clock::now();
|
|
||||||
|
|
||||||
std::cout << fn << ": " << words.size() << " words, " << ( t2 - t1 ) / 1ms << " ms\n\n";
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_word_size( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
for( auto const& word: words )
|
|
||||||
{
|
|
||||||
++map[ word.size() ];
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time( t1, "Word size count", 0, map.size() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class Map> BOOST_NOINLINE void test_iteration( Map& map, std::chrono::steady_clock::time_point & t1 )
|
|
||||||
{
|
|
||||||
std::size_t s = 0;
|
|
||||||
|
|
||||||
for( auto const& x: map )
|
|
||||||
{
|
|
||||||
s += x.second;
|
|
||||||
}
|
|
||||||
|
|
||||||
print_time( t1, "Iterate and sum counts", s, map.size() );
|
|
||||||
|
|
||||||
std::cout << std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// counting allocator
|
|
||||||
|
|
||||||
static std::size_t s_alloc_bytes = 0;
|
|
||||||
static std::size_t s_alloc_count = 0;
|
|
||||||
|
|
||||||
template<class T> struct allocator
|
|
||||||
{
|
|
||||||
using value_type = T;
|
|
||||||
|
|
||||||
allocator() = default;
|
|
||||||
|
|
||||||
template<class U> allocator( allocator<U> const & ) noexcept
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U> bool operator==( allocator<U> const & ) const noexcept
|
|
||||||
{
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<class U> bool operator!=( allocator<U> const& ) const noexcept
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
T* allocate( std::size_t n ) const
|
|
||||||
{
|
|
||||||
s_alloc_bytes += n * sizeof(T);
|
|
||||||
s_alloc_count++;
|
|
||||||
|
|
||||||
return std::allocator<T>().allocate( n );
|
|
||||||
}
|
|
||||||
|
|
||||||
void deallocate( T* p, std::size_t n ) const noexcept
|
|
||||||
{
|
|
||||||
s_alloc_bytes -= n * sizeof(T);
|
|
||||||
s_alloc_count--;
|
|
||||||
|
|
||||||
std::allocator<T>().deallocate( p, n );
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
|
|
||||||
struct record
|
|
||||||
{
|
|
||||||
std::string label_;
|
|
||||||
long long time_;
|
|
||||||
std::size_t bytes_;
|
|
||||||
std::size_t count_;
|
|
||||||
};
|
|
||||||
|
|
||||||
static std::vector<record> times;
|
|
||||||
|
|
||||||
template<template<class...> class Map> BOOST_NOINLINE void test( char const* label )
|
|
||||||
{
|
|
||||||
std::cout << label << ":\n\n";
|
|
||||||
|
|
||||||
s_alloc_bytes = 0;
|
|
||||||
s_alloc_count = 0;
|
|
||||||
|
|
||||||
Map<std::size_t, std::size_t> map;
|
|
||||||
|
|
||||||
auto t0 = std::chrono::steady_clock::now();
|
|
||||||
auto t1 = t0;
|
|
||||||
|
|
||||||
test_word_size( map, t1 );
|
|
||||||
|
|
||||||
std::cout << "Memory: " << s_alloc_bytes << " bytes in " << s_alloc_count << " allocations\n\n";
|
|
||||||
|
|
||||||
record rec = { label, 0, s_alloc_bytes, s_alloc_count };
|
|
||||||
|
|
||||||
test_iteration( map, t1 );
|
|
||||||
|
|
||||||
auto tN = std::chrono::steady_clock::now();
|
|
||||||
std::cout << "Total: " << ( tN - t0 ) / 1ms << " ms\n\n";
|
|
||||||
|
|
||||||
rec.time_ = ( tN - t0 ) / 1ms;
|
|
||||||
times.push_back( rec );
|
|
||||||
}
|
|
||||||
|
|
||||||
// aliases using the counting allocator
|
|
||||||
|
|
||||||
template<class K, class V> using allocator_for = ::allocator< std::pair<K const, V> >;
|
|
||||||
|
|
||||||
template<class K, class V> using std_unordered_map =
|
|
||||||
std::unordered_map<K, V, std::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_map =
|
|
||||||
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_node_map =
|
|
||||||
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using boost_unordered_flat_map =
|
|
||||||
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
template<class K, class V> using absl_node_hash_map =
|
|
||||||
absl::node_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
template<class K, class V> using absl_flat_hash_map =
|
|
||||||
absl::flat_hash_map<K, V, absl::container_internal::hash_default_hash<K>, absl::container_internal::hash_default_eq<K>, allocator_for<K, V>>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
template<class K, class V> using ankerl_unordered_dense_map =
|
|
||||||
ankerl::unordered_dense::map<K, V, ankerl::unordered_dense::hash<K>, std::equal_to<K>, ::allocator< std::pair<K, V> >>;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
int main()
|
|
||||||
{
|
|
||||||
init_words();
|
|
||||||
|
|
||||||
test<std_unordered_map>( "std::unordered_map" );
|
|
||||||
test<boost_unordered_map>( "boost::unordered_map" );
|
|
||||||
test<boost_unordered_node_map>( "boost::unordered_node_map" );
|
|
||||||
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
|
|
||||||
|
|
||||||
#ifdef HAVE_ANKERL_UNORDERED_DENSE
|
|
||||||
|
|
||||||
test<ankerl_unordered_dense_map>( "ankerl::unordered_dense::map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
|
|
||||||
test<absl_node_hash_map>( "absl::node_hash_map" );
|
|
||||||
test<absl_flat_hash_map>( "absl::flat_hash_map" );
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
std::cout << "---\n\n";
|
|
||||||
|
|
||||||
for( auto const& x: times )
|
|
||||||
{
|
|
||||||
std::cout << std::setw( 30 ) << ( x.label_ + ": " ) << std::setw( 5 ) << x.time_ << " ms, " << std::setw( 9 ) << x.bytes_ << " bytes in " << x.count_ << " allocations\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef HAVE_ABSEIL
|
|
||||||
# include "absl/container/internal/raw_hash_set.cc"
|
|
||||||
# include "absl/hash/internal/hash.cc"
|
|
||||||
# include "absl/hash/internal/low_level_hash.cc"
|
|
||||||
# include "absl/hash/internal/city.cc"
|
|
||||||
#endif
|
|
||||||
@@ -1,26 +0,0 @@
|
|||||||
# Copyright 2023-2024 René Ferdinand Rivera Morell
|
|
||||||
# Copyright 2024 Peter Dimov
|
|
||||||
# Distributed under the Boost Software License, Version 1.0.
|
|
||||||
# https://www.boost.org/LICENSE_1_0.txt
|
|
||||||
|
|
||||||
require-b2 5.2 ;
|
|
||||||
|
|
||||||
constant boost_dependencies :
|
|
||||||
/boost/assert//boost_assert
|
|
||||||
/boost/config//boost_config
|
|
||||||
/boost/container_hash//boost_container_hash
|
|
||||||
/boost/core//boost_core
|
|
||||||
/boost/mp11//boost_mp11
|
|
||||||
/boost/predef//boost_predef
|
|
||||||
/boost/throw_exception//boost_throw_exception
|
|
||||||
;
|
|
||||||
|
|
||||||
project /boost/unordered ;
|
|
||||||
|
|
||||||
explicit
|
|
||||||
[ alias boost_unordered : : : : <include>include <library>$(boost_dependencies) ]
|
|
||||||
[ alias all : boost_unordered test ]
|
|
||||||
;
|
|
||||||
|
|
||||||
call-if : boost-library unordered
|
|
||||||
;
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
/build/
|
|
||||||
/node_modules/
|
|
||||||
@@ -1,28 +1,21 @@
|
|||||||
# Copyright 2026 Joaquin M Lopez Munoz
|
# Copyright 2005 Daniel James.
|
||||||
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
# Distributed under the Boost Software License, Version 1.0. (See accompanying
|
||||||
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
# file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
||||||
|
|
||||||
import path ;
|
import asciidoctor ;
|
||||||
|
|
||||||
make html_ : build_antora.sh : @run-script ;
|
html unordered.html : unordered.adoc ;
|
||||||
|
|
||||||
actions run-script
|
install html_ : unordered.html : <location>html ;
|
||||||
{
|
|
||||||
bash $(>)
|
|
||||||
}
|
|
||||||
|
|
||||||
path-constant DOC_DIR : . ;
|
pdf unordered.pdf : unordered.adoc ;
|
||||||
.node_modules = [ path.join $(DOC_DIR) node_modules ] ;
|
explicit unordered.pdf ;
|
||||||
|
|
||||||
make cleanup_node_modules_ : html_ : @cleanup-node-modules ;
|
install pdf_ : unordered.pdf : <location>pdf ;
|
||||||
|
explicit pdf_ ;
|
||||||
actions cleanup-node-modules
|
|
||||||
{
|
|
||||||
rm -rf $(.node_modules)
|
|
||||||
}
|
|
||||||
|
|
||||||
###############################################################################
|
###############################################################################
|
||||||
alias boostdoc ;
|
alias boostdoc ;
|
||||||
explicit boostdoc ;
|
explicit boostdoc ;
|
||||||
alias boostrelease : html_ cleanup_node_modules_ ;
|
alias boostrelease : html_ ;
|
||||||
explicit boostrelease ;
|
explicit boostrelease ;
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
name: unordered
|
|
||||||
version: ~
|
|
||||||
title: Boost.Unordered
|
|
||||||
nav:
|
|
||||||
- modules/ROOT/nav.adoc
|
|
||||||
start_page: intro.adoc
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
set -ex
|
|
||||||
|
|
||||||
SCRIPT_DIR=$( cd -- "$( dirname -- "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )
|
|
||||||
cd "$SCRIPT_DIR"
|
|
||||||
|
|
||||||
npm ci
|
|
||||||
npx antora unordered-playbook.yml
|
|
||||||
cp -f html/index.html html/unordered.html
|
|
||||||
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 33 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 37 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 36 KiB |
|
After Width: | Height: | Size: 35 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 41 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 39 KiB |
|
After Width: | Height: | Size: 42 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 38 KiB |
|
After Width: | Height: | Size: 40 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 44 KiB |
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 47 KiB |
|
After Width: | Height: | Size: 46 KiB |
|
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 5.9 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 28 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 33 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 31 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 35 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 32 KiB |
|
Before Width: | Height: | Size: 33 KiB |