diff --git a/doc/.gitignore b/doc/.gitignore new file mode 100644 index 00000000..34b23da8 --- /dev/null +++ b/doc/.gitignore @@ -0,0 +1,2 @@ +/build/ +/node_modules/ diff --git a/doc/antora-playbook.yml b/doc/antora-playbook.yml new file mode 100644 index 00000000..d5201911 --- /dev/null +++ b/doc/antora-playbook.yml @@ -0,0 +1,12 @@ +site: + title: Docs Site + start_page: project-name::index.adoc +content: + sources: + - url: .. + start_path: doc + branches: HEAD +ui: + bundle: + url: https://gitlab.com/antora/antora-ui-default/-/jobs/artifacts/HEAD/raw/build/ui-bundle.zip?job=bundle-stable + snapshot: true diff --git a/doc/antora.yml b/doc/antora.yml new file mode 100644 index 00000000..472e48cb --- /dev/null +++ b/doc/antora.yml @@ -0,0 +1,5 @@ +name: project-name +version: ~ +title: Project Name +nav: + - modules/ROOT/nav.adoc diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..f983f4e2 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..cd7185ba Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..3249b67d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..227ef608 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..652c1f78 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..3cb93eb5 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..d231be5c Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..7e9a30b0 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..097d15f6 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..a4b3ab51 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..863d1c7b Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..fafa3bef Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..809c3318 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..48c449e8 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..e35f1a25 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..de82930e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..40910437 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..546a226d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..1803f6f3 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..ac55cbc7 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..9ff61345 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..b424d49d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..1e524304 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..ca121e62 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..afb4f810 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..feb133b8 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..7f3f679a Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..735a14cc Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..f49ea1a9 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..30bd02bc Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..996b73a8 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..cd9c7990 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..25cc9a0c Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..b9c3524a Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..16afca91 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..8f569590 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png new file mode 100644 index 00000000..45d712e5 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png new file mode 100644 index 00000000..d5121754 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png new file mode 100644 index 00000000..d8557346 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png new file mode 100644 index 00000000..c0cd0dbf Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png new file mode 100644 index 00000000..15fabd09 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png new file mode 100644 index 00000000..d729d508 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..e01caffd Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..396d7c8c Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..82946e47 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..d745607e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..39c7245b Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..2e8512ce Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..bc0ac6fa Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..2d718f5b Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..671e700e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..f745cc2c Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..62aace55 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..1e997b3d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..cfde3d48 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..95f1129a Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..dd2db3cd Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..163f6b7e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..3f84432a Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..9429d442 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..2cb8519d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..75a9c32e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..1b06622b Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..d58edb85 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..f6346791 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..565ab758 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..35a52fe5 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..f0fc8012 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..708c86b4 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..4ec67969 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..7c1870bc Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png new file mode 100644 index 00000000..fd4b3c3f Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png new file mode 100644 index 00000000..61ed9643 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png new file mode 100644 index 00000000..a7be6483 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png new file mode 100644 index 00000000..11569d6d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png new file mode 100644 index 00000000..8b901f31 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..46c3201d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique.png new file mode 100644 index 00000000..09f6bf78 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..91fc8981 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png new file mode 100644 index 00000000..c11d25f4 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png new file mode 100644 index 00000000..94c7dadb Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..9c275163 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..67b14fb5 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png new file mode 100644 index 00000000..87a02fb7 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..9f68a843 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..253f8147 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png new file mode 100644 index 00000000..9b857ddb Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..1ebff77e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png new file mode 100644 index 00000000..a00c9cbd Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png new file mode 100644 index 00000000..b5408eba Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png new file mode 100644 index 00000000..77870d8b Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png new file mode 100644 index 00000000..97f54b2e Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice.png new file mode 100644 index 00000000..f2e9492d Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/running insertion.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..0b5f9754 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique.png new file mode 100644 index 00000000..ea7b0509 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..87f92cb7 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png new file mode 100644 index 00000000..5041acda Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice.png new file mode 100644 index 00000000..babc4e3f Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered erasure.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..805b5876 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..c5dcf5a0 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png new file mode 100644 index 00000000..255c272c Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..931ef55c Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..735e3183 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png new file mode 100644 index 00000000..2f4d61c9 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..863f5d67 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png new file mode 100644 index 00000000..91546ddb Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png new file mode 100644 index 00000000..f11c9eb2 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png new file mode 100644 index 00000000..c60d3e83 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash.png b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash.png new file mode 100644 index 00000000..ceb79bb4 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice norehash.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice.png new file mode 100644 index 00000000..7f9ec959 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/running insertion.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..0b25793a Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique.png new file mode 100644 index 00000000..fe8bd367 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..142de003 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png new file mode 100644 index 00000000..94416751 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice.png new file mode 100644 index 00000000..d59c1b63 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered erasure.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..8eb2a9b2 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..9cd03ce8 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png new file mode 100644 index 00000000..ee9f8350 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..5a1a1cae Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..d717a31a Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png differ diff --git a/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png b/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png new file mode 100644 index 00000000..eba120e8 Binary files /dev/null and b/doc/modules/ROOT/images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png differ diff --git a/doc/modules/ROOT/images/bucket-groups.png b/doc/modules/ROOT/images/bucket-groups.png new file mode 100644 index 00000000..d9c5e96d Binary files /dev/null and b/doc/modules/ROOT/images/bucket-groups.png differ diff --git a/doc/modules/ROOT/images/buckets-oa.png b/doc/modules/ROOT/images/buckets-oa.png new file mode 100644 index 00000000..25fc6045 Binary files /dev/null and b/doc/modules/ROOT/images/buckets-oa.png differ diff --git a/doc/modules/ROOT/images/buckets.png b/doc/modules/ROOT/images/buckets.png new file mode 100644 index 00000000..ba14df79 Binary files /dev/null and b/doc/modules/ROOT/images/buckets.png differ diff --git a/doc/modules/ROOT/images/cfoa.png b/doc/modules/ROOT/images/cfoa.png new file mode 100644 index 00000000..a72e3d53 Binary files /dev/null and b/doc/modules/ROOT/images/cfoa.png differ diff --git a/doc/modules/ROOT/images/fca.png b/doc/modules/ROOT/images/fca.png new file mode 100644 index 00000000..d1ecb63c Binary files /dev/null and b/doc/modules/ROOT/images/fca.png differ diff --git a/doc/modules/ROOT/images/foa-metadata-interleaving.png b/doc/modules/ROOT/images/foa-metadata-interleaving.png new file mode 100644 index 00000000..0c751922 Binary files /dev/null and b/doc/modules/ROOT/images/foa-metadata-interleaving.png differ diff --git a/doc/modules/ROOT/images/foa-metadata.png b/doc/modules/ROOT/images/foa-metadata.png new file mode 100644 index 00000000..0d2a530f Binary files /dev/null and b/doc/modules/ROOT/images/foa-metadata.png differ diff --git a/doc/modules/ROOT/images/foa.png b/doc/modules/ROOT/images/foa.png new file mode 100644 index 00000000..9b3e2362 Binary files /dev/null and b/doc/modules/ROOT/images/foa.png differ diff --git a/doc/modules/ROOT/images/singly-linked.png b/doc/modules/ROOT/images/singly-linked.png new file mode 100644 index 00000000..ae3cf61a Binary files /dev/null and b/doc/modules/ROOT/images/singly-linked.png differ diff --git a/doc/modules/ROOT/nav.adoc b/doc/modules/ROOT/nav.adoc new file mode 100644 index 00000000..7d552ff9 --- /dev/null +++ b/doc/modules/ROOT/nav.adoc @@ -0,0 +1,16 @@ +* xref:intro.adoc[] +* xref:buckets.adoc[] +* xref:hash_equality.adoc[] +* xref:regular.adoc[] +* xref:concurrent.adoc[] +* xref:hash_quality.adoc[] +* xref:compliance.adoc[] +* xref:structures.adoc[] +* xref:debuggability.adoc[] +* xref:benchmarks.adoc[] +* xref:rationale.adoc[] +* xref:ref.adoc[] +** xref:reference/unordered_flat_map.adoc[unordered_flat_map] +* xref:changes.adoc[] +* xref:bibliography.adoc[] +* xref:copyright.adoc[] diff --git a/doc/modules/ROOT/pages/benchmarks.adoc b/doc/modules/ROOT/pages/benchmarks.adoc new file mode 100644 index 00000000..f7fb7d1b --- /dev/null +++ b/doc/modules/ROOT/pages/benchmarks.adoc @@ -0,0 +1,725 @@ +[#benchmarks] +:idprefix: benchmarks_ + += Benchmarks + +== boost::unordered_[multi]set + +All benchmarks were created using `unordered_set` (non-duplicate) and `unordered_multiset` (duplicate). The source code can be https://github.com/boostorg/boost_unordered_benchmarks/tree/boost_unordered_set[found here^]. + +The insertion benchmarks insert `n` random values, where `n` is between 10,000 and 3 million. For the duplicated benchmarks, the same random values are repeated an average of 5 times. + +The erasure benchmarks erase all `n` elements randomly until the container is empty. Erasure by key uses `erase(const key_type&)` to remove entire groups of equivalent elements in each operation. + +The successful lookup benchmarks are done by looking up all `n` values, in their original insertion order. + +The unsuccessful lookup benchmarks use `n` randomly generated integers but using a different seed value. + +=== GCC 12 + libstdc++-v3, x64 + +==== Insertion + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/gcc/running insertion.xlsx.practice.png[width=250,link=_images/benchmarks-set/gcc/running insertion.xlsx.practice.png,window=_blank] +|image::benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png[width=250,link=_images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png[width=250,link=_images/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png,window=_blank] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/gcc/running insertion.xlsx.practice norehash.png[width=250,link= _images/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png,window=_blank] +|image::benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png[width=250,link= _images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png,window=_blank] +|image::benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png[width=250,link= _images/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png,window=_blank] + +h|non-duplicate elements, + +prior `reserve` +h|duplicate elements, + +prior `reserve` +h|duplicate elements, + +max load factor 5, + +prior `reserve` + +|=== + +==== Erasure + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/gcc/scattered erasure.xlsx.practice.png[width=250,link= _images/benchmarks-set/gcc/scattered erasure.xlsx.practice.png,window=_blank] +|image::benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png[width=250,link= _images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png[width=250,link= _images/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png,window=_blank] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +| +|image::benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique.png[width=250,link= _images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique 5.png[width=250,link= _images/benchmarks-set/gcc/scattered erasure by key.xlsx.practice non-unique 5.png,window=_blank] + +| +h|by key, duplicate elements +h|by key, duplicate elements, + +max load factor 5 + +|=== + +==== Successful Lookup + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png] +|image::benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +==== Unsuccessful lookup + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png] +|image::benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +=== Clang 15 + libc++, x64 + +==== Insertion + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png[width=250, window=_blank,link= _images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png[width=250, window=_blank,link= _images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png[width=250, window=_blank,link= _images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png] +|image::benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png] +|image::benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png] + +h|non-duplicate elements, + +prior `reserve` +h|duplicate elements, + +prior `reserve` +h|duplicate elements, + +max load factor 5, + +prior `reserve` + +|=== + +==== Erasure + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +| +|image::benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique.png[width=250,link= _images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique 5.png[width=250,link= _images/benchmarks-set/clang_libcpp/scattered erasure by key.xlsx.practice non-unique 5.png,window=_blank] + +| +h|by key, duplicate elements +h|by key, duplicate elements, + +max load factor 5 + +|=== + +==== Successful lookup + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +==== Unsuccessful lookup + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +=== Visual Studio 2022 + Dinkumware, x64 + +==== Insertion + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/vs/running insertion.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/vs/running insertion.xlsx.practice.png] +|image::benchmarks-set/vs/running insertion.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/vs/running insertion.xlsx.practice norehash.png[width=250,window=_blank,link= _images/benchmarks-set/vs/running insertion.xlsx.practice norehash.png] +|image::benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png] +|image::benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png] + +h|non-duplicate elements, + +prior `reserve` +h|duplicate elements, + +prior `reserve` +h|duplicate elements, + +max load factor 5, + +prior `reserve` + +|=== + +==== Erasure + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/vs/scattered erasure.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered erasure.xlsx.practice.png] +|image::benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +| +|image::benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique.png[width=250,link= _images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique 5.png[width=250,link= _images/benchmarks-set/vs/scattered erasure by key.xlsx.practice non-unique 5.png,window=_blank] + +| +h|by key, duplicate elements +h|by key, duplicate elements, + +max load factor 5 + +|=== + +==== Successful lookup + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/vs/scattered successful looukp.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png] +|image::benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +==== Unsuccessful lookup + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png] +|image::benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link= _images/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png] + +h|non-duplicate elements +h|duplicate elements +h|duplicate elements, + +max load factor 5 + +|=== + +== boost::unordered_(flat|node)_map + +All benchmarks were created using: + +* `https://abseil.io/docs/cpp/guides/container[absl::flat_hash_map^]` +* `boost::unordered_map` +* `boost::unordered_flat_map` +* `boost::unordered_node_map` + +The source code can be https://github.com/boostorg/boost_unordered_benchmarks/tree/boost_unordered_flat_map[found here^]. + +The insertion benchmarks insert `n` random values, where `n` is between 10,000 and 10 million. + +The erasure benchmarks erase traverse the `n` elements and erase those with odd key (50% on average). + +The successful lookup benchmarks are done by looking up all `n` values, in their original insertion order. + +The unsuccessful lookup benchmarks use `n` randomly generated integers but using a different seed value. + + +=== GCC 12, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Clang 15, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Visual Studio 2022, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Clang 12, ARM64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== GCC 12, x86 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Clang 15, x86 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Visual Studio 2022, x86 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png[width=250,window=_blank,link= _images/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +== boost::concurrent_(flat|node)_map + +All benchmarks were created using: + +* `https://spec.oneapi.io/versions/latest/elements/oneTBB/source/containers/concurrent_hash_map_cls.html[oneapi::tbb::concurrent_hash_map^]` +* `https://github.com/greg7mdp/gtl/blob/main/docs/phmap.md[gtl::parallel_flat_hash_map^]` with 64 submaps +* `boost::concurrent_flat_map` +* `boost::concurrent_node_map` + +The source code can be https://github.com/boostorg/boost_unordered_benchmarks/tree/boost_concurrent_flat_map[found here^]. + +The benchmarks exercise a number of threads _T_ (between 1 and 16) concurrently performing operations +randomly chosen among **update**, **successful lookup** and **unsuccessful lookup**. The keys used in the +operations follow a https://en.wikipedia.org/wiki/Zipf%27s_law#Formal_definition[Zipf distribution^] +with different _skew_ parameters: the higher the skew, the more concentrated are the keys in the lower values +of the covered range. + +`boost::concurrent_flat_map` and `boost::concurrent_node_map` are exercised using both regular and xref:#concurrent_bulk_visitation[bulk visitation]: +in the latter case, lookup keys are buffered in a local array and then processed at +once each time the buffer reaches xref:#concurrent_flat_map_constants[`bulk_visit_size`]. + +=== GCC 12, x64 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x64/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== + +=== Clang 15, x64 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x64/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== + +=== Visual Studio 2022, x64 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x64/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== + +=== Clang 12, ARM64 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-arm64/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== + +=== GCC 12, x86 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/gcc-x86/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== + +=== Clang 15, x86 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/clang-x86/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== + +=== Visual Studio 2022, x86 + + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.01.png] +|image::benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.5.png] +|image::benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.500k, 0.99.png] + +h|500k updates, 4.5M lookups + +skew=0.01 +h|500k updates, 4.5M lookups + +skew=0.5 +h|500k updates, 4.5M lookups + +skew=0.99 +|=== + +[caption=] +[cols="3*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.01.png] +|image::benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.5.png] +|image::benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png[width=250,window=_blank,link= _images/benchmarks-concurrent_map/vs-x86/Parallel workload.xlsx.5M, 0.99.png] + +h|5M updates, 45M lookups + +skew=0.01 +h|5M updates, 45M lookups + +skew=0.5 +h|5M updates, 45M lookups + +skew=0.99 +|=== diff --git a/doc/modules/ROOT/pages/bibliography.adoc b/doc/modules/ROOT/pages/bibliography.adoc new file mode 100644 index 00000000..020d3c04 --- /dev/null +++ b/doc/modules/ROOT/pages/bibliography.adoc @@ -0,0 +1,12 @@ +[#bibliography] + +:idprefix: bibliography_ + += Bibliography + +* _C/C++ Users Journal_. February, 2006. Pete Becker. http://www.ddj.com/cpp/184402066[STL and TR1: Part III - Unordered containers^]. + +An introduction to the standard unordered containers. +* _Wikipedia_. https://en.wikipedia.org/wiki/Hash_table[Hash table^]. + +An introduction to hash table implementations. Discusses the differences between closed-addressing and open-addressing approaches. +* Peter Dimov, 2022. https://pdimov.github.io/articles/unordered_dev_plan.html[Development Plan for Boost.Unordered^]. + diff --git a/doc/modules/ROOT/pages/buckets.adoc b/doc/modules/ROOT/pages/buckets.adoc new file mode 100644 index 00000000..bbf77e24 --- /dev/null +++ b/doc/modules/ROOT/pages/buckets.adoc @@ -0,0 +1,147 @@ +[#buckets] +:idprefix: buckets_ + += Basics of Hash Tables + +The containers are made up of a number of _buckets_, each of which can contain +any number of elements. For example, the following diagram shows a <> with 7 buckets containing 5 elements, `A`, +`B`, `C`, `D` and `E` (this is just for illustration, containers will typically +have more buckets). + +image::buckets.png[] + +In order to decide which bucket to place an element in, the container applies +the hash function, `Hash`, to the element's key (for sets the key is the whole element, but is referred to as the key +so that the same terminology can be used for sets and maps). This returns a +value of type `std::size_t`. `std::size_t` has a much greater range of values +then the number of buckets, so the container applies another transformation to +that value to choose a bucket to place the element in. + +Retrieving the elements for a given key is simple. The same process is applied +to the key to find the correct bucket. Then the key is compared with the +elements in the bucket to find any elements that match (using the equality +predicate `Pred`). If the hash function has worked well the elements will be +evenly distributed amongst the buckets so only a small number of elements will +need to be examined. + +There is <>. + +You can see in the diagram that `A` & `D` have been placed in the same bucket. +When looking for elements in this bucket up to 2 comparisons are made, making +the search slower. This is known as a *collision*. To keep things fast we try to +keep collisions to a minimum. + +If instead of `boost::unordered_set` we had used <>, the +diagram would look as follows: + +image::buckets-oa.png[] + +In open-addressing containers, buckets can hold at most one element; if a collision happens +(like is the case of `D` in the example), the element uses some other available bucket in +the vicinity of the original position. Given this simpler scenario, Boost.Unordered +open-addressing containers offer a very limited API for accessing buckets. + +[caption=, title='Table {counter:table-counter}. Methods for Accessing Buckets'] +[cols="1,.^1", frame=all, grid=rows] +|=== +2+^h| *All containers* +h|*Method* h|*Description* + +|`size_type bucket_count() const` +|The number of buckets. + +2+^h| *Closed-addressing containers only* +h|*Method* h|*Description* + +|`size_type max_bucket_count() const` +|An upper bound on the number of buckets. +|`size_type bucket_size(size_type n) const` +|The number of elements in bucket `n`. + +|`size_type bucket(key_type const& k) const` +|Returns the index of the bucket which would contain `k`. + +|`local_iterator begin(size_type n)` +1.6+|Return begin and end iterators for bucket `n`. + +|`local_iterator end(size_type n)` + +|`const_local_iterator begin(size_type n) const` + +|`const_local_iterator end(size_type n) const` + +|`const_local_iterator cbegin(size_type n) const` + +|`const_local_iterator cend(size_type n) const` + +|=== + +== Controlling the Number of Buckets + +As more elements are added to an unordered associative container, the number +of collisions will increase causing performance to degrade. +To combat this the containers increase the bucket count as elements are inserted. +You can also tell the container to change the bucket count (if required) by +calling `rehash`. + +The standard leaves a lot of freedom to the implementer to decide how the +number of buckets is chosen, but it does make some requirements based on the +container's _load factor_, the number of elements divided by the number of buckets. +Containers also have a _maximum load factor_ which they should try to keep the +load factor below. + +You can't control the bucket count directly but there are two ways to +influence it: + +* Specify the minimum number of buckets when constructing a container or when calling `rehash`. +* Suggest a maximum load factor by calling `max_load_factor`. + +`max_load_factor` doesn't let you set the maximum load factor yourself, it just +lets you give a _hint_. And even then, the standard doesn't actually +require the container to pay much attention to this value. The only time the +load factor is _required_ to be less than the maximum is following a call to +`rehash`. But most implementations will try to keep the number of elements +below the max load factor, and set the maximum load factor to be the same as +or close to the hint - unless your hint is unreasonably small or large. + +[caption=, title='Table {counter:table-counter}. Methods for Controlling Bucket Size'] +[cols="1,.^1", frame=all, grid=rows] +|=== +2+^h| *All containers* +h|*Method* h|*Description* + +|`X(size_type n)` +|Construct an empty container with at least `n` buckets (`X` is the container type). + +|`X(InputIterator i, InputIterator j, size_type n)` +|Construct an empty container with at least `n` buckets and insert elements from the range `[i, j)` (`X` is the container type). + +|`float load_factor() const` +|The average number of elements per bucket. + +|`float max_load_factor() const` +|Returns the current maximum load factor. + +|`float max_load_factor(float z)` +|Changes the container's maximum load factor, using `z` as a hint. + +**Open-addressing and concurrent containers:** this function does nothing: users are not allowed to change the maximum load factor. + +|`void rehash(size_type n)` +|Changes the number of buckets so that there at least `n` buckets, and so that the load factor is less than the maximum load factor. + +2+^h| *Open-addressing and concurrent containers only* +h|*Method* h|*Description* + +|`size_type max_load() const` +|Returns the maximum number of allowed elements in the container before rehash. + +|=== + +A note on `max_load` for open-addressing and concurrent containers: the maximum load will be +(`max_load_factor() * bucket_count()`) right after `rehash` or on container creation, but may +slightly decrease when erasing elements in high-load situations. For instance, if we +have a <> with `size()` almost +at `max_load()` level and then erase 1,000 elements, `max_load()` may decrease by around a +few dozen elements. This is done internally by Boost.Unordered in order +to keep its performance stable, and must be taken into account when planning for rehash-free insertions. diff --git a/doc/modules/ROOT/pages/changes.adoc b/doc/modules/ROOT/pages/changes.adoc new file mode 100644 index 00000000..32a1bf64 --- /dev/null +++ b/doc/modules/ROOT/pages/changes.adoc @@ -0,0 +1,458 @@ +[#changes] += Change Log + +:idprefix: changes_ +:svn-ticket-url: https://svn.boost.org/trac/boost/ticket +:github-pr-url: https://github.com/boostorg/unordered/pull +:cpp: C++ + +== Release 1.87.0 - Major update + +* Added concurrent, node-based containers `boost::concurrent_node_map` and `boost::concurrent_node_set`. +* Added `insert_and_visit(x, f1, f2)` and similar operations to concurrent containers, which +allow for visitation of an element right after insertion (by contrast, `insert_or_visit(x, f)` only +visits the element if insertion did _not_ take place). +* Made visitation exclusive-locked within certain +`boost::concurrent_flat_set` operations to allow for safe mutable modification of elements +({github-pr-url}/265[PR#265^]). +* In Visual Studio Natvis, supported any container with an allocator that uses fancy pointers. This applies to any fancy pointer type, as long as the proper Natvis customization point "Intrinsic" functions are written for the fancy pointer type. +* Added GDB pretty-printers for all containers and iterators. For a container with an allocator that uses fancy pointers, these only work if the proper pretty-printer is written for the fancy pointer type itself. +* Fixed `std::initializer_list` assignment issues for open-addressing containers +({github-pr-url}/277[PR#277^]). +* Allowed non-copyable callables to be passed to the `std::initializer_list` overloads of `insert_{and|or}_[c]visit` for concurrent containers, by internally passing a `std::reference_wrapper` of the callable to the iterator-pair overloads. + + +== Release 1.86.0 + +* Added container `pmr` aliases when header `` is available. The alias `boost::unordered::pmr::[container]` refers to `boost::unordered::[container]` with a `std::pmr::polymorphic_allocator` allocator type. +* Equipped open-addressing and concurrent containers to internally calculate and provide statistical metrics affected by the quality of the hash function. This functionality is enabled by the global macro `BOOST_UNORDERED_ENABLE_STATS`. +* Avalanching hash functions must now be marked via an `is_avalanching` typedef with an embedded `value` constant set to `true` (typically, defining `is_avalanching` as `std::true_type`). `using is_avalanching = void` is deprecated but allowed for backwards compatibility. +* Added Visual Studio Natvis framework custom visualizations for containers and iterators. This works for all containers with an allocator using raw pointers. In this release, containers and iterators are not supported if their allocator uses fancy pointers. This may be addressed in later releases. + +== Release 1.85.0 + +* Optimized `emplace()` for a `value_type` or `init_type` (if applicable) argument to bypass creating an intermediate object. The argument is already the same type as the would-be intermediate object. +* Optimized `emplace()` for `k,v` arguments on map containers to delay constructing the object until it is certain that an element should be inserted. This optimization happens when the map's `key_type` is move constructible or when the `k` argument is a `key_type`. +* Fixed support for allocators with `explicit` copy constructors ({github-pr-url}/234[PR#234^]). +* Fixed bug in the `const` version of `unordered_multimap::find(k, hash, eq)` ({github-pr-url}/238[PR#238^]). + +== Release 1.84.0 - Major update + +* Added `boost::concurrent_flat_set`. +* Added `[c]visit_while` operations to concurrent containers, +with serial and parallel variants. +* Added efficient move construction of `boost::unordered_flat_(map|set)` from +`boost::concurrent_flat_(map|set)` and vice versa. +* Added bulk visitation to concurrent containers for increased lookup performance. +* Added debug-mode mechanisms for detecting illegal reentrancies into +a concurrent container from user code. +* Added Boost.Serialization support to all containers and their (non-local) iterator types. +* Added support for fancy pointers to open-addressing and concurrent containers. + This enables scenarios like the use of Boost.Interprocess allocators to construct containers in shared memory. +* Fixed bug in member of pointer operator for local iterators of closed-addressing + containers ({github-pr-url}/221[PR#221^], credit goes to GitHub user vslashg for finding + and fixing this issue). +* Starting with this release, `boost::unordered_[multi]set` and `boost::unordered_[multi]map` + only work with C++11 onwards. + +== Release 1.83.0 - Major update + +* Added `boost::concurrent_flat_map`, a fast, thread-safe hashmap based on open addressing. +* Sped up iteration of open-addressing containers. +* In open-addressing containers, `erase(iterator)`, which previously returned nothing, now +returns a proxy object convertible to an iterator to the next element. +This enables the typical `it = c.erase(it)` idiom without incurring any performance penalty +when the returned proxy is not used. + +== Release 1.82.0 - Major update + +* {cpp}03 support is planned for deprecation. Boost 1.84.0 will no longer support + {cpp}03 mode and {cpp}11 will become the new minimum for using the library. +* Added node-based, open-addressing containers + `boost::unordered_node_map` and `boost::unordered_node_set`. +* Extended heterogeneous lookup to more member functions as specified in + https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2363r5.html[P2363]. +* Replaced the previous post-mixing process for open-addressing containers with + a new algorithm based on extended multiplication by a constant. +* Fixed bug in internal emplace() impl where stack-local types were not properly + constructed using the Allocator of the container which breaks uses-allocator + construction. + +== Release 1.81.0 - Major update + +* Added fast containers `boost::unordered_flat_map` and `boost::unordered_flat_set` + based on open addressing. +* Added CTAD deduction guides for all containers. +* Added missing constructors as specified in https://cplusplus.github.io/LWG/issue2713[LWG issue 2713]. + +== Release 1.80.0 - Major update + +* Refactor internal implementation to be dramatically faster +* Allow `final` Hasher and KeyEqual objects +* Update documentation, adding benchmark graphs and notes on the new internal + data structures + +== Release 1.79.0 + +* Improved {cpp}20 support: + ** All containers have been updated to support + heterogeneous `count`, `equal_range` and `find`. + ** All containers now implement the member function `contains`. + ** `erase_if` has been implemented for all containers. +* Improved {cpp}23 support: + ** All containers have been updated to support + heterogeneous `erase` and `extract`. +* Changed behavior of `reserve` to eagerly + allocate ({github-pr-url}/59[PR#59^]). +* Various warning fixes in the test suite. +* Update code to internally use `boost::allocator_traits`. +* Switch to Fibonacci hashing. +* Update documentation to be written in AsciiDoc instead of QuickBook. + +== Release 1.67.0 + +* Improved {cpp}17 support: + ** Add template deduction guides from the standard. + ** Use a simple implementation of `optional` in node handles, so + that they're closer to the standard. + ** Add missing `noexcept` specifications to `swap`, `operator=` + and node handles, and change the implementation to match. + Using `std::allocator_traits::is_always_equal`, or our own + implementation when not available, and + `boost::is_nothrow_swappable` in the implementation. +* Improved {cpp}20 support: + ** Use `boost::to_address`, which has the proposed {cpp}20 semantics, + rather than the old custom implementation. +* Add `element_type` to iterators, so that `std::pointer_traits` + will work. +* Use `std::piecewise_construct` on recent versions of Visual {cpp}, + and other uses of the Dinkumware standard library, + now using Boost.Predef to check compiler and library versions. +* Use `std::iterator_traits` rather than the boost iterator traits + in order to remove dependency on Boost.Iterator. +* Remove iterators' inheritance from `std::iterator`, which is + deprecated in {cpp}17, thanks to Daniela Engert + ({github-pr-url}/7[PR#7^]). +* Stop using `BOOST_DEDUCED_TYPENAME`. +* Update some Boost include paths. +* Rename some internal methods, and variables. +* Various testing improvements. +* Miscellaneous internal changes. + +== Release 1.66.0 + +* Simpler move construction implementation. +* Documentation fixes ({github-pr-url}/6[GitHub #6^]). + +== Release 1.65.0 + +* Add deprecated attributes to `quick_erase` and `erase_return_void`. + I really will remove them in a future version this time. +* Small standards compliance fixes: + ** `noexpect` specs for `swap` free functions. + ** Add missing `insert(P&&)` methods. + +== Release 1.64.0 + +* Initial support for new {cpp}17 member functions: + `insert_or_assign` and `try_emplace` in `unordered_map`, +* Initial support for `merge` and `extract`. + Does not include transferring nodes between + `unordered_map` and `unordered_multimap` or between `unordered_set` and + `unordered_multiset` yet. That will hopefully be in the next version of + Boost. + +== Release 1.63.0 + +* Check hint iterator in `insert`/`emplace_hint`. +* Fix some warnings, mostly in the tests. +* Manually write out `emplace_args` for small numbers of arguments - + should make template error messages a little more bearable. +* Remove superfluous use of `boost::forward` in emplace arguments, + which fixes emplacing string literals in old versions of Visual {cpp}. +* Fix an exception safety issue in assignment. If bucket allocation + throws an exception, it can overwrite the hash and equality functions while + leaving the existing elements in place. This would mean that the function + objects wouldn't match the container elements, so elements might be in the + wrong bucket and equivalent elements would be incorrectly handled. +* Various reference documentation improvements. +* Better allocator support ({svn-ticket-url}/12459[#12459^]). +* Make the no argument constructors implicit. +* Implement missing allocator aware constructors. +* Fix assigning the hash/key equality functions for empty containers. +* Remove unary/binary_function from the examples in the documentation. + They are removed in {cpp}17. +* Support 10 constructor arguments in emplace. It was meant to support up to 10 + arguments, but an off by one error in the preprocessor code meant it only + supported up to 9. + +== Release 1.62.0 + +* Remove use of deprecated `boost::iterator`. +* Remove `BOOST_NO_STD_DISTANCE` workaround. +* Remove `BOOST_UNORDERED_DEPRECATED_EQUALITY` warning. +* Simpler implementation of assignment, fixes an exception safety issue + for `unordered_multiset` and `unordered_multimap`. Might be a little slower. +* Stop using return value SFINAE which some older compilers have issues + with. + +== Release 1.58.0 + +* Remove unnecessary template parameter from const iterators. +* Rename private `iterator` typedef in some iterator classes, as it + confuses some traits classes. +* Fix move assignment with stateful, propagate_on_container_move_assign + allocators ({svn-ticket-url}/10777[#10777^]). +* Fix rare exception safety issue in move assignment. +* Fix potential overflow when calculating number of buckets to allocate + ({github-pr-url}/4[GitHub #4^]). + +== Release 1.57.0 + +* Fix the `pointer` typedef in iterators ({svn-ticket-url}/10672[#10672^]). +* Fix Coverity warning + ({github-pr-url}/2[GitHub #2^]). + +== Release 1.56.0 + +* Fix some shadowed variable warnings ({svn-ticket-url}/9377[#9377^]). +* Fix allocator use in documentation ({svn-ticket-url}/9719[#9719^]). +* Always use prime number of buckets for integers. Fixes performance + regression when inserting consecutive integers, although makes other + uses slower ({svn-ticket-url}/9282[#9282^]). +* Only construct elements using allocators, as specified in {cpp}11 standard. + +== Release 1.55.0 + +* Avoid some warnings ({svn-ticket-url}/8851[#8851^], {svn-ticket-url}/8874[#8874^]). +* Avoid exposing some detail functions via. ADL on the iterators. +* Follow the standard by only using the allocators' construct and destroy + methods to construct and destroy stored elements. Don't use them for internal + data like pointers. + +== Release 1.54.0 + +* Mark methods specified in standard as `noexpect`. More to come in the next + release. +* If the hash function and equality predicate are known to both have nothrow + move assignment or construction then use them. + +== Release 1.53.0 + +* Remove support for the old pre-standard variadic pair constructors, and + equality implementation. Both have been deprecated since Boost 1.48. +* Remove use of deprecated config macros. +* More internal implementation changes, including a much simpler + implementation of `erase`. + +== Release 1.52.0 + +* Faster assign, which assigns to existing nodes where possible, rather than + creating entirely new nodes and copy constructing. +* Fixed bug in `erase_range` ({svn-ticket-url}/7471[#7471^]). +* Reverted some of the internal changes to how nodes are created, especially + for {cpp}11 compilers. 'construct' and 'destroy' should work a little better + for {cpp}11 allocators. +* Simplified the implementation a bit. Hopefully more robust. + +== Release 1.51.0 + +* Fix construction/destruction issue when using a {cpp}11 compiler with a + {cpp}03 allocator ({svn-ticket-url}/7100[#7100^]). +* Remove a `try..catch` to support compiling without exceptions. +* Adjust SFINAE use to try to support g++ 3.4 ({svn-ticket-url}/7175[#7175^]). +* Updated to use the new config macros. + +== Release 1.50.0 + +* Fix equality for `unordered_multiset` and `unordered_multimap`. +* {svn-ticket-url}/6857[Ticket 6857^]: + Implement `reserve`. +* {svn-ticket-url}/6771[Ticket 6771^]: + Avoid gcc's `-Wfloat-equal` warning. +* {svn-ticket-url}/6784[Ticket 6784^]: + Fix some Sun specific code. +* {svn-ticket-url}/6190[Ticket 6190^]: + Avoid gcc's `-Wshadow` warning. +* {svn-ticket-url}/6905[Ticket 6905^]: + Make namespaces in macros compatible with `bcp` custom namespaces. + Fixed by Luke Elliott. +* Remove some of the smaller prime number of buckets, as they may make + collisions quite probable (e.g. multiples of 5 are very common because + we used base 10). +* On old versions of Visual {cpp}, use the container library's implementation + of `allocator_traits`, as it's more likely to work. +* On machines with 64 bit std::size_t, use power of 2 buckets, with Thomas + Wang's hash function to pick which one to use. As modulus is very slow + for 64 bit values. +* Some internal changes. + +== Release 1.49.0 + +* Fix warning due to accidental odd assignment. +* Slightly better error messages. + +== Release 1.48.0 - Major update + +This is major change which has been converted to use Boost.Move's move +emulation, and be more compliant with the {cpp}11 standard. See the +xref:compliance.adoc[compliance section] for details. + +The container now meets {cpp}11's complexity requirements, but to do so +uses a little more memory. This means that `quick_erase` and +`erase_return_void` are no longer required, they'll be removed in a +future version. + +{cpp}11 support has resulted in some breaking changes: + +* Equality comparison has been changed to the {cpp}11 specification. + In a container with equivalent keys, elements in a group with equal + keys used to have to be in the same order to be considered equal, + now they can be a permutation of each other. To use the old + behavior define the macro `BOOST_UNORDERED_DEPRECATED_EQUALITY`. + +* The behaviour of swap is different when the two containers to be + swapped has unequal allocators. It used to allocate new nodes using + the appropriate allocators, it now swaps the allocators if + the allocator has a member structure `propagate_on_container_swap`, + such that `propagate_on_container_swap::value` is true. + +* Allocator's `construct` and `destroy` functions are called with raw + pointers, rather than the allocator's `pointer` type. + +* `emplace` used to emulate the variadic pair constructors that + appeared in early {cpp}0x drafts. Since they were removed it no + longer does so. It does emulate the new `piecewise_construct` + pair constructors - only you need to use + `boost::piecewise_construct`. To use the old emulation of + the variadic constructors define + `BOOST_UNORDERED_DEPRECATED_PAIR_CONSTRUCT`. + +== Release 1.45.0 + +* Fix a bug when inserting into an `unordered_map` or `unordered_set` using + iterators which returns `value_type` by copy. + +== Release 1.43.0 + +* {svn-ticket-url}/3966[Ticket 3966^]: + `erase_return_void` is now `quick_erase`, which is the + http://home.roadrunner.com/~hinnant/issue_review/lwg-active.html#579[ + current forerunner for resolving the slow erase by iterator^], although + there's a strong possibility that this may change in the future. The old + method name remains for backwards compatibility but is considered deprecated + and will be removed in a future release. +* Use Boost.Exception. +* Stop using deprecated `BOOST_HAS_*` macros. + +== Release 1.42.0 + +* Support instantiating the containers with incomplete value types. +* Reduced the number of warnings (mostly in tests). +* Improved codegear compatibility. +* {svn-ticket-url}/3693[Ticket 3693^]: + Add `erase_return_void` as a temporary workaround for the current + `erase` which can be inefficient because it has to find the next + element to return an iterator. +* Add templated find overload for compatible keys. +* {svn-ticket-url}/3773[Ticket 3773^]: + Add missing `std` qualifier to `ptrdiff_t`. +* Some code formatting changes to fit almost all lines into 80 characters. + +== Release 1.41.0 - Major update + +* The original version made heavy use of macros to sidestep some of the older + compilers' poor template support. But since I no longer support those + compilers and the macro use was starting to become a maintenance burden it + has been rewritten to use templates instead of macros for the implementation + classes. + +* The container object is now smaller thanks to using `boost::compressed_pair` + for EBO and a slightly different function buffer - now using a bool instead + of a member pointer. + +* Buckets are allocated lazily which means that constructing an empty container + will not allocate any memory. + +== Release 1.40.0 + +* {svn-ticket-url}/2975[Ticket 2975^]: + Store the prime list as a preprocessor sequence - so that it will always get + the length right if it changes again in the future. +* {svn-ticket-url}/1978[Ticket 1978^]: + Implement `emplace` for all compilers. +* {svn-ticket-url}/2908[Ticket 2908^], + {svn-ticket-url}/3096[Ticket 3096^]: + Some workarounds for old versions of borland, including adding explicit + destructors to all containers. +* {svn-ticket-url}/3082[Ticket 3082^]: + Disable incorrect Visual {cpp} warnings. +* Better configuration for {cpp}0x features when the headers aren't available. +* Create less buckets by default. + +== Release 1.39.0 + +* {svn-ticket-url}/2756[Ticket 2756^]: Avoid a warning + on Visual {cpp} 2009. +* Some other minor internal changes to the implementation, tests and + documentation. +* Avoid an unnecessary copy in `operator[]`. +* {svn-ticket-url}/2975[Ticket 2975^]: Fix length of + prime number list. + +== Release 1.38.0 + +* Use link:../../../core/swap.html[`boost::swap`^]. +* {svn-ticket-url}/2237[Ticket 2237^]: + Document that the equality and inequality operators are undefined for two + objects if their equality predicates aren't equivalent. Thanks to Daniel + Krügler. +* {svn-ticket-url}/1710[Ticket 1710^]: + Use a larger prime number list. Thanks to Thorsten Ottosen and Hervé + Brönnimann. +* Use + link:../../../type_traits/index.html[aligned storage^] to store the types. + This changes the way the allocator is used to construct nodes. It used to + construct the node with two calls to the allocator's `construct` + method - once for the pointers and once for the value. It now constructs + the node with a single call to construct and then constructs the value using + in place construction. +* Add support for {cpp}0x initializer lists where they're available (currently + only g++ 4.4 in {cpp}0x mode). + +== Release 1.37.0 + +* Rename overload of `emplace` with hint, to `emplace_hint` as specified in + http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2691.pdf[n2691^]. +* Provide forwarding headers at `` and + ``. +* Move all the implementation inside `boost/unordered`, to assist + modularization and hopefully make it easier to track Release subversion. + +== Release 1.36.0 + +First official release. + +* Rearrange the internals. +* Move semantics - full support when rvalue references are available, emulated + using a cut down version of the Adobe move library when they are not. +* Emplace support when rvalue references and variadic template are available. +* More efficient node allocation when rvalue references and variadic template + are available. +* Added equality operators. + +== Boost 1.35.0 Add-on - 31st March 2008 + +Unofficial release uploaded to vault, to be used with Boost 1.35.0. Incorporated +many of the suggestions from the review. + +* Improved portability thanks to Boost regression testing. +* Fix lots of typos, and clearer text in the documentation. +* Fix floating point to `std::size_t` conversion when calculating sizes from + the max load factor, and use `double` in the calculation for greater accuracy. +* Fix some errors in the examples. + +== Review Version + +Initial review version, for the review conducted from 7th December 2007 to +16th December 2007. diff --git a/doc/modules/ROOT/pages/compliance.adoc b/doc/modules/ROOT/pages/compliance.adoc new file mode 100644 index 00000000..d532b246 --- /dev/null +++ b/doc/modules/ROOT/pages/compliance.adoc @@ -0,0 +1,150 @@ +[#compliance] += Standard Compliance + +:idprefix: compliance_ + +:cpp: C++ + +== Closed-addressing Containers + +`boost::unordered_[multi]set` and `boost::unordered_[multi]map` provide a conformant +implementation for {cpp}11 (or later) compilers of the latest standard revision of +{cpp} unordered associative containers, with very minor deviations as noted. +The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^] +and support https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers^]. + +=== Deduction Guides + +Deduction guides for +https://en.cppreference.com/w/cpp/language/class_template_argument_deduction[class template argument deduction (CTAD)^] +are only available on {cpp}17 (or later) compilers. + +=== Piecewise Pair Emplacement + +In accordance with the standard specification, +`boost::unordered_[multi]map::emplace` supports piecewise pair construction: + +[source,c++] +---- +boost::unordered_multimap x; + +x.emplace( + std::piecewise_construct, + std::make_tuple("key"), std::make_tuple(1, 2)); +---- + +Additionally, the same +functionality is provided via non-standard `boost::unordered::piecewise_construct` +and Boost.Tuple: + +[source,c++] +---- +x.emplace( + boost::unordered::piecewise_construct, + boost::make_tuple("key"), boost::make_tuple(1, 2)); +---- + +This feature has been retained for backwards compatibility with +previous versions of Boost.Unordered: users are encouraged to +update their code to use `std::piecewise_construct` and +``std::tuple``s instead. + +=== Swap + +When swapping, `Pred` and `Hash` are not currently swapped by calling +`swap`, their copy constructors are used. As a consequence, when swapping +an exception may be thrown from their copy constructor. + +== Open-addressing Containers + +The C++ standard does not currently provide any open-addressing container +specification to adhere to, so `boost::unordered_flat_set`/`unordered_node_set` and +`boost::unordered_flat_map`/`unordered_node_map` take inspiration from `std::unordered_set` and +`std::unordered_map`, respectively, and depart from their interface where +convenient or as dictated by their internal data structure, which is +radically different from that imposed by the standard (closed addressing). + +Open-addressing containers provided by Boost.Unordered only work with reasonably +compliant C++11 (or later) compilers. Language-level features such as move semantics +and variadic template parameters are then not emulated. +The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^] +and support https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers^]. + + +The main differences with C++ unordered associative containers are: + +* In general: + ** `begin()` is not constant-time. + ** `erase(iterator)` does not return an iterator to the following element, but + a proxy object that converts to that iterator if requested; this avoids + a potentially costly iterator increment operation when not needed. + ** There is no API for bucket handling (except `bucket_count`). + ** The maximum load factor of the container is managed internally and can't be set by the user. The maximum load, + exposed through the public function `max_load`, may decrease on erasure under high-load conditions. +* Flat containers (`boost::unordered_flat_set` and `boost::unordered_flat_map`): + ** `value_type` must be move-constructible. + ** Pointer stability is not kept under rehashing. + ** There is no API for node extraction/insertion. + +== Concurrent Containers + +There is currently no specification in the C++ standard for this or any other type of concurrent +data structure. The APIs of `boost::concurrent_flat_set`/`boost::concurrent_node_set` and +`boost::concurrent_flat_map`/`boost::concurrent_node_map` +are modelled after `std::unordered_flat_set` and `std::unordered_flat_map`, respectively, +with the crucial difference that iterators are not provided +due to their inherent problems in concurrent scenarios (high contention, prone to deadlocking): +so, Boost.Unordered concurrent containers are technically not models of +https://en.cppreference.com/w/cpp/named_req/Container[Container^], although +they meet all the requirements of https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^] +containers (including +https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointer^] support) +except those implying iterators. + +In a non-concurrent unordered container, iterators serve two main purposes: + +* Access to an element previously located via lookup. +* Container traversal. + +In place of iterators, Boost.Unordered concurrent containers use _internal visitation_ +facilities as a thread-safe substitute. Classical operations returning an iterator to an +element already existing in the container, like for instance: + +[source,c++] +---- +iterator find(const key_type& k); +std::pair insert(const value_type& obj); +---- + +are transformed to accept a _visitation function_ that is passed such element: + +[source,c++] +---- +template size_t visit(const key_type& k, F f); +template bool insert_or_visit(const value_type& obj, F f); +---- + +(In the second case `f` is only invoked if there's an equivalent element +to `obj` in the table, not if insertion is successful). Container traversal +is served by: + +[source,c++] +---- +template size_t visit_all(F f); +---- + +of which there are parallelized versions in C++17 compilers with parallel +algorithm support. In general, the interface of concurrent containers +is derived from that of their non-concurrent counterparts by a fairly straightforward +process of replacing iterators with visitation where applicable. If for +regular maps `iterator` and `const_iterator` provide mutable and const access to elements, +respectively, here visitation is granted mutable or const access depending on +the constness of the member function used (there are also `*cvisit` overloads for +explicit const visitation); In the case of `boost::concurrent_flat_set`, visitation is always const. + +One notable operation not provided by `boost::concurrent_flat_map`/`boost::concurrent_node_map` +is `operator[]`/`at`, which can be +replaced, if in a more convoluted manner, by +xref:#concurrent_flat_map_try_emplace_or_cvisit[`try_emplace_or_visit`]. + +//- diff --git a/doc/modules/ROOT/pages/concurrent.adoc b/doc/modules/ROOT/pages/concurrent.adoc new file mode 100644 index 00000000..75fd7922 --- /dev/null +++ b/doc/modules/ROOT/pages/concurrent.adoc @@ -0,0 +1,320 @@ +[#concurrent] += Concurrent Containers + +:idprefix: concurrent_ + +Boost.Unordered provides `boost::concurrent_node_set`, `boost::concurrent_node_map`, +`boost::concurrent_flat_set` and `boost::concurrent_flat_map`, +hash tables that allow concurrent write/read access from +different threads without having to implement any synchronzation mechanism on the user's side. + +[source,c++] +---- +std::vector input; +boost::concurrent_flat_map m; + +... + +// process input in parallel +const int num_threads = 8; +std::vector threads; +std::size_t chunk = input.size() / num_threads; // how many elements per thread + +for (int i = 0; i < num_threads; ++i) { + threads.emplace_back([&,i] { + // calculate the portion of input this thread takes care of + std::size_t start = i * chunk; + std::size_t end = (i == num_threads - 1)? input.size(): (i + 1) * chunk; + + for (std::size_t n = start; n < end; ++n) { + m.emplace(input[n], calculation(input[n])); + } + }); +} +---- + +In the example above, threads access `m` without synchronization, just as we'd do in a +single-threaded scenario. In an ideal setting, if a given workload is distributed among +_N_ threads, execution is _N_ times faster than with one thread —this limit is +never attained in practice due to synchronization overheads and _contention_ (one thread +waiting for another to leave a locked portion of the map), but Boost.Unordered concurrent containers +are designed to perform with very little overhead and typically achieve _linear scaling_ +(that is, performance is proportional to the number of threads up to the number of +logical cores in the CPU). + +== Visitation-based API + +The first thing a new user of Boost.Unordered concurrent containers +will notice is that these classes _do not provide iterators_ (which makes them technically +not https://en.cppreference.com/w/cpp/named_req/Container[Containers^] +in the C++ standard sense). The reason for this is that iterators are inherently +thread-unsafe. Consider this hypothetical code: + +[source,c++] +---- +auto it = m.find(k); // A: get an iterator pointing to the element with key k +if (it != m.end() ) { + some_function(*it); // B: use the value of the element +} +---- + +In a multithreaded scenario, the iterator `it` may be invalid at point B if some other +thread issues an `m.erase(k)` operation between A and B. There are designs that +can remedy this by making iterators lock the element they point to, but this +approach lends itself to high contention and can easily produce deadlocks in a program. +`operator[]` has similar concurrency issues, and is not provided by +`boost::concurrent_flat_map`/`boost::concurrent_node_map` either. Instead, element access is done through +so-called _visitation functions_: + +[source,c++] +---- +m.visit(k, [](const auto& x) { // x is the element with key k (if it exists) + some_function(x); // use it +}); +---- + +The visitation function passed by the user (in this case, a lambda function) +is executed internally by Boost.Unordered in +a thread-safe manner, so it can access the element without worrying about other +threads interfering in the process. + +On the other hand, a visitation function can _not_ access the container itself: + +[source,c++] +---- +m.visit(k, [&](const auto& x) { + some_function(x, m.size()); // forbidden: m can't be accessed inside visitation +}); +---- + +Access to a different container is allowed, though: + +[source,c++] +---- +m.visit(k, [&](const auto& x) { + if (some_function(x)) { + m2.insert(x); // OK, m2 is a different boost::concurrent_flat_map + } +}); +---- + +But, in general, visitation functions should be as lightweight as possible to +reduce contention and increase parallelization. In some cases, moving heavy work +outside of visitation may be beneficial: + +[source,c++] +---- +std::optional o; +bool found = m.visit(k, [&](const auto& x) { + o = x; +}); +if (found) { + some_heavy_duty_function(*o); +} +---- + +Visitation is prominent in the API provided by concurrent containers, and +many classical operations have visitation-enabled variations: + +[source,c++] +---- +m.insert_or_visit(x, [](auto& y) { + // if insertion failed because of an equivalent element y, + // do something with it, for instance: + ++y.second; // increment the mapped part of the element +}); +---- + +Note that in this last example the visitation function could actually _modify_ +the element: as a general rule, operations on a concurrent map `m` +will grant visitation functions const/non-const access to the element depending on whether +`m` is const/non-const. Const access can be always be explicitly requested +by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result +in higher parallelization. For concurrent sets, on the other hand, +visitation is always const access. + +Although expected to be used much less frequently, concurrent containers +also provide insertion operations where an element can be visited right after +element creation (in addition to the usual visitation when an equivalent +element already exists): + +[source,c++] +---- + m.insert_and_cvisit(x, + [](const auto& y) { + std::cout<< "(" << y.first << ", " << y.second <<") inserted\n"; + }, + [](const auto& y) { + std::cout<< "(" << y.first << ", " << y.second << ") already exists\n"; + }); +---- + +Consult the references of +xref:#concurrent_node_set[`boost::concurrent_node_set`], +xref:#concurrent_flat_map[`boost::concurrent_node_map`], +xref:#concurrent_flat_set[`boost::concurrent_flat_set`] and +xref:#concurrent_flat_map[`boost::concurrent_flat_map`] +for the complete list of visitation-enabled operations. + +== Whole-Table Visitation + +In the absence of iterators, `visit_all` is provided +as an alternative way to process all the elements in the container: + +[source,c++] +---- +m.visit_all([](auto& x) { + x.second = 0; // reset the mapped part of the element +}); +---- + +In C++17 compilers implementing standard parallel algorithms, whole-table +visitation can be parallelized: + +[source,c++] +---- +m.visit_all(std::execution::par, [](auto& x) { // run in parallel + x.second = 0; // reset the mapped part of the element +}); +---- + +Traversal can be interrupted midway: + +[source,c++] +---- +// finds the key to a given (unique) value + +int key = 0; +int value = ...; +bool found = !m.visit_while([&](const auto& x) { + if(x.second == value) { + key = x.first; + return false; // finish + } + else { + return true; // keep on visiting + } +}); + +if(found) { ... } +---- + +There is one last whole-table visitation operation, `erase_if`: + +[source,c++] +---- +m.erase_if([](auto& x) { + return x.second == 0; // erase the elements whose mapped value is zero +}); +---- + +`visit_while` and `erase_if` can also be parallelized. Note that, in order to increase efficiency, +whole-table visitation operations do not block the table during execution: this implies that elements +may be inserted, modified or erased by other threads during visitation. It is +advisable not to assume too much about the exact global state of a concurrent container +at any point in your program. + +== Bulk visitation + +Suppose you have an `std::array` of keys you want to look up for in a concurrent map: + +[source,c++] +---- +std::array keys; +... +for(const auto& key: keys) { + m.visit(key, [](auto& x) { ++x.second; }); +} +---- + +_Bulk visitation_ allows us to pass all the keys in one operation: + +[source,c++] +---- +m.visit(keys.begin(), keys.end(), [](auto& x) { ++x.second; }); +---- + +This functionality is not provided for mere syntactic convenience, though: by processing all the +keys at once, some internal optimizations can be applied that increase +performance over the regular, one-at-a-time case (consult the +xref:#benchmarks_boostconcurrent_flat_map[benchmarks]). In fact, it may be beneficial +to buffer incoming keys so that they can be bulk visited in chunks: + +[source,c++] +---- +static constexpr auto bulk_visit_size = boost::concurrent_flat_map::bulk_visit_size; +std::array buffer; +std::size_t i=0; +while(...) { // processing loop + ... + buffer[i++] = k; + if(i == bulk_visit_size) { + map.visit(buffer.begin(), buffer.end(), [](auto& x) { ++x.second; }); + i = 0; + } + ... +} +// flush remaining keys +map.visit(buffer.begin(), buffer.begin() + i, [](auto& x) { ++x.second; }); +---- + +There's a latency/throughput tradeoff here: it will take longer for incoming keys to +be processed (since they are buffered), but the number of processed keys per second +is higher. `bulk_visit_size` is the recommended chunk size —smaller buffers +may yield worse performance. + +== Blocking Operations + +Concurrent containers can be copied, assigned, cleared and merged just like any other +Boost.Unordered container. Unlike most other operations, these are _blocking_, +that is, all other threads are prevented from accesing the tables involved while a copy, assignment, +clear or merge operation is in progress. Blocking is taken care of automatically by the library +and the user need not take any special precaution, but overall performance may be affected. + +Another blocking operation is _rehashing_, which happens explicitly via `rehash`/`reserve` +or during insertion when the table's load hits `max_load()`. As with non-concurrent containers, +reserving space in advance of bulk insertions will generally speed up the process. + +== Interoperability with non-concurrent containers + +As open-addressing and concurrent containers are based on the same internal data structure, +they can be efficiently move-constructed from their non-concurrent counterpart, and vice versa. + +[caption=, title='Table {counter:table-counter}. Concurrent/non-concurrent interoperatibility'] +[cols="1,1", frame=all, grid=all] +|=== +^|`boost::concurrent_node_set` +^|`boost::unordered_node_set` + +^|`boost::concurrent_node_map` +^|`boost::unordered_node_map` + +^|`boost::concurrent_flat_set` +^|`boost::unordered_flat_set` + +^|`boost::concurrent_flat_map` +^|`boost::unordered_flat_map` + +|=== + +This interoperability comes handy in multistage scenarios where parts of the data processing happen +in parallel whereas other steps are non-concurrent (or non-modifying). In the following example, +we want to construct a histogram from a huge input vector of words: +the population phase can be done in parallel with `boost::concurrent_flat_map` and results +then transferred to the final container. + +[source,c++] +---- +std::vector words = ...; + +// Insert words in parallel +boost::concurrent_flat_map m0; +std::for_each( + std::execution::par, words.begin(), words.end(), + [&](const auto& word) { + m0.try_emplace_or_visit(word, 1, [](auto& x) { ++x.second; }); + }); + +// Transfer to a regular unordered_flat_map +boost::unordered_flat_map m=std::move(m0); +---- diff --git a/doc/modules/ROOT/pages/copyright.adoc b/doc/modules/ROOT/pages/copyright.adoc new file mode 100644 index 00000000..dd03fe7c --- /dev/null +++ b/doc/modules/ROOT/pages/copyright.adoc @@ -0,0 +1,20 @@ +[#copyright] += Copyright and License + +:idprefix: copyright_ + +*Daniel James* + +Copyright (C) 2003, 2004 Jeremy B. Maitin-Shepard + +Copyright (C) 2005-2008 Daniel James + +Copyright (C) 2022-2023 Christian Mazakas + +Copyright (C) 2022-2024 Joaquín M López Muñoz + +Copyright (C) 2022-2023 Peter Dimov + +Copyright (C) 2024 Braden Ganetsky + +Distributed under the Boost Software License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) diff --git a/doc/modules/ROOT/pages/debuggability.adoc b/doc/modules/ROOT/pages/debuggability.adoc new file mode 100644 index 00000000..6e7e674f --- /dev/null +++ b/doc/modules/ROOT/pages/debuggability.adoc @@ -0,0 +1,90 @@ +[#debuggability] +:idprefix: debuggability_ + += Debuggability + +== Visual Studio Natvis + +All containers and iterators have custom visualizations in the Natvis framework. + +=== Using in your project + +To visualize Boost.Unordered containers in the Natvis framework in your project, simply add the file link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered.natvis[/extra/boost_unordered.natvis] to your Visual Studio project as an "Existing Item". + +=== Visualization structure + +The visualizations mirror those for the standard unordered containers. A container has a maximum of 100 elements displayed at once. Each set element has its item name listed as `[i]`, where `i` is the index in the display, starting at `0`. Each map element has its item name listed as `[\{key-display}]` by default. For example, if the first element is the pair `("abc", 1)`, the item name will be `["abc"]`. This behaviour can be overridden by using the view "ShowElementsByIndex", which switches the map display behaviour to name the elements by index. This same view name is used in the standard unordered containers. + +By default, the closed-addressing containers will show the `[hash_function]` and `[key_eq]`, the `[spare_hash_function]` and `[spare_key_eq]` if applicable, the `[allocator]`, and the elements. Using the view "detailed" adds the `[bucket_count]` and `[max_load_factor]`. Conversely, using the view "simple" shows only the elements, with no other items present. + +By default, the open-addressing containers will show the `[hash_function]`, `[key_eq]`, `[allocator]`, and the elements. Using the view "simple" shows only the elements, with no other items present. Both the SIMD and the non-SIMD implementations are viewable through the Natvis framework. + +Iterators are displayed similarly to their standard counterparts. An iterator is displayed as though it were the element that it points to. An end iterator is simply displayed as `{ end iterator }`. + +=== Fancy pointers + +The container visualizations also work if you are using fancy pointers in your allocator, such as `boost::interprocess::offset_ptr`. While this is rare, Boost.Unordered has natvis customization points to support any type of fancy pointer. `boost::interprocess::offset_ptr` has support already defined in the Boost.Interprocess library, and you can add support to your own type by following the instructions contained in a comment near the end of the file link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered.natvis[/extra/boost_unordered.natvis]. + +== GDB Pretty-Printers + +All containers and iterators have a custom GDB pretty-printer. + +=== Using in your project + +Always, when using pretty-printers, you must enable pretty-printing like below. This is typically a one-time setup. + +```plaintext +(gdb) set print pretty on +``` + +By default, if you compile into an ELF binary format, your binary will contain the Boost.Unordered pretty-printers. To use the embedded pretty-printers, ensure you allow auto-loading like below. This must be done every time you load GDB, or add it to a ".gdbinit" file. + +```plaintext +(gdb) add-auto-load-safe-path [/path/to/executable] +``` + +You can choose to compile your binary _without_ embedding the pretty-printers by defining `BOOST_ALL_NO_EMBEDDED_GDB_SCRIPTS`, which disables the embedded GDB pretty-printers for all Boost libraries that have this feature. + +You can load the pretty-printers externally from the non-embedded Python script. Add the script, link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered_printers.py[/extra/boost_unordered_printers.py], using the `source` command as shown below. + +```plaintext +(gdb) source [/path/to/boost]/libs/unordered/extra/boost_unordered_printers.py +``` + +=== Visualization structure + +The visualizations mirror the standard unordered containers. The map containers display an association from key to mapped value. The set containers display an association from index to value. An iterator is either displayed with its item, or as an end iterator. Here is what may be shown for an example `boost::unordered_map`, an example `boost::unordered_set`, and their respective begin and end iterators. + +```plaintext +(gdb) print example_unordered_map +$1 = boost::unordered_map with 3 elements = {["C"] = "c", ["B"] = "b", ["A"] = "a"} +(gdb) print example_unordered_map_begin +$2 = iterator = { {first = "C", second = "c"} } +(gdb) print example_unordered_map_end +$3 = iterator = { end iterator } +(gdb) print example_unordered_set +$4 = boost::unordered_set with 3 elements = {[0] = "c", [1] = "b", [2] = "a"} +(gdb) print example_unordered_set_begin +$5 = iterator = { "c" } +(gdb) print example_unordered_set_end +$6 = iterator = { end iterator } +``` + +The other containers are identical other than replacing "`boost::unordered_{map|set}`" with the appropriate template name when displaying the container itself. Note that each sub-element (i.e. the key, the mapped value, or the value) is displayed based on its own printing settings which may include its own pretty-printer. + +Both the SIMD and the non-SIMD implementations are viewable through the GDB pretty-printers. + +For open-addressing containers where xref:#hash_quality_container_statistics[container statistics] are enabled, you can obtain these statistics by calling `get_stats()` on the container, from within GDB. This is overridden in GDB as an link:https://sourceware.org/gdb/current/onlinedocs/gdb.html/Xmethod-API.html[xmethod], so it will not invoke any C++ synchronization code. See the following printout as an example for the expected format. + +```plaintext +(gdb) print example_flat_map.get_stats() +$1 = [stats] = {[insertion] = {[count] = 5, [probe_length] = {avg = 1.0, var = 0.0, dev = 0.0}}, + [successful_lookup] = {[count] = 0, [probe_length] = {avg = 0.0, var = 0.0, dev = 0.0}, + [num_comparisons] = {avg = 0.0, var = 0.0, dev = 0.0}}, [unsuccessful_lookup] = {[count] = 5, + [probe_length] = {avg = 1.0, var = 0.0, dev = 0.0}, + [num_comparisons] = {avg = 0.0, var = 0.0, dev = 0.0}}} +``` + +=== Fancy pointers + +The pretty-printers also work if you are using fancy pointers in your allocator, such as `boost::interprocess::offset_ptr`. While this is rare, Boost.Unordered has GDB pretty-printer customization points to support any type of fancy pointer. `boost::interprocess::offset_ptr` has support already defined in the Boost.Interprocess library, and you can add support to your own type by following the instructions contained in a comment near the end of the file link:https://github.com/boostorg/unordered/blob/develop/extra/boost_unordered_printers.py[/extra/boost_unordered_printers.py]. diff --git a/doc/modules/ROOT/pages/hash_equality.adoc b/doc/modules/ROOT/pages/hash_equality.adoc new file mode 100644 index 00000000..065c03a2 --- /dev/null +++ b/doc/modules/ROOT/pages/hash_equality.adoc @@ -0,0 +1,149 @@ +[#hash_equality] + +:idprefix: hash_equality_ + += Equality Predicates and Hash Functions + +While the associative containers use an ordering relation to specify how the +elements are stored, the unordered associative containers use an equality +predicate and a hash function. For example, <> +is declared as: + +```cpp +template < + class Key, class Mapped, + class Hash = boost::hash, + class Pred = std::equal_to, + class Alloc = std::allocator > > +class unordered_map; +``` + +The hash function comes first as you might want to change the hash function +but not the equality predicate. For example, if you wanted to use the +https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash[FNV-1a hash^] you could write: + +```cpp +boost::unordered_map + dictionary; +``` + +There is an link:../../examples/fnv1.hpp[implementation of FNV-1a^] in the examples directory. + +If you wish to use a different equality function, you will also need to use a matching hash function. For example, to implement a case insensitive dictionary you need to define a case insensitive equality predicate and hash function: + +```cpp +struct iequal_to +{ + bool operator()(std::string const& x, + std::string const& y) const + { + return boost::algorithm::iequals(x, y, std::locale()); + } +}; + +struct ihash +{ + std::size_t operator()(std::string const& x) const + { + std::size_t seed = 0; + std::locale locale; + + for(std::string::const_iterator it = x.begin(); + it != x.end(); ++it) + { + boost::hash_combine(seed, std::toupper(*it, locale)); + } + + return seed; + } +}; +``` + +Which you can then use in a case insensitive dictionary: +```cpp +boost::unordered_map + idictionary; +``` + +This is a simplified version of the example at +link:../../examples/case_insensitive.hpp[/libs/unordered/examples/case_insensitive.hpp^] which supports other locales and string types. + +CAUTION: Be careful when using the equality (`==`) operator with custom equality +predicates, especially if you're using a function pointer. If you compare two +containers with different equality predicates then the result is undefined. +For most stateless function objects this is impossible - since you can only +compare objects with the same equality predicate you know the equality +predicates must be equal. But if you're using function pointers or a stateful +equality predicate (e.g. `boost::function`) then you can get into trouble. + +== Custom Types + +Similarly, a custom hash function can be used for custom types: + +```cpp +struct point { + int x; + int y; +}; + +bool operator==(point const& p1, point const& p2) +{ + return p1.x == p2.x && p1.y == p2.y; +} + +struct point_hash +{ + std::size_t operator()(point const& p) const + { + std::size_t seed = 0; + boost::hash_combine(seed, p.x); + boost::hash_combine(seed, p.y); + return seed; + } +}; + +boost::unordered_multiset points; +``` + +Since the default hash function is link:../../../container_hash/index.html[Boost.Hash^], +we can extend it to support the type so that the hash function doesn't need to be explicitly given: + +```cpp +struct point { + int x; + int y; +}; + +bool operator==(point const& p1, point const& p2) +{ + return p1.x == p2.x && p1.y == p2.y; +} + +std::size_t hash_value(point const& p) { + std::size_t seed = 0; + boost::hash_combine(seed, p.x); + boost::hash_combine(seed, p.y); + return seed; +} + +// Now the default function objects work. +boost::unordered_multiset points; +``` + +See the link:../../../container_hash/index.html[Boost.Hash documentation^] for more detail on how to +do this. Remember that it relies on extensions to the standard - so it +won't work for other implementations of the unordered associative containers, +you'll need to explicitly use Boost.Hash. + +[caption=, title='Table {counter:table-counter} Methods for accessing the hash and equality functions'] +[cols="1,.^1", frame=all, grid=rows] +|=== +|Method |Description + +|`hasher hash_function() const` +|Returns the container's hash function. + +|`key_equal key_eq() const` +|Returns the container's key equality function.. + +|=== diff --git a/doc/modules/ROOT/pages/hash_quality.adoc b/doc/modules/ROOT/pages/hash_quality.adoc new file mode 100644 index 00000000..828e9421 --- /dev/null +++ b/doc/modules/ROOT/pages/hash_quality.adoc @@ -0,0 +1,145 @@ +[#hash_quality] += Hash Quality + +:idprefix: hash_quality_ + +In order to work properly, hash tables require that the supplied hash function +be of __good quality__, roughly meaning that it uses its `std::size_t` output +space as uniformly as possible, much like a random number generator would do +—except, of course, that the value of a hash function is not random but strictly determined +by its input argument. + +Closed-addressing containers in Boost.Unordered are fairly robust against +hash functions with less-than-ideal quality, but open-addressing and concurrent +containers are much more sensitive to this factor, and their performance can +degrade dramatically if the hash function is not appropriate. In general, if +you're using functions provided by or generated with link:../../../container_hash/index.html[Boost.Hash^], +the quality will be adequate, but you have to be careful when using alternative +hash algorithms. + +The rest of this section applies only to open-addressing and concurrent containers. + +== Hash Post-mixing and the Avalanching Property + +Even if your supplied hash function does not conform to the uniform behavior +required by open addressing, chances are that +the performance of Boost.Unordered containers will be acceptable, because the library +executes an internal __post-mixing__ step that improves the statistical +properties of the calculated hash values. This comes with an extra computational +cost; if you'd like to opt out of post-mixing, annotate your hash function as +follows: + +[source,c++] +---- +struct my_string_hash_function +{ + using is_avalanching = std::true_type; // instruct Boost.Unordered to not use post-mixing + + std::size_t operator()(const std::string& x) const + { + ... + } +}; +---- + +By setting the +xref:#hash_traits_hash_is_avalanching[hash_is_avalanching] trait, we inform Boost.Unordered +that `my_string_hash_function` is of sufficient quality to be used directly without +any post-mixing safety net. This comes at the risk of degraded performance in the +cases where the hash function is not as well-behaved as we've declared. + +== Container Statistics + +If we globally define the macro `BOOST_UNORDERED_ENABLE_STATS`, open-addressing and +concurrent containers will calculate some internal statistics directly correlated to the +quality of the hash function: + +[source,c++] +---- +#define BOOST_UNORDERED_ENABLE_STATS +#include + +... + +int main() +{ + boost::unordered_flat_map m; + ... // use m + + auto stats = m.get_stats(); + ... // inspect stats +} +---- + +The `stats` object provides the following information: + +[source,subs=+quotes] +---- +stats + .insertion // *Insertion operations* + .count // Number of operations + .probe_length // Probe length per operation + .average + .variance + .deviation + .successful_lookup // *Lookup operations (element found)* + .count // Number of operations + .probe_length // Probe length per operation + .average + .variance + .deviation + .num_comparisons // Elements compared per operation + .average + .variance + .deviation + .unsuccessful_lookup // *Lookup operations (element not found)* + .count // Number of operations + .probe_length // Probe length per operation + .average + .variance + .deviation + .num_comparisons // Elements compared per operation + .average + .variance + .deviation +---- + +Statistics for three internal operations are maintained: insertions (without considering +the previous lookup to determine that the key is not present yet), successful lookups, +and unsuccessful lookups (including those issued internally when inserting elements). +_Probe length_ is the number of +xref:#structures_open_addressing_containers[bucket groups] accessed per operation. +If the hash function behaves properly: + +* Average probe lengths should be close to 1.0. +* The average number of comparisons per successful lookup should be close to 1.0 (that is, +just the element found is checked). +* The average number of comparisons per unsuccessful lookup should be close to 0.0. + +An link:../../benchmark/string_stats.cpp[example^] is provided that displays container +statistics for `boost::hash`, an implementation of the +https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash[FNV-1a hash^] +and two ill-behaved custom hash functions that have been incorrectly marked as avalanching: + +[listing] +---- + boost::unordered_flat_map: 319 ms + insertion: probe length 1.08771 + successful lookup: probe length 1.06206, num comparisons 1.02121 + unsuccessful lookup: probe length 1.12301, num comparisons 0.0388251 + + boost::unordered_flat_map, FNV-1a: 301 ms + insertion: probe length 1.09567 + successful lookup: probe length 1.06202, num comparisons 1.0227 + unsuccessful lookup: probe length 1.12195, num comparisons 0.040527 + +boost::unordered_flat_map, slightly_bad_hash: 654 ms + insertion: probe length 1.03443 + successful lookup: probe length 1.04137, num comparisons 6.22152 + unsuccessful lookup: probe length 1.29334, num comparisons 11.0335 + + boost::unordered_flat_map, bad_hash: 12216 ms + insertion: probe length 699.218 + successful lookup: probe length 590.183, num comparisons 43.4886 + unsuccessful lookup: probe length 1361.65, num comparisons 75.238 +---- diff --git a/doc/modules/ROOT/pages/index.adoc b/doc/modules/ROOT/pages/index.adoc new file mode 100644 index 00000000..c90a7741 --- /dev/null +++ b/doc/modules/ROOT/pages/index.adoc @@ -0,0 +1,12 @@ += Boost.Unordered + +:toc: left +:toclevels: 3 +:idprefix: +:docinfo: private-footer +:source-highlighter: rouge +:source-language: c++ +:nofooter: +:sectlinks: + +:leveloffset: +1 diff --git a/doc/modules/ROOT/pages/intro.adoc b/doc/modules/ROOT/pages/intro.adoc new file mode 100644 index 00000000..e6728c04 --- /dev/null +++ b/doc/modules/ROOT/pages/intro.adoc @@ -0,0 +1,100 @@ +[#intro] += Introduction + +:idprefix: intro_ +:cpp: C++ + +link:https://en.wikipedia.org/wiki/Hash_table[Hash tables^] are extremely popular +computer data structures and can be found under one form or another in virtually any programming +language. Whereas other associative structures such as rb-trees (used in {cpp} by `std::set` and `std::map`) +have logarithmic-time complexity for insertion and lookup, hash tables, if configured properly, +perform these operations in constant time on average, and are generally much faster. + +{cpp} introduced __unordered associative containers__ `std::unordered_set`, `std::unordered_map`, +`std::unordered_multiset` and `std::unordered_multimap` in {cpp}11, but research on hash tables +hasn't stopped since: advances in CPU architectures such as +more powerful caches, link:https://en.wikipedia.org/wiki/Single_instruction,_multiple_data[SIMD] operations +and increasingly available link:https://en.wikipedia.org/wiki/Multi-core_processor[multicore processors] +open up possibilities for improved hash-based data structures and new use cases that +are simply beyond reach of unordered associative containers as specified in 2011. + +Boost.Unordered offers a catalog of hash containers with different standards compliance levels, +performances and intented usage scenarios: + +[caption=, title='Table {counter:table-counter}. Boost.Unordered containers'] +[cols="1,1,.^1", frame=all, grid=all] +|=== +^h| +^h|*Node-based* +^h|*Flat* + +^.^h|*Closed addressing* +^m| +boost::unordered_set + +boost::unordered_map + +boost::unordered_multiset + +boost::unordered_multimap +^| + +^.^h|*Open addressing* +^m| boost::unordered_node_set + +boost::unordered_node_map +^m| boost::unordered_flat_set + +boost::unordered_flat_map + +^.^h|*Concurrent* +^| `boost::concurrent_node_set` + +`boost::concurrent_node_map` +^| `boost::concurrent_flat_set` + +`boost::concurrent_flat_map` + +|=== + +* **Closed-addressing containers** are fully compliant with the C++ specification +for unordered associative containers and feature one of the fastest implementations +in the market within the technical constraints imposed by the required standard interface. +* **Open-addressing containers** rely on much faster data structures and algorithms +(more than 2 times faster in typical scenarios) while slightly diverging from the standard +interface to accommodate the implementation. +There are two variants: **flat** (the fastest) and **node-based**, which +provide pointer stability under rehashing at the expense of being slower. +* Finally, **concurrent containers** are designed and implemented to be used in high-performance +multithreaded scenarios. Their interface is radically different from that of regular C++ containers. +Flat and node-based variants are provided. + +All sets and maps in Boost.Unordered are instantiatied similarly as +`std::unordered_set` and `std::unordered_map`, respectively: + +[source,c++] +---- +namespace boost { + template < + class Key, + class Hash = boost::hash, + class Pred = std::equal_to, + class Alloc = std::allocator > + class unordered_set; + // same for unordered_multiset, unordered_flat_set, unordered_node_set, + // concurrent_flat_set and concurrent_node_set + + template < + class Key, class Mapped, + class Hash = boost::hash, + class Pred = std::equal_to, + class Alloc = std::allocator > > + class unordered_map; + // same for unordered_multimap, unordered_flat_map, unordered_node_map, + // concurrent_flat_map and concurrent_node_map +} +---- + +Storing an object in an unordered associative container requires both a +key equality function and a hash function. The default function objects in +the standard containers support a few basic types including integer types, +floating point types, pointer types, and the standard strings. Since +Boost.Unordered uses link:../../../container_hash/index.html[boost::hash^] it also supports some other types, +including standard containers. To use any types not supported by these methods +you have to extend Boost.Hash to support the type or use +your own custom equality predicates and hash functions. See the +<> section +for more details. diff --git a/doc/modules/ROOT/pages/rationale.adoc b/doc/modules/ROOT/pages/rationale.adoc new file mode 100644 index 00000000..29df32f0 --- /dev/null +++ b/doc/modules/ROOT/pages/rationale.adoc @@ -0,0 +1,143 @@ +[#rationale] + +:idprefix: rationale_ + += Implementation Rationale + +== Closed-addressing Containers + +`boost::unordered_[multi]set` and `boost::unordered_[multi]map` +adhere to the standard requirements for unordered associative +containers, so the interface was fixed. But there are +still some implementation decisions to make. The priorities are +conformance to the standard and portability. + +The http://en.wikipedia.org/wiki/Hash_table[Wikipedia article on hash tables^] +has a good summary of the implementation issues for hash tables in general. + +=== Data Structure + +By specifying an interface for accessing the buckets of the container the +standard pretty much requires that the hash table uses closed addressing. + +It would be conceivable to write a hash table that uses another method. For +example, it could use open addressing, and use the lookup chain to act as a +bucket but there are some serious problems with this: + +* The standard requires that pointers to elements aren't invalidated, so + the elements can't be stored in one array, but will need a layer of + indirection instead - losing the efficiency and most of the memory gain, + the main advantages of open addressing. +* Local iterators would be very inefficient and may not be able to + meet the complexity requirements. +* There are also the restrictions on when iterators can be invalidated. Since + open addressing degrades badly when there are a high number of collisions the + restrictions could prevent a rehash when it's really needed. The maximum load + factor could be set to a fairly low value to work around this - but the + standard requires that it is initially set to 1.0. +* And since the standard is written with a eye towards closed + addressing, users will be surprised if the performance doesn't reflect that. + +So closed addressing is used. + +=== Number of Buckets + +There are two popular methods for choosing the number of buckets in a hash +table. One is to have a prime number of buckets, another is to use a power +of 2. + +Using a prime number of buckets, and choosing a bucket by using the modulus +of the hash function's result will usually give a good result. The downside +is that the required modulus operation is fairly expensive. This is what the +containers used to do in most cases. + +Using a power of 2 allows for much quicker selection of the bucket to use, +but at the expense of losing the upper bits of the hash value. For some +specially designed hash functions it is possible to do this and still get a +good result but as the containers can take arbitrary hash functions this can't +be relied on. + +To avoid this a transformation could be applied to the hash function, for an +example see +http://web.archive.org/web/20121102023700/http://www.concentric.net/~Ttwang/tech/inthash.htm[Thomas Wang's article on integer hash functions^]. +Unfortunately, a transformation like Wang's requires knowledge of the number +of bits in the hash value, so it was only used when `size_t` was 64 bit. + +Since release 1.79.0, https://en.wikipedia.org/wiki/Hash_function#Fibonacci_hashing[Fibonacci hashing] +is used instead. With this implementation, the bucket number is determined +by using `(h * m) >> (w - k)`, where `h` is the hash value, `m` is `2^w` divided +by the golden ratio, `w` is the word size (32 or 64), and `2^k` is the +number of buckets. This provides a good compromise between speed and +distribution. + +Since release 1.80.0, prime numbers are chosen for the number of buckets in +tandem with sophisticated modulo arithmetic. This removes the need for "mixing" +the result of the user's hash function as was used for release 1.79.0. + +== Open-addresing Containers + +The C++ standard specification of unordered associative containers impose +severe limitations on permissible implementations, the most important being +that closed addressing is implicitly assumed. Slightly relaxing this specification +opens up the possibility of providing container variations taking full +advantage of open-addressing techniques. + +The design of `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` has been +guided by Peter Dimov's https://pdimov.github.io/articles/unordered_dev_plan.html[Development Plan for Boost.Unordered^]. +We discuss here the most relevant principles. + +=== Hash Function + +Given its rich functionality and cross-platform interoperability, +`boost::hash` remains the default hash function of open-addressing containers. +As it happens, `boost::hash` for integral and other basic types does not possess +the statistical properties required by open addressing; to cope with this, +we implement a post-mixing stage: + +{nbsp}{nbsp}{nbsp}{nbsp} _a_ <- _h_ *mulx* _C_, + +{nbsp}{nbsp}{nbsp}{nbsp} _h_ <- *high*(_a_) *xor* *low*(_a_), + +where *mulx* is an _extended multiplication_ (128 bits in 64-bit architectures, 64 bits in 32-bit environments), +and *high* and *low* are the upper and lower halves of an extended word, respectively. +In 64-bit architectures, _C_ is the integer part of 2^64^∕https://en.wikipedia.org/wiki/Golden_ratio[_φ_], +whereas in 32 bits _C_ = 0xE817FB2Du has been obtained from https://arxiv.org/abs/2001.05304[Steele and Vigna (2021)^]. + +When using a hash function directly suitable for open addressing, post-mixing can be opted out of via a dedicated <>trait. +`boost::hash` specializations for string types are marked as avalanching. + +=== Platform Interoperability + +The observable behavior of `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` is deterministically +identical across different compilers as long as their ``std::size_t``s are the same size and the user-provided +hash function and equality predicate are also interoperable +—this includes elements being ordered in exactly the same way for the same sequence of +operations. + +Although the implementation internally uses SIMD technologies, such as https://en.wikipedia.org/wiki/SSE2[SSE2^] +and https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(NEON)[Neon^], when available, +this does not affect interoperatility. For instance, the behavior is the same +for Visual Studio on an x64-mode Intel CPU with SSE2 and for GCC on an IBM s390x without any supported SIMD technology. + +== Concurrent Containers + +The same data structure used by Boost.Unordered open-addressing containers has been chosen +also as the foundation of `boost::concurrent_flat_set`/`boost::concurrent_node_set` and +`boost::concurrent_flat_map`/`boost::concurrent_node_map`: + +* Open-addressing is faster than closed-addressing alternatives, both in non-concurrent and +concurrent scenarios. +* Open-addressing layouts are eminently suitable for concurrent access and modification +with minimal locking. In particular, the metadata array can be used for implementations of +lookup that are lock-free up to the last step of actual element comparison. +* Layout compatibility with Boost.Unordered flat containers allows for +xref:#concurrent_interoperability_with_non_concurrent_containers[fast transfer] +of all elements between a concurrent container and its non-concurrent counterpart, +and vice versa. + +=== Hash Function and Platform Interoperability + +Concurrent containers make the same decisions and provide the same guarantees +as Boost.Unordered open-addressing containers with regards to +xref:#rationale_hash_function[hash function defaults] and +xref:#rationale_platform_interoperability[platform interoperability]. + diff --git a/doc/modules/ROOT/pages/ref.adoc b/doc/modules/ROOT/pages/ref.adoc new file mode 100644 index 00000000..c6f65ce9 --- /dev/null +++ b/doc/modules/ROOT/pages/ref.adoc @@ -0,0 +1,17 @@ +[#reference] += Reference + +* xref:reference/unordered_map.adoc[unordered_map] +* xref:reference/unordered_multimap.adoc[unordered_multimap] +* xref:reference/unordered_set.adoc[unordered_set] +* xref:reference/unordered_multiset.adoc[unordered_multiset] +* xref:reference/hash_traits.adoc[hash_traits] +* xref:reference/stats.adoc[stats] +* xref:reference/unordered_flat_map.adoc[unordered_flat_map] +* xref:reference/unordered_flat_set.adoc[unordered_flat_set] +* xref:reference/unordered_node_map.adoc[unordered_node_map] +* xref:reference/unordered_node_set.adoc[unordered_node_set] +* xref:reference/concurrent_flat_map.adoc[concurrent_flat_map] +* xref:reference/concurrent_flat_set.adoc[concurrent_flat_set] +* xref:reference/concurrent_node_map.adoc[concurrent_node_map] +* xref:reference/concurrent_node_set.adoc[concurrent_node_set] diff --git a/doc/modules/ROOT/pages/reference/concurrent.adoc b/doc/modules/ROOT/pages/reference/concurrent.adoc new file mode 100644 index 00000000..75fd7922 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/concurrent.adoc @@ -0,0 +1,320 @@ +[#concurrent] += Concurrent Containers + +:idprefix: concurrent_ + +Boost.Unordered provides `boost::concurrent_node_set`, `boost::concurrent_node_map`, +`boost::concurrent_flat_set` and `boost::concurrent_flat_map`, +hash tables that allow concurrent write/read access from +different threads without having to implement any synchronzation mechanism on the user's side. + +[source,c++] +---- +std::vector input; +boost::concurrent_flat_map m; + +... + +// process input in parallel +const int num_threads = 8; +std::vector threads; +std::size_t chunk = input.size() / num_threads; // how many elements per thread + +for (int i = 0; i < num_threads; ++i) { + threads.emplace_back([&,i] { + // calculate the portion of input this thread takes care of + std::size_t start = i * chunk; + std::size_t end = (i == num_threads - 1)? input.size(): (i + 1) * chunk; + + for (std::size_t n = start; n < end; ++n) { + m.emplace(input[n], calculation(input[n])); + } + }); +} +---- + +In the example above, threads access `m` without synchronization, just as we'd do in a +single-threaded scenario. In an ideal setting, if a given workload is distributed among +_N_ threads, execution is _N_ times faster than with one thread —this limit is +never attained in practice due to synchronization overheads and _contention_ (one thread +waiting for another to leave a locked portion of the map), but Boost.Unordered concurrent containers +are designed to perform with very little overhead and typically achieve _linear scaling_ +(that is, performance is proportional to the number of threads up to the number of +logical cores in the CPU). + +== Visitation-based API + +The first thing a new user of Boost.Unordered concurrent containers +will notice is that these classes _do not provide iterators_ (which makes them technically +not https://en.cppreference.com/w/cpp/named_req/Container[Containers^] +in the C++ standard sense). The reason for this is that iterators are inherently +thread-unsafe. Consider this hypothetical code: + +[source,c++] +---- +auto it = m.find(k); // A: get an iterator pointing to the element with key k +if (it != m.end() ) { + some_function(*it); // B: use the value of the element +} +---- + +In a multithreaded scenario, the iterator `it` may be invalid at point B if some other +thread issues an `m.erase(k)` operation between A and B. There are designs that +can remedy this by making iterators lock the element they point to, but this +approach lends itself to high contention and can easily produce deadlocks in a program. +`operator[]` has similar concurrency issues, and is not provided by +`boost::concurrent_flat_map`/`boost::concurrent_node_map` either. Instead, element access is done through +so-called _visitation functions_: + +[source,c++] +---- +m.visit(k, [](const auto& x) { // x is the element with key k (if it exists) + some_function(x); // use it +}); +---- + +The visitation function passed by the user (in this case, a lambda function) +is executed internally by Boost.Unordered in +a thread-safe manner, so it can access the element without worrying about other +threads interfering in the process. + +On the other hand, a visitation function can _not_ access the container itself: + +[source,c++] +---- +m.visit(k, [&](const auto& x) { + some_function(x, m.size()); // forbidden: m can't be accessed inside visitation +}); +---- + +Access to a different container is allowed, though: + +[source,c++] +---- +m.visit(k, [&](const auto& x) { + if (some_function(x)) { + m2.insert(x); // OK, m2 is a different boost::concurrent_flat_map + } +}); +---- + +But, in general, visitation functions should be as lightweight as possible to +reduce contention and increase parallelization. In some cases, moving heavy work +outside of visitation may be beneficial: + +[source,c++] +---- +std::optional o; +bool found = m.visit(k, [&](const auto& x) { + o = x; +}); +if (found) { + some_heavy_duty_function(*o); +} +---- + +Visitation is prominent in the API provided by concurrent containers, and +many classical operations have visitation-enabled variations: + +[source,c++] +---- +m.insert_or_visit(x, [](auto& y) { + // if insertion failed because of an equivalent element y, + // do something with it, for instance: + ++y.second; // increment the mapped part of the element +}); +---- + +Note that in this last example the visitation function could actually _modify_ +the element: as a general rule, operations on a concurrent map `m` +will grant visitation functions const/non-const access to the element depending on whether +`m` is const/non-const. Const access can be always be explicitly requested +by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result +in higher parallelization. For concurrent sets, on the other hand, +visitation is always const access. + +Although expected to be used much less frequently, concurrent containers +also provide insertion operations where an element can be visited right after +element creation (in addition to the usual visitation when an equivalent +element already exists): + +[source,c++] +---- + m.insert_and_cvisit(x, + [](const auto& y) { + std::cout<< "(" << y.first << ", " << y.second <<") inserted\n"; + }, + [](const auto& y) { + std::cout<< "(" << y.first << ", " << y.second << ") already exists\n"; + }); +---- + +Consult the references of +xref:#concurrent_node_set[`boost::concurrent_node_set`], +xref:#concurrent_flat_map[`boost::concurrent_node_map`], +xref:#concurrent_flat_set[`boost::concurrent_flat_set`] and +xref:#concurrent_flat_map[`boost::concurrent_flat_map`] +for the complete list of visitation-enabled operations. + +== Whole-Table Visitation + +In the absence of iterators, `visit_all` is provided +as an alternative way to process all the elements in the container: + +[source,c++] +---- +m.visit_all([](auto& x) { + x.second = 0; // reset the mapped part of the element +}); +---- + +In C++17 compilers implementing standard parallel algorithms, whole-table +visitation can be parallelized: + +[source,c++] +---- +m.visit_all(std::execution::par, [](auto& x) { // run in parallel + x.second = 0; // reset the mapped part of the element +}); +---- + +Traversal can be interrupted midway: + +[source,c++] +---- +// finds the key to a given (unique) value + +int key = 0; +int value = ...; +bool found = !m.visit_while([&](const auto& x) { + if(x.second == value) { + key = x.first; + return false; // finish + } + else { + return true; // keep on visiting + } +}); + +if(found) { ... } +---- + +There is one last whole-table visitation operation, `erase_if`: + +[source,c++] +---- +m.erase_if([](auto& x) { + return x.second == 0; // erase the elements whose mapped value is zero +}); +---- + +`visit_while` and `erase_if` can also be parallelized. Note that, in order to increase efficiency, +whole-table visitation operations do not block the table during execution: this implies that elements +may be inserted, modified or erased by other threads during visitation. It is +advisable not to assume too much about the exact global state of a concurrent container +at any point in your program. + +== Bulk visitation + +Suppose you have an `std::array` of keys you want to look up for in a concurrent map: + +[source,c++] +---- +std::array keys; +... +for(const auto& key: keys) { + m.visit(key, [](auto& x) { ++x.second; }); +} +---- + +_Bulk visitation_ allows us to pass all the keys in one operation: + +[source,c++] +---- +m.visit(keys.begin(), keys.end(), [](auto& x) { ++x.second; }); +---- + +This functionality is not provided for mere syntactic convenience, though: by processing all the +keys at once, some internal optimizations can be applied that increase +performance over the regular, one-at-a-time case (consult the +xref:#benchmarks_boostconcurrent_flat_map[benchmarks]). In fact, it may be beneficial +to buffer incoming keys so that they can be bulk visited in chunks: + +[source,c++] +---- +static constexpr auto bulk_visit_size = boost::concurrent_flat_map::bulk_visit_size; +std::array buffer; +std::size_t i=0; +while(...) { // processing loop + ... + buffer[i++] = k; + if(i == bulk_visit_size) { + map.visit(buffer.begin(), buffer.end(), [](auto& x) { ++x.second; }); + i = 0; + } + ... +} +// flush remaining keys +map.visit(buffer.begin(), buffer.begin() + i, [](auto& x) { ++x.second; }); +---- + +There's a latency/throughput tradeoff here: it will take longer for incoming keys to +be processed (since they are buffered), but the number of processed keys per second +is higher. `bulk_visit_size` is the recommended chunk size —smaller buffers +may yield worse performance. + +== Blocking Operations + +Concurrent containers can be copied, assigned, cleared and merged just like any other +Boost.Unordered container. Unlike most other operations, these are _blocking_, +that is, all other threads are prevented from accesing the tables involved while a copy, assignment, +clear or merge operation is in progress. Blocking is taken care of automatically by the library +and the user need not take any special precaution, but overall performance may be affected. + +Another blocking operation is _rehashing_, which happens explicitly via `rehash`/`reserve` +or during insertion when the table's load hits `max_load()`. As with non-concurrent containers, +reserving space in advance of bulk insertions will generally speed up the process. + +== Interoperability with non-concurrent containers + +As open-addressing and concurrent containers are based on the same internal data structure, +they can be efficiently move-constructed from their non-concurrent counterpart, and vice versa. + +[caption=, title='Table {counter:table-counter}. Concurrent/non-concurrent interoperatibility'] +[cols="1,1", frame=all, grid=all] +|=== +^|`boost::concurrent_node_set` +^|`boost::unordered_node_set` + +^|`boost::concurrent_node_map` +^|`boost::unordered_node_map` + +^|`boost::concurrent_flat_set` +^|`boost::unordered_flat_set` + +^|`boost::concurrent_flat_map` +^|`boost::unordered_flat_map` + +|=== + +This interoperability comes handy in multistage scenarios where parts of the data processing happen +in parallel whereas other steps are non-concurrent (or non-modifying). In the following example, +we want to construct a histogram from a huge input vector of words: +the population phase can be done in parallel with `boost::concurrent_flat_map` and results +then transferred to the final container. + +[source,c++] +---- +std::vector words = ...; + +// Insert words in parallel +boost::concurrent_flat_map m0; +std::for_each( + std::execution::par, words.begin(), words.end(), + [&](const auto& word) { + m0.try_emplace_or_visit(word, 1, [](auto& x) { ++x.second; }); + }); + +// Transfer to a regular unordered_flat_map +boost::unordered_flat_map m=std::move(m0); +---- diff --git a/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc b/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc new file mode 100644 index 00000000..8abc740c --- /dev/null +++ b/doc/modules/ROOT/pages/reference/concurrent_flat_map.adoc @@ -0,0 +1,1860 @@ +[#concurrent_flat_map] +== Class Template concurrent_flat_map + +:idprefix: concurrent_flat_map_ + +`boost::concurrent_flat_map` — A hash table that associates unique keys with another value and +allows for concurrent element insertion, erasure, lookup and access +without external synchronization mechanisms. + +Even though it acts as a container, `boost::concurrent_flat_map` +does not model the standard C++ https://en.cppreference.com/w/cpp/named_req/Container[Container^] concept. +In particular, iterators and associated operations (`begin`, `end`, etc.) are not provided. +Element access and modification are done through user-provided _visitation functions_ that are passed +to `concurrent_flat_map` operations where they are executed internally in a controlled fashion. +Such visitation-based API allows for low-contention concurrent usage scenarios. + +The internal data structure of `boost::concurrent_flat_map` is similar to that of +`boost::unordered_flat_map`. As a result of its using open-addressing techniques, +`value_type` must be move-constructible and pointer stability is not kept under rehashing. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + class concurrent_flat_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using init_type = std::pair< + typename std::remove_const::type, + typename std::remove_const::type + >; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:concurrent_flat_map_boost_unordered_enable_stats[enabled] + + // constants + static constexpr size_type xref:#concurrent_flat_map_constants[bulk_visit_size] = _implementation-defined_; + + // construct/copy/destroy + xref:#concurrent_flat_map_default_constructor[concurrent_flat_map](); + explicit xref:#concurrent_flat_map_bucket_count_constructor[concurrent_flat_map](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#concurrent_flat_map_iterator_range_constructor[concurrent_flat_map](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_flat_map_copy_constructor[concurrent_flat_map](const concurrent_flat_map& other); + xref:#concurrent_flat_map_move_constructor[concurrent_flat_map](concurrent_flat_map&& other); + template + xref:#concurrent_flat_map_iterator_range_constructor_with_allocator[concurrent_flat_map](InputIterator f, InputIterator l,const allocator_type& a); + explicit xref:#concurrent_flat_map_allocator_constructor[concurrent_flat_map](const Allocator& a); + xref:#concurrent_flat_map_copy_constructor_with_allocator[concurrent_flat_map](const concurrent_flat_map& other, const Allocator& a); + xref:#concurrent_flat_map_move_constructor_with_allocator[concurrent_flat_map](concurrent_flat_map&& other, const Allocator& a); + xref:#concurrent_flat_map_move_constructor_from_unordered_flat_map[concurrent_flat_map](unordered_flat_map&& other); + xref:#concurrent_flat_map_initializer_list_constructor[concurrent_flat_map](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_flat_map_bucket_count_constructor_with_allocator[concurrent_flat_map](size_type n, const allocator_type& a); + xref:#concurrent_flat_map_bucket_count_constructor_with_hasher_and_allocator[concurrent_flat_map](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#concurrent_flat_map_iterator_range_constructor_with_bucket_count_and_allocator[concurrent_flat_map](InputIterator f, InputIterator l, size_type n, + const allocator_type& a); + template + xref:#concurrent_flat_map_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_flat_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_flat_map_initializer_list_constructor_with_allocator[concurrent_flat_map](std::initializer_list il, const allocator_type& a); + xref:#concurrent_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_map](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#concurrent_flat_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_flat_map](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_flat_map_destructor[~concurrent_flat_map](); + concurrent_flat_map& xref:#concurrent_flat_map_copy_assignment[operator++=++](const concurrent_flat_map& other); + concurrent_flat_map& xref:#concurrent_flat_map_move_assignment[operator++=++](concurrent_flat_map&& other) ++noexcept( + (boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value);++ + concurrent_flat_map& xref:#concurrent_flat_map_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#concurrent_flat_map_get_allocator[get_allocator]() const noexcept; + + + // visitation + template size_t xref:#concurrent_flat_map_cvisit[visit](const key_type& k, F f); + template size_t xref:#concurrent_flat_map_cvisit[visit](const key_type& k, F f) const; + template size_t xref:#concurrent_flat_map_cvisit[cvisit](const key_type& k, F f) const; + template size_t xref:#concurrent_flat_map_cvisit[visit](const K& k, F f); + template size_t xref:#concurrent_flat_map_cvisit[visit](const K& k, F f) const; + template size_t xref:#concurrent_flat_map_cvisit[cvisit](const K& k, F f) const; + + template + size_t xref:concurrent_flat_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f); + template + size_t xref:concurrent_flat_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const; + template + size_t xref:concurrent_flat_map_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const; + + template size_t xref:#concurrent_flat_map_cvisit_all[visit_all](F f); + template size_t xref:#concurrent_flat_map_cvisit_all[visit_all](F f) const; + template size_t xref:#concurrent_flat_map_cvisit_all[cvisit_all](F f) const; + template + void xref:#concurrent_flat_map_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f); + template + void xref:#concurrent_flat_map_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f) const; + template + void xref:#concurrent_flat_map_parallel_cvisit_all[cvisit_all](ExecutionPolicy&& policy, F f) const; + + template bool xref:#concurrent_flat_map_cvisit_while[visit_while](F f); + template bool xref:#concurrent_flat_map_cvisit_while[visit_while](F f) const; + template bool xref:#concurrent_flat_map_cvisit_while[cvisit_while](F f) const; + template + bool xref:#concurrent_flat_map_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f); + template + bool xref:#concurrent_flat_map_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f) const; + template + bool xref:#concurrent_flat_map_parallel_cvisit_while[cvisit_while](ExecutionPolicy&& policy, F f) const; + + // capacity + ++[[nodiscard]]++ bool xref:#concurrent_flat_map_empty[empty]() const noexcept; + size_type xref:#concurrent_flat_map_size[size]() const noexcept; + size_type xref:#concurrent_flat_map_max_size[max_size]() const noexcept; + + // modifiers + template bool xref:#concurrent_flat_map_emplace[emplace](Args&&... args); + bool xref:#concurrent_flat_map_copy_insert[insert](const value_type& obj); + bool xref:#concurrent_flat_map_copy_insert[insert](const init_type& obj); + bool xref:#concurrent_flat_map_move_insert[insert](value_type&& obj); + bool xref:#concurrent_flat_map_move_insert[insert](init_type&& obj); + template size_type xref:#concurrent_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + size_type xref:#concurrent_flat_map_insert_initializer_list[insert](std::initializer_list il); + + template bool xref:#concurrent_flat_map_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f); + template bool xref:#concurrent_flat_map_emplace_or_cvisit[emplace_or_cvisit](Args&&... args, F&& f); + template bool xref:#concurrent_flat_map_copy_insert_or_cvisit[insert_or_visit](const value_type& obj, F f); + template bool xref:#concurrent_flat_map_copy_insert_or_cvisit[insert_or_cvisit](const value_type& obj, F f); + template bool xref:#concurrent_flat_map_copy_insert_or_cvisit[insert_or_visit](const init_type& obj, F f); + template bool xref:#concurrent_flat_map_copy_insert_or_cvisit[insert_or_cvisit](const init_type& obj, F f); + template bool xref:#concurrent_flat_map_move_insert_or_cvisit[insert_or_visit](value_type&& obj, F f); + template bool xref:#concurrent_flat_map_move_insert_or_cvisit[insert_or_cvisit](value_type&& obj, F f); + template bool xref:#concurrent_flat_map_move_insert_or_cvisit[insert_or_visit](init_type&& obj, F f); + template bool xref:#concurrent_flat_map_move_insert_or_cvisit[insert_or_cvisit](init_type&& obj, F f); + template + size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); + template + size_type xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); + template size_type xref:#concurrent_flat_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list il, F f); + + template + bool xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2); + template bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_visit](const init_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_copy_insert_and_cvisit[insert_and_cvisit](const init_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_visit](init_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_map_move_insert_and_cvisit[insert_and_cvisit](init_type&& obj, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_map_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list il, F1 f1, F2 f2); + + template bool xref:#concurrent_flat_map_try_emplace[try_emplace](const key_type& k, Args&&... args); + template bool xref:#concurrent_flat_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template bool xref:#concurrent_flat_map_try_emplace[try_emplace](K&& k, Args&&... args); + + template + bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_visit](const key_type& k, Args&&... args, F&& f); + template + bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_cvisit](const key_type& k, Args&&... args, F&& f); + template + bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_visit](key_type&& k, Args&&... args, F&& f); + template + bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_cvisit](key_type&& k, Args&&... args, F&& f); + template + bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_visit](K&& k, Args&&... args, F&& f); + template + bool xref:#concurrent_flat_map_try_emplace_or_cvisit[try_emplace_or_cvisit](K&& k, Args&&... args, F&& f); + + template + bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_visit](const key_type& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_cvisit](const key_type& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_visit](key_type&& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_cvisit](key_type&& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_visit](K&& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_map_try_emplace_and_cvisit[try_emplace_and_cvisit](K&& k, Args&&... args, F1&& f1, F2&& f2); + + template bool xref:#concurrent_flat_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); + template bool xref:#concurrent_flat_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template bool xref:#concurrent_flat_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); + + size_type xref:#concurrent_flat_map_erase[erase](const key_type& k); + template size_type xref:#concurrent_flat_map_erase[erase](const K& k); + + template size_type xref:#concurrent_flat_map_erase_if_by_key[erase_if](const key_type& k, F f); + template size_type xref:#concurrent_flat_map_erase_if_by_key[erase_if](const K& k, F f); + template size_type xref:#concurrent_flat_map_erase_if[erase_if](F f); + template void xref:#concurrent_flat_map_parallel_erase_if[erase_if](ExecutionPolicy&& policy, F f); + + void xref:#concurrent_flat_map_swap[swap](concurrent_flat_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + void xref:#concurrent_flat_map_clear[clear]() noexcept; + + template + size_type xref:#concurrent_flat_map_merge[merge](concurrent_flat_map& source); + template + size_type xref:#concurrent_flat_map_merge[merge](concurrent_flat_map&& source); + + // observers + hasher xref:#concurrent_flat_map_hash_function[hash_function]() const; + key_equal xref:#concurrent_flat_map_key_eq[key_eq]() const; + + // map operations + size_type xref:#concurrent_flat_map_count[count](const key_type& k) const; + template + size_type xref:#concurrent_flat_map_count[count](const K& k) const; + bool xref:#concurrent_flat_map_contains[contains](const key_type& k) const; + template + bool xref:#concurrent_flat_map_contains[contains](const K& k) const; + + // bucket interface + size_type xref:#concurrent_flat_map_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#concurrent_flat_map_load_factor[load_factor]() const noexcept; + float xref:#concurrent_flat_map_max_load_factor[max_load_factor]() const noexcept; + void xref:#concurrent_flat_map_set_max_load_factor[max_load_factor](float z); + size_type xref:#concurrent_flat_map_max_load[max_load]() const noexcept; + void xref:#concurrent_flat_map_rehash[rehash](size_type n); + void xref:#concurrent_flat_map_reserve[reserve](size_type n); + + // statistics (if xref:concurrent_flat_map_boost_unordered_enable_stats[enabled]) + stats xref:#concurrent_flat_map_get_stats[get_stats]() const; + void xref:#concurrent_flat_map_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + concurrent_flat_map(InputIterator, InputIterator, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_map_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_map, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, + Pred, Allocator>; + + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + concurrent_flat_map(std::initializer_list>, + typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_map_deduction_guides[__see below__], Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_map; + + template + concurrent_flat_map(InputIterator, InputIterator, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_flat_map, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_map(InputIterator, InputIterator, Allocator) + -> concurrent_flat_map, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_map(InputIterator, InputIterator, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> concurrent_flat_map, xref:#concurrent_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, + std::equal_to>, Allocator>; + + template + concurrent_flat_map(std::initializer_list>, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, + Allocator) + -> concurrent_flat_map, std::equal_to, Allocator>; + + template + concurrent_flat_map(std::initializer_list>, Allocator) + -> concurrent_flat_map, std::equal_to, Allocator>; + + template + concurrent_flat_map(std::initializer_list>, typename xref:#concurrent_flat_map_deduction_guides[__see below__]::size_type, + Hash, Allocator) + -> concurrent_flat_map, Allocator>; + + // Equality Comparisons + template + bool xref:#concurrent_flat_map_operator[operator==](const concurrent_flat_map& x, + const concurrent_flat_map& y); + + template + bool xref:#concurrent_flat_map_operator_2[operator!=](const concurrent_flat_map& x, + const concurrent_flat_map& y); + + // swap + template + void xref:#concurrent_flat_map_swap_2[swap](concurrent_flat_map& x, + concurrent_flat_map& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename concurrent_flat_map::size_type + xref:#concurrent_flat_map_erase_if_2[erase_if](concurrent_flat_map& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using concurrent_flat_map = + boost::concurrent_flat_map>>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +.2+|`Key` and `T` must be https://en.cppreference.com/w/cpp/named_req/MoveConstructible[MoveConstructible^]. +`std::pair` must be https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] +into the table from any `std::pair` object convertible to it, and it also must be +https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the table. + +|_T_ + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the table's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements of the table are held into an internal _bucket array_. An element is inserted into a bucket determined by its +hash code, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the table (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Concurrency Requirements and Guarantees + +Concurrent invocations of `operator()` on the same const instance of `Hash` or `Pred` are required +to not introduce data races. For `Alloc` being either `Allocator` or any allocator type rebound +from `Allocator`, concurrent invocations of the following operations on the same instance `al` of `Alloc` +are required to not introduce data races: + +* Copy construction from `al` of an allocator rebound from `Alloc` +* `std::allocator_traits::allocate` +* `std::allocator_traits::deallocate` +* `std::allocator_traits::construct` +* `std::allocator_traits::destroy` + +In general, these requirements on `Hash`, `Pred` and `Allocator` are met if these types +are not stateful or if the operations only involve constant access to internal data members. + +With the exception of destruction, concurrent invocations of any operation on the same instance of a +`concurrent_flat_map` do not introduce data races — that is, they are thread-safe. + +If an operation *op* is explicitly designated as _blocking on_ `x`, where `x` is an instance of a `boost::concurrent_flat_map`, +prior blocking operations on `x` synchronize with *op*. So, blocking operations on the same +`concurrent_flat_map` execute sequentially in a multithreaded scenario. + +An operation is said to be _blocking on rehashing of_ ``__x__`` if it blocks on `x` +only when an internal rehashing is issued. + +When executed internally by a `boost::concurrent_flat_map`, the following operations by a +user-provided visitation function on the element passed do not introduce data races: + +* Read access to the element. +* Non-mutable modification of the element. +* Mutable modification of the element: + ** Within a container function accepting two visitation functions, always for the first function. + ** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function. + +Any `boost::concurrent_flat_map operation` that inserts or modifies an element `e` +synchronizes with the internal invocation of a visitation function on `e`. + +Visitation functions executed by a `boost::concurrent_flat_map` `x` are not allowed to invoke any operation +on `x`; invoking operations on a different `boost::concurrent_flat_map` instance `y` is allowed only +if concurrent outstanding operations on `y` do not access `x` directly or indirectly. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK` + +In debug builds (more precisely, when +link:../../../assert/doc/html/assert.html#boost_assert_is_void[`BOOST_ASSERT_IS_VOID`^] +is not defined), __container reentrancies__ (illegaly invoking an operation on `m` from within +a function visiting elements of `m`) are detected and signalled through `BOOST_ASSERT_MSG`. +When run-time speed is a concern, the feature can be disabled by globally defining +this macro. + +--- + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the table. Note +that this option decreases the overall performance of many operations. + +--- + +=== Constants + +```cpp +static constexpr size_type bulk_visit_size; +``` + +Chunk size internally used in xref:concurrent_flat_map_bulk_visit[bulk visit] operations. + +=== Constructors + +==== Default Constructor +```c++ +concurrent_flat_map(); +``` + +Constructs an empty table using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit concurrent_flat_map(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + concurrent_flat_map(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +concurrent_flat_map(concurrent_flat_map const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor +```c++ +concurrent_flat_map(concurrent_flat_map&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new table. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + concurrent_flat_map(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty table using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit concurrent_flat_map(Allocator const& a); +``` + +Constructs an empty table, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +concurrent_flat_map(concurrent_flat_map const& other, Allocator const& a); +``` + +Constructs a table, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor with Allocator +```c++ +concurrent_flat_map(concurrent_flat_map&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the elements of `other` are transferred directly to the new table; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:concurrent_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor from unordered_flat_map + +```c++ +concurrent_flat_map(unordered_flat_map&& other); +``` + +Move construction from a xref:#unordered_flat_map[`unordered_flat_map`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; O(`bucket_count()`) + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +concurrent_flat_map(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +concurrent_flat_map(size_type n, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +concurrent_flat_map(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + concurrent_flat_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + concurrent_flat_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +concurrent_flat_map(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +concurrent_flat_map(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +concurrent_flat_map(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~concurrent_flat_map(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +concurrent_flat_map& operator=(concurrent_flat_map const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Move Assignment +```c++ +concurrent_flat_map& operator=(concurrent_flat_map&& other) + noexcept((boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to `*this`; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:concurrent_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Initializer List Assignment +```c++ +concurrent_flat_map& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this`. + +--- + +=== Visitation + +==== [c]visit + +```c++ +template size_t visit(const key_type& k, F f); +template size_t visit(const key_type& k, F f) const; +template size_t cvisit(const key_type& k, F f) const; +template size_t visit(const K& k, F f); +template size_t visit(const K& k, F f) const; +template size_t cvisit(const K& k, F f) const; +``` + +If an element `x` exists with key equivalent to `k`, invokes `f` with a reference to `x`. +Such reference is const iff `*this` is const. + +[horizontal] +Returns:;; The number of elements visited (0 or 1). +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Bulk visit + +```c++ +template + size_t visit(FwdIterator first, FwdIterator last, F f); +template + size_t visit(FwdIterator first, FwdIterator last, F f) const; +template + size_t cvisit(FwdIterator first, FwdIterator last, F f) const; +``` + +For each element `k` in the range [`first`, `last`), +if there is an element `x` in the container with key equivalent to `k`, +invokes `f` with a reference to `x`. +Such reference is const iff `*this` is const. + +Although functionally equivalent to individually invoking +xref:concurrent_flat_map_cvisit[`[c\]visit`] for each key, bulk visitation +performs generally faster due to internal streamlining optimizations. +It is advisable that `std::distance(first,last)` be at least +xref:#concurrent_flat_map_constants[`bulk_visit_size`] to enjoy +a performance gain: beyond this size, performance is not expected +to increase further. + +[horizontal] +Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^] +({cpp}11 to {cpp}17), +or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later). +For `K` = `std::iterator_traits::value_type`, either `K` is `key_type` or +else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. +In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. +This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +Returns:;; The number of elements visited. + +--- + +==== [c]visit_all + +```c++ +template size_t visit_all(F f); +template size_t visit_all(F f) const; +template size_t cvisit_all(F f) const; +``` + +Successively invokes `f` with references to each of the elements in the table. +Such references are const iff `*this` is const. + +[horizontal] +Returns:;; The number of elements visited. + +--- + +==== Parallel [c]visit_all + +```c++ +template void visit_all(ExecutionPolicy&& policy, F f); +template void visit_all(ExecutionPolicy&& policy, F f) const; +template void cvisit_all(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with references to each of the elements in the table. Such references are const iff `*this` is const. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== [c]visit_while + +```c++ +template bool visit_while(F f); +template bool visit_while(F f) const; +template bool cvisit_while(F f) const; +``` + +Successively invokes `f` with references to each of the elements in the table until `f` returns `false` +or all the elements are visited. +Such references to the elements are const iff `*this` is const. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. + +--- + +==== Parallel [c]visit_while + +```c++ +template bool visit_while(ExecutionPolicy&& policy, F f); +template bool visit_while(ExecutionPolicy&& policy, F f) const; +template bool cvisit_while(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with references to each of the elements in the table until `f` returns `false` +or all the elements are visited. +Such references to the elements are const iff `*this` is const. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + ++ +Parallelization implies that execution does not necessary finish as soon as `f` returns `false`, and as a result +`f` may be invoked with further elements for which the return value is also `false`. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; The number of elements in the table. + +[horizontal] +Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true size of the table right after execution. + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible table. + +--- + +=== Modifiers + +==== emplace +```c++ +template bool emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. + +--- + +==== Copy Insert +```c++ +bool insert(const value_type& obj); +bool insert(const init_type& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +A call of the form `insert(x)`, where `x` is equally convertible to both `const value_type&` and `const init_type&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Move Insert +```c++ +bool insert(value_type&& obj); +bool insert(init_type&& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +A call of the form `insert(x)`, where `x` is equally convertible to both `value_type&&` and `init_type&&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Insert Iterator Range +```c++ +template size_type insert(InputIterator first, InputIterator last); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_flat_map_emplace[emplace](*first++); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List +```c++ +size_type insert(std::initializer_list il); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_flat_map_insert_iterator_range[insert](il.begin(), il.end()); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== emplace_or_[c]visit +```c++ +template bool emplace_or_visit(Args&&... args, F&& f); +template bool emplace_or_cvisit(Args&&... args, F&& f); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff `emplace_or_cvisit` is used. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +The interface is exposition only, as C++ does not allow to declare a parameter `f` after a variadic parameter pack. + +--- + +==== Copy insert_or_[c]visit +```c++ +template bool insert_or_visit(const value_type& obj, F f); +template bool insert_or_cvisit(const value_type& obj, F f); +template bool insert_or_visit(const init_type& obj, F f); +template bool insert_or_cvisit(const init_type& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +In a call of the form `insert_or_[c]visit(obj, f)`, the overloads accepting a `const value_type&` argument participate in overload resolution +only if `std::remove_cv::type>::type` is `value_type`. + +--- + +==== Move insert_or_[c]visit +```c++ +template bool insert_or_visit(value_type&& obj, F f); +template bool insert_or_cvisit(value_type&& obj, F f); +template bool insert_or_visit(init_type&& obj, F f); +template bool insert_or_cvisit(init_type&& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +In a call of the form `insert_or_[c]visit(obj, f)`, the overloads accepting a `value_type&&` argument participate in overload resolution +only if `std::remove_reference::type` is `value_type`. + +--- + +==== Insert Iterator Range or Visit +```c++ +template + size_type insert_or_visit(InputIterator first, InputIterator last, F f); +template + size_type insert_or_cvisit(InputIterator first, InputIterator last, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_flat_map_emplace_or_cvisit[emplace_or_[c\]visit](*first++, f); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List or Visit +```c++ +template size_type insert_or_visit(std::initializer_list il, F f); +template size_type insert_or_cvisit(std::initializer_list il, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_flat_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== emplace_and_[c]visit +```c++ +template + bool emplace_and_visit(Args&&... args, F1&& f1, F2&& f2); +template + bool emplace_and_cvisit(Args&&... args, F1&& f1, F2&& f2); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff `emplace_and_cvisit` is used. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack. + +--- + +==== Copy insert_and_[c]visit +```c++ +template bool insert_and_visit(const value_type& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(const value_type& obj, F1 f1, F2 f2); +template bool insert_and_visit(const init_type& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(const init_type& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `const value_type&` argument participate in overload resolution +only if `std::remove_cv::type>::type` is `value_type`. + +--- + +==== Move insert_and_[c]visit +```c++ +template bool insert_and_visit(value_type&& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2); +template bool insert_and_visit(init_type&& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `value_type&&` argument participate in overload resolution +only if `std::remove_reference::type` is `value_type`. + +--- + +==== Insert Iterator Range and Visit +```c++ +template + size_type insert_or_visit(InputIterator first, InputIterator last, F1 f1, F2 f2); +template + size_type insert_or_cvisit(InputIterator first, InputIterator last, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_flat_map_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List and Visit +```c++ +template + size_type insert_and_visit(std::initializer_list il, F1 f1, F2 f2); +template + size_type insert_and_cvisit(std::initializer_list il, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_flat_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== try_emplace +```c++ +template bool try_emplace(const key_type& k, Args&&... args); +template bool try_emplace(key_type&& k, Args&&... args); +template bool try_emplace(K&& k, Args&&... args); +``` + +Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it. + +[horizontal] +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; This function is similiar to xref:#concurrent_flat_map_emplace[emplace], with the difference that no `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +unlike xref:#concurrent_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor. + +Invalidates pointers and references to elements if a rehashing is issued. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== try_emplace_or_[c]visit +```c++ +template + bool try_emplace_or_visit(const key_type& k, Args&&... args, F&& f); +template + bool try_emplace_or_cvisit(const key_type& k, Args&&... args, F&& f); +template + bool try_emplace_or_visit(key_type&& k, Args&&... args, F&& f); +template + bool try_emplace_or_cvisit(key_type&& k, Args&&... args, F&& f); +template + bool try_emplace_or_visit(K&& k, Args&&... args, F&& f); +template + bool try_emplace_or_cvisit(K&& k, Args&&... args, F&& f); +``` + +Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; No `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first four overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// last two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +Invalidates pointers and references to elements if a rehashing is issued. + +The interface is exposition only, as C++ does not allow to declare a parameter `f` after a variadic parameter pack. + +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== try_emplace_and_[c]visit +```c++ +template + bool try_emplace_and_visit(const key_type& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_cvisit(const key_type& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_visit(key_type&& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_cvisit(key_type&& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_visit(K&& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_cvisit(K&& k, Args&&... args, F1&& f1, F2&& f2); +``` + +Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; No `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first four overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// last two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +Invalidates pointers and references to elements if a rehashing is issued. + +The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack. + +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== insert_or_assign +```c++ +template bool insert_or_assign(const key_type& k, M&& obj); +template bool insert_or_assign(key_type&& k, M&& obj); +template bool insert_or_assign(K&& k, M&& obj); +``` + +Inserts a new element into the table or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the table as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +[horizontal] +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase +```c++ +size_type erase(const key_type& k); +template size_type erase(const K& k); +``` + +Erases the element with key equivalent to `k` if it exists. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if by Key +```c++ +template size_type erase_if(const key_type& k, F f); +template size_type erase_if(const K& k, F f); +``` + +Erases the element `x` with key equivalent to `k` if it exists and `f(x)` is `true`. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher`, `key_equal` or `f`. +Notes:;; The `template` overload only participates in overload resolution if `std::is_execution_policy_v>` is `false`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if +```c++ +template size_type erase_if(F f); +``` + +Successively invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `f`. + +--- + +==== Parallel erase_if +```c++ +template void erase_if(ExecutionPolicy&& policy, F f); +``` + +Invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +This overload only participates in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== swap +```c++ +void swap(concurrent_flat_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the table with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the tables' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the table. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` +Concurrency:;; Blocking on `*this`. + +--- + +==== merge +```c++ +template + size_type merge(concurrent_flat_map& source); +template + size_type merge(concurrent_flat_map&& source); +``` + +Move-inserts all the elements from `source` whose key is not already present in `*this`, and erases them from `source`. + +[horizontal] +Returns:;; The number of elements inserted. +Concurrency:;; Blocking on `*this` and `source`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The table's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The table's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The table's key equality predicate. + +--- + +=== Map Operations + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k` (0 or 1). +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `k` in the table. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the table's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_map`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the table can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the table's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the table. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +Invalidates pointers and references to elements, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the table. + +Invalidates pointers and references to elements, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the table so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_flat_map_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the table. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_flat_map_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +table type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +==== __iter-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-key-type__ = std::remove_const_t< + std::tuple_element_t<0, xref:#concurrent_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +==== __iter-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-mapped-type__ = + std::tuple_element_t<1, xref:#concurrent_map_iter_value_type[__iter-value-type__]>; // exposition only +----- + +==== __iter-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-to-alloc-type__ = std::pair< + std::add_const_t>>, + std::tuple_element_t<1, xref:#concurrent_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const concurrent_flat_map& x, + const concurrent_flat_map& y); +``` + +Returns `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const concurrent_flat_map& x, + const concurrent_flat_map& y); +``` + +Returns `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(concurrent_flat_map& x, + concurrent_flat_map& y) + noexcept(noexcept(x.swap(y))); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +x.xref:#concurrent_flat_map_swap[swap](y); +----- + +--- + +=== erase_if +```c++ +template + typename concurrent_flat_map::size_type + erase_if(concurrent_flat_map& c, Predicate pred); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +c.xref:#concurrent_flat_map_erase_if[erase_if](pred); +----- + +=== Serialization + +``concurrent_flat_map``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an concurrent_flat_map to an archive + +Saves all the elements of a `concurrent_flat_map` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `std::remove_const::type` and `std::remove_const::type` +are serializable (XML serializable), and they do support Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). +Concurrency:;; Blocking on `x`. + +--- + +==== Loading an concurrent_flat_map from an archive + +Deletes all preexisting elements of a `concurrent_flat_map` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `concurrent_flat_map` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`. +Concurrency:;; Blocking on `x`. diff --git a/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc b/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc new file mode 100644 index 00000000..3a6ebe70 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/concurrent_flat_set.adoc @@ -0,0 +1,1634 @@ +[#concurrent_flat_set] +== Class Template concurrent_flat_set + +:idprefix: concurrent_flat_set_ + +`boost::concurrent_flat_set` — A hash table that stores unique values and +allows for concurrent element insertion, erasure, lookup and access +without external synchronization mechanisms. + +Even though it acts as a container, `boost::concurrent_flat_set` +does not model the standard C++ https://en.cppreference.com/w/cpp/named_req/Container[Container^] concept. +In particular, iterators and associated operations (`begin`, `end`, etc.) are not provided. +Element access is done through user-provided _visitation functions_ that are passed +to `concurrent_flat_set` operations where they are executed internally in a controlled fashion. +Such visitation-based API allows for low-contention concurrent usage scenarios. + +The internal data structure of `boost::concurrent_flat_set` is similar to that of +`boost::unordered_flat_set`. As a result of its using open-addressing techniques, +`value_type` must be move-constructible and pointer stability is not kept under rehashing. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator> + class concurrent_flat_set { + public: + // types + using key_type = Key; + using value_type = Key; + using init_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:concurrent_flat_set_boost_unordered_enable_stats[enabled] + + // constants + static constexpr size_type xref:#concurrent_flat_set_constants[bulk_visit_size] = _implementation-defined_; + + // construct/copy/destroy + xref:#concurrent_flat_set_default_constructor[concurrent_flat_set](); + explicit xref:#concurrent_flat_set_bucket_count_constructor[concurrent_flat_set](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#concurrent_flat_set_iterator_range_constructor[concurrent_flat_set](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_flat_set_copy_constructor[concurrent_flat_set](const concurrent_flat_set& other); + xref:#concurrent_flat_set_move_constructor[concurrent_flat_set](concurrent_flat_set&& other); + template + xref:#concurrent_flat_set_iterator_range_constructor_with_allocator[concurrent_flat_set](InputIterator f, InputIterator l,const allocator_type& a); + explicit xref:#concurrent_flat_set_allocator_constructor[concurrent_flat_set](const Allocator& a); + xref:#concurrent_flat_set_copy_constructor_with_allocator[concurrent_flat_set](const concurrent_flat_set& other, const Allocator& a); + xref:#concurrent_flat_set_move_constructor_with_allocator[concurrent_flat_set](concurrent_flat_set&& other, const Allocator& a); + xref:#concurrent_flat_set_move_constructor_from_unordered_flat_set[concurrent_flat_set](unordered_flat_set&& other); + xref:#concurrent_flat_set_initializer_list_constructor[concurrent_flat_set](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_flat_set_bucket_count_constructor_with_allocator[concurrent_flat_set](size_type n, const allocator_type& a); + xref:#concurrent_flat_set_bucket_count_constructor_with_hasher_and_allocator[concurrent_flat_set](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#concurrent_flat_set_iterator_range_constructor_with_bucket_count_and_allocator[concurrent_flat_set](InputIterator f, InputIterator l, size_type n, + const allocator_type& a); + template + xref:#concurrent_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_flat_set_initializer_list_constructor_with_allocator[concurrent_flat_set](std::initializer_list il, const allocator_type& a); + xref:#concurrent_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_flat_set](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#concurrent_flat_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_flat_set](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_flat_set_destructor[~concurrent_flat_set](); + concurrent_flat_set& xref:#concurrent_flat_set_copy_assignment[operator++=++](const concurrent_flat_set& other); + concurrent_flat_set& xref:#concurrent_flat_set_move_assignment[operator++=++](concurrent_flat_set&& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value); + concurrent_flat_set& xref:#concurrent_flat_set_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#concurrent_flat_set_get_allocator[get_allocator]() const noexcept; + + + // visitation + template size_t xref:#concurrent_flat_set_cvisit[visit](const key_type& k, F f); + template size_t xref:#concurrent_flat_set_cvisit[visit](const key_type& k, F f) const; + template size_t xref:#concurrent_flat_set_cvisit[cvisit](const key_type& k, F f) const; + template size_t xref:#concurrent_flat_set_cvisit[visit](const K& k, F f); + template size_t xref:#concurrent_flat_set_cvisit[visit](const K& k, F f) const; + template size_t xref:#concurrent_flat_set_cvisit[cvisit](const K& k, F f) const; + + template + size_t xref:concurrent_flat_set_bulk_visit[visit](FwdIterator first, FwdIterator last, F f); + template + size_t xref:concurrent_flat_set_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const; + template + size_t xref:concurrent_flat_set_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const; + + template size_t xref:#concurrent_flat_set_cvisit_all[visit_all](F f); + template size_t xref:#concurrent_flat_set_cvisit_all[visit_all](F f) const; + template size_t xref:#concurrent_flat_set_cvisit_all[cvisit_all](F f) const; + template + void xref:#concurrent_flat_set_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f); + template + void xref:#concurrent_flat_set_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f) const; + template + void xref:#concurrent_flat_set_parallel_cvisit_all[cvisit_all](ExecutionPolicy&& policy, F f) const; + + template bool xref:#concurrent_flat_set_cvisit_while[visit_while](F f); + template bool xref:#concurrent_flat_set_cvisit_while[visit_while](F f) const; + template bool xref:#concurrent_flat_set_cvisit_while[cvisit_while](F f) const; + template + bool xref:#concurrent_flat_set_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f); + template + bool xref:#concurrent_flat_set_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f) const; + template + bool xref:#concurrent_flat_set_parallel_cvisit_while[cvisit_while](ExecutionPolicy&& policy, F f) const; + + // capacity + ++[[nodiscard]]++ bool xref:#concurrent_flat_set_empty[empty]() const noexcept; + size_type xref:#concurrent_flat_set_size[size]() const noexcept; + size_type xref:#concurrent_flat_set_max_size[max_size]() const noexcept; + + // modifiers + template bool xref:#concurrent_flat_set_emplace[emplace](Args&&... args); + bool xref:#concurrent_flat_set_copy_insert[insert](const value_type& obj); + bool xref:#concurrent_flat_set_move_insert[insert](value_type&& obj); + template bool xref:#concurrent_flat_set_transparent_insert[insert](K&& k); + template size_type xref:#concurrent_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + size_type xref:#concurrent_flat_set_insert_initializer_list[insert](std::initializer_list il); + + template bool xref:#concurrent_flat_set_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f); + template bool xref:#concurrent_flat_set_emplace_or_cvisit[emplace_or_cvisit](Args&&... args, F&& f); + template bool xref:#concurrent_flat_set_copy_insert_or_cvisit[insert_or_visit](const value_type& obj, F f); + template bool xref:#concurrent_flat_set_copy_insert_or_cvisit[insert_or_cvisit](const value_type& obj, F f); + template bool xref:#concurrent_flat_set_move_insert_or_cvisit[insert_or_visit](value_type&& obj, F f); + template bool xref:#concurrent_flat_set_move_insert_or_cvisit[insert_or_cvisit](value_type&& obj, F f); + template bool xref:#concurrent_flat_set_transparent_insert_or_cvisit[insert_or_visit](K&& k, F f); + template bool xref:#concurrent_flat_set_transparent_insert_or_cvisit[insert_or_cvisit](K&& k, F f); + template + size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); + template + size_type xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); + template size_type xref:#concurrent_flat_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list il, F f); + + template + bool xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2); + template bool xref:#concurrent_flat_set_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_set_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_set_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_set_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_flat_set_transparent_insert_and_cvisit[insert_and_visit](K&& k, F1 f1, F2 f2); + template bool xref:#concurrent_flat_set_transparent_insert_and_cvisit[insert_and_cvisit](K&& k, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); + template + size_type xref:#concurrent_flat_set_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list il, F1 f1, F2 f2); + + size_type xref:#concurrent_flat_set_erase[erase](const key_type& k); + template size_type xref:#concurrent_flat_set_erase[erase](const K& k); + + template size_type xref:#concurrent_flat_set_erase_if_by_key[erase_if](const key_type& k, F f); + template size_type xref:#concurrent_flat_set_erase_if_by_key[erase_if](const K& k, F f); + template size_type xref:#concurrent_flat_set_erase_if[erase_if](F f); + template void xref:#concurrent_flat_set_parallel_erase_if[erase_if](ExecutionPolicy&& policy, F f); + + void xref:#concurrent_flat_set_swap[swap](concurrent_flat_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + void xref:#concurrent_flat_set_clear[clear]() noexcept; + + template + size_type xref:#concurrent_flat_set_merge[merge](concurrent_flat_set& source); + template + size_type xref:#concurrent_flat_set_merge[merge](concurrent_flat_set&& source); + + // observers + hasher xref:#concurrent_flat_set_hash_function[hash_function]() const; + key_equal xref:#concurrent_flat_set_key_eq[key_eq]() const; + + // set operations + size_type xref:#concurrent_flat_set_count[count](const key_type& k) const; + template + size_type xref:#concurrent_flat_set_count[count](const K& k) const; + bool xref:#concurrent_flat_set_contains[contains](const key_type& k) const; + template + bool xref:#concurrent_flat_set_contains[contains](const K& k) const; + + // bucket interface + size_type xref:#concurrent_flat_set_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#concurrent_flat_set_load_factor[load_factor]() const noexcept; + float xref:#concurrent_flat_set_max_load_factor[max_load_factor]() const noexcept; + void xref:#concurrent_flat_set_set_max_load_factor[max_load_factor](float z); + size_type xref:#concurrent_flat_set_max_load[max_load]() const noexcept; + void xref:#concurrent_flat_set_rehash[rehash](size_type n); + void xref:#concurrent_flat_set_reserve[reserve](size_type n); + + // statistics (if xref:concurrent_flat_set_boost_unordered_enable_stats[enabled]) + stats xref:#concurrent_flat_set_get_stats[get_stats]() const; + void xref:#concurrent_flat_set_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + concurrent_flat_set(InputIterator, InputIterator, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_set, Hash, Pred, Allocator>; + + template, class Pred = std::equal_to, + class Allocator = std::allocator> + concurrent_flat_set(std::initializer_list, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type = xref:#concurrent_flat_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_flat_set; + + template + concurrent_flat_set(InputIterator, InputIterator, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_set(InputIterator, InputIterator, Allocator) + -> concurrent_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_flat_set(InputIterator, InputIterator, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> concurrent_flat_set, Hash, + std::equal_to>, Allocator>; + + template + concurrent_flat_set(std::initializer_list, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_flat_set, std::equal_to, Allocator>; + + template + concurrent_flat_set(std::initializer_list, Allocator) + -> concurrent_flat_set, std::equal_to, Allocator>; + + template + concurrent_flat_set(std::initializer_list, typename xref:#concurrent_flat_set_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> concurrent_flat_set, Allocator>; + + // Equality Comparisons + template + bool xref:#concurrent_flat_set_operator[operator==](const concurrent_flat_set& x, + const concurrent_flat_set& y); + + template + bool xref:#concurrent_flat_set_operator_2[operator!=](const concurrent_flat_set& x, + const concurrent_flat_set& y); + + // swap + template + void xref:#concurrent_flat_set_swap_2[swap](concurrent_flat_set& x, + concurrent_flat_set& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename concurrent_flat_set::size_type + xref:#concurrent_flat_set_erase_if_2[erase_if](concurrent_flat_set& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using concurrent_flat_set = + boost::concurrent_flat_set>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^] into the container +and https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container. + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the table's value type. +`std::allocator_traits::pointer` and `std::allocator_traits::const_pointer` +must be convertible to/from `value_type*` and `const value_type*`, respectively. + +|=== + +The elements of the table are held into an internal _bucket array_. An element is inserted into a bucket determined by its +hash code, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the table (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Concurrency Requirements and Guarantees + +Concurrent invocations of `operator()` on the same const instance of `Hash` or `Pred` are required +to not introduce data races. For `Alloc` being either `Allocator` or any allocator type rebound +from `Allocator`, concurrent invocations of the following operations on the same instance `al` of `Alloc` +are required to not introduce data races: + +* Copy construction from `al` of an allocator rebound from `Alloc` +* `std::allocator_traits::allocate` +* `std::allocator_traits::deallocate` +* `std::allocator_traits::construct` +* `std::allocator_traits::destroy` + +In general, these requirements on `Hash`, `Pred` and `Allocator` are met if these types +are not stateful or if the operations only involve constant access to internal data members. + +With the exception of destruction, concurrent invocations of any operation on the same instance of a +`concurrent_flat_set` do not introduce data races — that is, they are thread-safe. + +If an operation *op* is explicitly designated as _blocking on_ `x`, where `x` is an instance of a `boost::concurrent_flat_set`, +prior blocking operations on `x` synchronize with *op*. So, blocking operations on the same +`concurrent_flat_set` execute sequentially in a multithreaded scenario. + +An operation is said to be _blocking on rehashing of_ ``__x__`` if it blocks on `x` +only when an internal rehashing is issued. + +When executed internally by a `boost::concurrent_flat_set`, the following operations by a +user-provided visitation function on the element passed do not introduce data races: + +* Read access to the element. +* Non-mutable modification of the element. +* Mutable modification of the element: + ** Within a container function accepting two visitation functions, always for the first function. + ** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function. + +Any `boost::concurrent_flat_set operation` that inserts or modifies an element `e` +synchronizes with the internal invocation of a visitation function on `e`. + +Visitation functions executed by a `boost::concurrent_flat_set` `x` are not allowed to invoke any operation +on `x`; invoking operations on a different `boost::concurrent_flat_set` instance `y` is allowed only +if concurrent outstanding operations on `y` do not access `x` directly or indirectly. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK` + +In debug builds (more precisely, when +link:../../../assert/doc/html/assert.html#boost_assert_is_void[`BOOST_ASSERT_IS_VOID`^] +is not defined), __container reentrancies__ (illegaly invoking an operation on `m` from within +a function visiting elements of `m`) are detected and signalled through `BOOST_ASSERT_MSG`. +When run-time speed is a concern, the feature can be disabled by globally defining +this macro. + +--- + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the table. Note +that this option decreases the overall performance of many operations. + +--- + +=== Constants + +```cpp +static constexpr size_type bulk_visit_size; +``` + +Chunk size internally used in xref:concurrent_flat_set_bulk_visit[bulk visit] operations. + +=== Constructors + +==== Default Constructor +```c++ +concurrent_flat_set(); +``` + +Constructs an empty table using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit concurrent_flat_set(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + concurrent_flat_set(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +concurrent_flat_set(concurrent_flat_set const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor +```c++ +concurrent_flat_set(concurrent_flat_set&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new table. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + concurrent_flat_set(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty table using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit concurrent_flat_set(Allocator const& a); +``` + +Constructs an empty table, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +concurrent_flat_set(concurrent_flat_set const& other, Allocator const& a); +``` + +Constructs a table, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor with Allocator +```c++ +concurrent_flat_set(concurrent_flat_set&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the elements of `other` are transferred directly to the new table; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:concurrent_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor from unordered_flat_set + +```c++ +concurrent_flat_set(unordered_flat_set&& other); +``` + +Move construction from a xref:#unordered_flat_set[`unordered_flat_set`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; O(`bucket_count()`) + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +concurrent_flat_set(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +concurrent_flat_set(size_type n, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +concurrent_flat_set(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + concurrent_flat_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + concurrent_flat_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +concurrent_flat_set(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +concurrent_flat_set(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +concurrent_flat_set(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~concurrent_flat_set(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +concurrent_flat_set& operator=(concurrent_flat_set const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Move Assignment +```c++ +concurrent_flat_set& operator=(concurrent_flat_set&& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to `*this`; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:concurrent_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Initializer List Assignment +```c++ +concurrent_flat_set& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this`. + +--- + +=== Visitation + +==== [c]visit + +```c++ +template size_t visit(const key_type& k, F f); +template size_t visit(const key_type& k, F f) const; +template size_t cvisit(const key_type& k, F f) const; +template size_t visit(const K& k, F f); +template size_t visit(const K& k, F f) const; +template size_t cvisit(const K& k, F f) const; +``` + +If an element `x` exists with key equivalent to `k`, invokes `f` with a const reference to `x`. + +[horizontal] +Returns:;; The number of elements visited (0 or 1). +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Bulk visit + +```c++ +template + size_t visit(FwdIterator first, FwdIterator last, F f); +template + size_t visit(FwdIterator first, FwdIterator last, F f) const; +template + size_t cvisit(FwdIterator first, FwdIterator last, F f) const; +``` + +For each element `k` in the range [`first`, `last`), +if there is an element `x` in the container with key equivalent to `k`, +invokes `f` with a const reference to `x`. + +Although functionally equivalent to individually invoking +xref:concurrent_flat_set_cvisit[`[c\]visit`] for each key, bulk visitation +performs generally faster due to internal streamlining optimizations. +It is advisable that `std::distance(first,last)` be at least +xref:#concurrent_flat_set_constants[`bulk_visit_size`] to enjoy +a performance gain: beyond this size, performance is not expected +to increase further. + +[horizontal] +Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^] +({cpp}11 to {cpp}17), +or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later). +For `K` = `std::iterator_traits::value_type`, either `K` is `key_type` or +else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. +In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. +This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +Returns:;; The number of elements visited. + +--- + +==== [c]visit_all + +```c++ +template size_t visit_all(F f); +template size_t visit_all(F f) const; +template size_t cvisit_all(F f) const; +``` + +Successively invokes `f` with const references to each of the elements in the table. + +[horizontal] +Returns:;; The number of elements visited. + +--- + +==== Parallel [c]visit_all + +```c++ +template void visit_all(ExecutionPolicy&& policy, F f); +template void visit_all(ExecutionPolicy&& policy, F f) const; +template void cvisit_all(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with const references to each of the elements in the table. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== [c]visit_while + +```c++ +template bool visit_while(F f); +template bool visit_while(F f) const; +template bool cvisit_while(F f) const; +``` + +Successively invokes `f` with const references to each of the elements in the table until `f` returns `false` +or all the elements are visited. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. + +--- + +==== Parallel [c]visit_while + +```c++ +template bool visit_while(ExecutionPolicy&& policy, F f); +template bool visit_while(ExecutionPolicy&& policy, F f) const; +template bool cvisit_while(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with const references to each of the elements in the table until `f` returns `false` +or all the elements are visited. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + ++ +Parallelization implies that execution does not necessary finish as soon as `f` returns `false`, and as a result +`f` may be invoked with further elements for which the return value is also `false`. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; The number of elements in the table. + +[horizontal] +Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true size of the table right after execution. + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible table. + +--- + +=== Modifiers + +==== emplace +```c++ +template bool emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Copy Insert +```c++ +bool insert(const value_type& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Move Insert +```c++ +bool insert(value_type&& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Transparent Insert +```c++ +template bool insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range +```c++ +template size_type insert(InputIterator first, InputIterator last); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_flat_set_emplace[emplace](*first++); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List +```c++ +size_type insert(std::initializer_list il); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_flat_set_insert_iterator_range[insert](il.begin(), il.end()); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== emplace_or_[c]visit +```c++ +template bool emplace_or_visit(Args&&... args, F&& f); +template bool emplace_or_cvisit(Args&&... args, F&& f); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +The interface is exposition only, as C++ does not allow to declare a parameter `f` after a variadic parameter pack. + +--- + +==== Copy insert_or_[c]visit +```c++ +template bool insert_or_visit(const value_type& obj, F f); +template bool insert_or_cvisit(const value_type& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Move insert_or_[c]visit +```c++ +template bool insert_or_visit(value_type&& obj, F f); +template bool insert_or_cvisit(value_type&& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Transparent insert_or_[c]visit +```c++ +template bool insert_or_visit(K&& k, F f); +template bool insert_or_cvisit(K&& k, F f); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +These overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range or Visit +```c++ +template + size_type insert_or_visit(InputIterator first, InputIterator last, F f); +template + size_type insert_or_cvisit(InputIterator first, InputIterator last, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_flat_set_emplace_or_cvisit[emplace_or_[c\]visit](*first++, f); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List or Visit +```c++ +template size_type insert_or_visit(std::initializer_list il, F f); +template size_type insert_or_cvisit(std::initializer_list il, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_flat_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== emplace_and_[c]visit +```c++ +template + bool emplace_and_visit(Args&&... args, F1&& f1, F2&& f2); +template + bool emplace_and_cvisit(Args&&... args, F1&& f1, F2&& f2); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack. + +--- + +==== Copy insert_and_[c]visit +```c++ +template bool insert_and_visit(const value_type& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(const value_type& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Move insert_and_[c]visit +```c++ +template bool insert_and_visit(value_type&& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + +--- + +==== Transparent insert_and_[c]visit +```c++ +template bool insert_and_visit(K&& k, F1 f1, F2 f2); +template bool insert_and_cvisit(K&& k, F1 f1, F2 f2); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Invalidates pointers and references to elements if a rehashing is issued. + ++ +These overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range and Visit +```c++ +template + size_type insert_and_visit(InputIterator first, InputIterator last, F1 f1, F2 f2); +template + size_type insert_and_cvisit(InputIterator first, InputIterator last, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_flat_set_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List and Visit +```c++ +template + size_type insert_and_visit(std::initializer_list il, F1 f1, F2 f2); +template + size_type insert_and_cvisit(std::initializer_list il, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_flat_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== erase +```c++ +size_type erase(const key_type& k); +template size_type erase(const K& k); +``` + +Erases the element with key equivalent to `k` if it exists. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if by Key +```c++ +template size_type erase_if(const key_type& k, F f); +template size_type erase_if(const K& k, F f); +``` + +Erases the element `x` with key equivalent to `k` if it exists and `f(x)` is `true`. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher`, `key_equal` or `f`. +Notes:;; The `template` overload only participates in overload resolution if `std::is_execution_policy_v>` is `false`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if +```c++ +template size_type erase_if(F f); +``` + +Successively invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `f`. + +--- + +==== Parallel erase_if +```c++ +template void erase_if(ExecutionPolicy&& policy, F f); +``` + +Invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +This overload only participates in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== swap +```c++ +void swap(concurrent_flat_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the table with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the tables' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the table. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` +Concurrency:;; Blocking on `*this`. + +--- + +==== merge +```c++ +template + size_type merge(concurrent_flat_set& source); +template + size_type merge(concurrent_flat_set&& source); +``` + +Move-inserts all the elements from `source` whose key is not already present in `*this`, and erases them from `source`. + +[horizontal] +Returns:;; The number of elements inserted. +Concurrency:;; Blocking on `*this` and `source`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The table's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The table's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The table's key equality predicate. + +--- + +=== Set Operations + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k` (0 or 1). +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `k` in the table. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the table's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_set`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the table can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the table's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the table. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +Invalidates pointers and references to elements, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the table. + +Invalidates pointers and references to elements, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the table so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_flat_set_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the table. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_flat_set_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const concurrent_flat_set& x, + const concurrent_flat_set& y); +``` + +Returns `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const concurrent_flat_set& x, + const concurrent_flat_set& y); +``` + +Returns `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(concurrent_flat_set& x, + concurrent_flat_set& y) + noexcept(noexcept(x.swap(y))); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +x.xref:#concurrent_flat_set_swap[swap](y); +----- + +--- + +=== erase_if +```c++ +template + typename concurrent_flat_set::size_type + erase_if(concurrent_flat_set& c, Predicate pred); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +c.xref:#concurrent_flat_set_erase_if[erase_if](pred); +----- + +=== Serialization + +``concurrent_flat_set``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an concurrent_flat_set to an archive + +Saves all the elements of a `concurrent_flat_set` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `value_type` is serializable (XML serializable), and it supports Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). +Concurrency:;; Blocking on `x`. + +--- + +==== Loading an concurrent_flat_set from an archive + +Deletes all preexisting elements of a `concurrent_flat_set` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `concurrent_flat_set` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`. +Concurrency:;; Blocking on `x`. diff --git a/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc b/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc new file mode 100644 index 00000000..f6e20dd8 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/concurrent_node_map.adoc @@ -0,0 +1,1976 @@ +[#concurrent_node_map] +== Class Template concurrent_node_map + +:idprefix: concurrent_node_map_ + +`boost::concurrent_node_map` — A node-based hash table that associates unique keys with another value and +allows for concurrent element insertion, erasure, lookup and access +without external synchronization mechanisms. + +Even though it acts as a container, `boost::concurrent_node_map` +does not model the standard C++ https://en.cppreference.com/w/cpp/named_req/Container[Container^] concept. +In particular, iterators and associated operations (`begin`, `end`, etc.) are not provided. +Element access and modification are done through user-provided _visitation functions_ that are passed +to `concurrent_node_map` operations where they are executed internally in a controlled fashion. +Such visitation-based API allows for low-contention concurrent usage scenarios. + +The internal data structure of `boost::concurrent_node_map` is similar to that of +`boost::unordered_node_map`. Unlike `boost::concurrent_flat_map`, pointer stability and +node handling functionalities are provided, at the expense of potentially lower performance. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + class concurrent_node_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using init_type = std::pair< + typename std::remove_const::type, + typename std::remove_const::type + >; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using node_type = _implementation-defined_; + using insert_return_type = _implementation-defined_; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:concurrent_node_map_boost_unordered_enable_stats[enabled] + + // constants + static constexpr size_type xref:#concurrent_node_map_constants[bulk_visit_size] = _implementation-defined_; + + // construct/copy/destroy + xref:#concurrent_node_map_default_constructor[concurrent_node_map](); + explicit xref:#concurrent_node_map_bucket_count_constructor[concurrent_node_map](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#concurrent_node_map_iterator_range_constructor[concurrent_node_map](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_node_map_copy_constructor[concurrent_node_map](const concurrent_node_map& other); + xref:#concurrent_node_map_move_constructor[concurrent_node_map](concurrent_node_map&& other); + template + xref:#concurrent_node_map_iterator_range_constructor_with_allocator[concurrent_node_map](InputIterator f, InputIterator l,const allocator_type& a); + explicit xref:#concurrent_node_map_allocator_constructor[concurrent_node_map](const Allocator& a); + xref:#concurrent_node_map_copy_constructor_with_allocator[concurrent_node_map](const concurrent_node_map& other, const Allocator& a); + xref:#concurrent_node_map_move_constructor_with_allocator[concurrent_node_map](concurrent_node_map&& other, const Allocator& a); + xref:#concurrent_node_map_move_constructor_from_unordered_node_map[concurrent_node_map](unordered_node_map&& other); + xref:#concurrent_node_map_initializer_list_constructor[concurrent_node_map](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_node_map_bucket_count_constructor_with_allocator[concurrent_node_map](size_type n, const allocator_type& a); + xref:#concurrent_node_map_bucket_count_constructor_with_hasher_and_allocator[concurrent_node_map](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#concurrent_node_map_iterator_range_constructor_with_bucket_count_and_allocator[concurrent_node_map](InputIterator f, InputIterator l, size_type n, + const allocator_type& a); + template + xref:#concurrent_node_map_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_node_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_node_map_initializer_list_constructor_with_allocator[concurrent_node_map](std::initializer_list il, const allocator_type& a); + xref:#concurrent_node_map_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_map](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#concurrent_node_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_node_map](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_node_map_destructor[~concurrent_node_map](); + concurrent_node_map& xref:#concurrent_node_map_copy_assignment[operator++=++](const concurrent_node_map& other); + concurrent_node_map& xref:#concurrent_node_map_move_assignment[operator++=++](concurrent_node_map&& other) ++noexcept( + (boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value);++ + concurrent_node_map& xref:#concurrent_node_map_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#concurrent_node_map_get_allocator[get_allocator]() const noexcept; + + + // visitation + template size_t xref:#concurrent_node_map_cvisit[visit](const key_type& k, F f); + template size_t xref:#concurrent_node_map_cvisit[visit](const key_type& k, F f) const; + template size_t xref:#concurrent_node_map_cvisit[cvisit](const key_type& k, F f) const; + template size_t xref:#concurrent_node_map_cvisit[visit](const K& k, F f); + template size_t xref:#concurrent_node_map_cvisit[visit](const K& k, F f) const; + template size_t xref:#concurrent_node_map_cvisit[cvisit](const K& k, F f) const; + + template + size_t xref:concurrent_node_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f); + template + size_t xref:concurrent_node_map_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const; + template + size_t xref:concurrent_node_map_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const; + + template size_t xref:#concurrent_node_map_cvisit_all[visit_all](F f); + template size_t xref:#concurrent_node_map_cvisit_all[visit_all](F f) const; + template size_t xref:#concurrent_node_map_cvisit_all[cvisit_all](F f) const; + template + void xref:#concurrent_node_map_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f); + template + void xref:#concurrent_node_map_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f) const; + template + void xref:#concurrent_node_map_parallel_cvisit_all[cvisit_all](ExecutionPolicy&& policy, F f) const; + + template bool xref:#concurrent_node_map_cvisit_while[visit_while](F f); + template bool xref:#concurrent_node_map_cvisit_while[visit_while](F f) const; + template bool xref:#concurrent_node_map_cvisit_while[cvisit_while](F f) const; + template + bool xref:#concurrent_node_map_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f); + template + bool xref:#concurrent_node_map_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f) const; + template + bool xref:#concurrent_node_map_parallel_cvisit_while[cvisit_while](ExecutionPolicy&& policy, F f) const; + + // capacity + ++[[nodiscard]]++ bool xref:#concurrent_node_map_empty[empty]() const noexcept; + size_type xref:#concurrent_node_map_size[size]() const noexcept; + size_type xref:#concurrent_node_map_max_size[max_size]() const noexcept; + + // modifiers + template bool xref:#concurrent_node_map_emplace[emplace](Args&&... args); + bool xref:#concurrent_node_map_copy_insert[insert](const value_type& obj); + bool xref:#concurrent_node_map_copy_insert[insert](const init_type& obj); + bool xref:#concurrent_node_map_move_insert[insert](value_type&& obj); + bool xref:#concurrent_node_map_move_insert[insert](init_type&& obj); + template size_type xref:#concurrent_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + size_type xref:#concurrent_node_map_insert_initializer_list[insert](std::initializer_list il); + insert_return_type xref:#concurrent_node_map_insert_node[insert](node_type&& nh); + + template bool xref:#concurrent_node_map_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f); + template bool xref:#concurrent_node_map_emplace_or_cvisit[emplace_or_cvisit](Args&&... args, F&& f); + template bool xref:#concurrent_node_map_copy_insert_or_cvisit[insert_or_visit](const value_type& obj, F f); + template bool xref:#concurrent_node_map_copy_insert_or_cvisit[insert_or_cvisit](const value_type& obj, F f); + template bool xref:#concurrent_node_map_copy_insert_or_cvisit[insert_or_visit](const init_type& obj, F f); + template bool xref:#concurrent_node_map_copy_insert_or_cvisit[insert_or_cvisit](const init_type& obj, F f); + template bool xref:#concurrent_node_map_move_insert_or_cvisit[insert_or_visit](value_type&& obj, F f); + template bool xref:#concurrent_node_map_move_insert_or_cvisit[insert_or_cvisit](value_type&& obj, F f); + template bool xref:#concurrent_node_map_move_insert_or_cvisit[insert_or_visit](init_type&& obj, F f); + template bool xref:#concurrent_node_map_move_insert_or_cvisit[insert_or_cvisit](init_type&& obj, F f); + template + size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); + template + size_type xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); + template size_type xref:#concurrent_node_map_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list il, F f); + template insert_return_type xref:#concurrent_node_map_insert_node_or_visit[insert_or_visit](node_type&& nh, F f); + template insert_return_type xref:#concurrent_node_map_insert_node_or_visit[insert_or_cvisit](node_type&& nh, F f); + + template + bool xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2); + template bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_visit](const init_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_copy_insert_and_cvisit[insert_and_cvisit](const init_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_visit](init_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_map_move_insert_and_cvisit[insert_and_cvisit](init_type&& obj, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_map_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list il, F1 f1, F2 f2); + template + insert_return_type xref:#concurrent_node_map_insert_node_and_visit[insert_and_visit](node_type&& nh, F1 f1, F2 f2); + template + insert_return_type xref:#concurrent_node_map_insert_node_and_visit[insert_and_cvisit](node_type&& nh, F1 f1, F2 f2); + + template bool xref:#concurrent_node_map_try_emplace[try_emplace](const key_type& k, Args&&... args); + template bool xref:#concurrent_node_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template bool xref:#concurrent_node_map_try_emplace[try_emplace](K&& k, Args&&... args); + + template + bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_visit](const key_type& k, Args&&... args, F&& f); + template + bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_cvisit](const key_type& k, Args&&... args, F&& f); + template + bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_visit](key_type&& k, Args&&... args, F&& f); + template + bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_cvisit](key_type&& k, Args&&... args, F&& f); + template + bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_visit](K&& k, Args&&... args, F&& f); + template + bool xref:#concurrent_node_map_try_emplace_or_cvisit[try_emplace_or_cvisit](K&& k, Args&&... args, F&& f); + + template + bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_visit](const key_type& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_cvisit](const key_type& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_visit](key_type&& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_cvisit](key_type&& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_visit](K&& k, Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_map_try_emplace_and_cvisit[try_emplace_and_cvisit](K&& k, Args&&... args, F1&& f1, F2&& f2); + + + template bool xref:#concurrent_node_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); + template bool xref:#concurrent_node_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template bool xref:#concurrent_node_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); + + size_type xref:#concurrent_node_map_erase[erase](const key_type& k); + template size_type xref:#concurrent_node_map_erase[erase](const K& k); + + template size_type xref:#concurrent_node_map_erase_if_by_key[erase_if](const key_type& k, F f); + template size_type xref:#concurrent_node_map_erase_if_by_key[erase_if](const K& k, F f); + template size_type xref:#concurrent_node_map_erase_if[erase_if](F f); + template void xref:#concurrent_node_map_parallel_erase_if[erase_if](ExecutionPolicy&& policy, F f); + + void xref:#concurrent_node_map_swap[swap](concurrent_node_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + + node_type xref:#concurrent_node_map_extract[extract](const key_type& k); + template node_type xref:#concurrent_node_map_extract[extract](const K& k); + + template node_type xref:#concurrent_node_map_extract_if[extract_if](const key_type& k, F f); + template node_type xref:#concurrent_node_map_extract[extract_if](const K& k, F f); + + void xref:#concurrent_node_map_clear[clear]() noexcept; + + template + size_type xref:#concurrent_node_map_merge[merge](concurrent_node_map& source); + template + size_type xref:#concurrent_node_map_merge[merge](concurrent_node_map&& source); + + // observers + hasher xref:#concurrent_node_map_hash_function[hash_function]() const; + key_equal xref:#concurrent_node_map_key_eq[key_eq]() const; + + // map operations + size_type xref:#concurrent_node_map_count[count](const key_type& k) const; + template + size_type xref:#concurrent_node_map_count[count](const K& k) const; + bool xref:#concurrent_node_map_contains[contains](const key_type& k) const; + template + bool xref:#concurrent_node_map_contains[contains](const K& k) const; + + // bucket interface + size_type xref:#concurrent_node_map_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#concurrent_node_map_load_factor[load_factor]() const noexcept; + float xref:#concurrent_node_map_max_load_factor[max_load_factor]() const noexcept; + void xref:#concurrent_node_map_set_max_load_factor[max_load_factor](float z); + size_type xref:#concurrent_node_map_max_load[max_load]() const noexcept; + void xref:#concurrent_node_map_rehash[rehash](size_type n); + void xref:#concurrent_node_map_reserve[reserve](size_type n); + + // statistics (if xref:concurrent_node_map_boost_unordered_enable_stats[enabled]) + stats xref:#concurrent_node_map_get_stats[get_stats]() const; + void xref:#concurrent_node_map_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + concurrent_node_map(InputIterator, InputIterator, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type = xref:#concurrent_node_map_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_node_map, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__], Hash, + Pred, Allocator>; + + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + concurrent_node_map(std::initializer_list>, + typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type = xref:#concurrent_node_map_deduction_guides[__see below__], Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> concurrent_node_map; + + template + concurrent_node_map(InputIterator, InputIterator, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_node_map, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_map(InputIterator, InputIterator, Allocator) + -> concurrent_node_map, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_map(InputIterator, InputIterator, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> concurrent_node_map, xref:#concurrent_node_map_iter_mapped_type[__iter-mapped-type__], Hash, + std::equal_to>, Allocator>; + + template + concurrent_node_map(std::initializer_list>, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, + Allocator) + -> concurrent_node_map, std::equal_to, Allocator>; + + template + concurrent_node_map(std::initializer_list>, Allocator) + -> concurrent_node_map, std::equal_to, Allocator>; + + template + concurrent_node_map(std::initializer_list>, typename xref:#concurrent_node_map_deduction_guides[__see below__]::size_type, + Hash, Allocator) + -> concurrent_node_map, Allocator>; + + // Equality Comparisons + template + bool xref:#concurrent_node_map_operator[operator==](const concurrent_node_map& x, + const concurrent_node_map& y); + + template + bool xref:#concurrent_node_map_operator_2[operator!=](const concurrent_node_map& x, + const concurrent_node_map& y); + + // swap + template + void xref:#concurrent_node_map_swap_2[swap](concurrent_node_map& x, + concurrent_node_map& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename concurrent_node_map::size_type + xref:#concurrent_node_map_erase_if_2[erase_if](concurrent_node_map& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using concurrent_node_map = + boost::concurrent_node_map>>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +.2+|`std::pair` must be https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] +into the table from any `std::pair` object convertible to it, and it also must be +https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the table. + +|_T_ + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the table's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The element nodes of the table are held into an internal _bucket array_. An node is inserted into a bucket determined by +the hash code of its element, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the table (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Concurrency Requirements and Guarantees + +Concurrent invocations of `operator()` on the same const instance of `Hash` or `Pred` are required +to not introduce data races. For `Alloc` being either `Allocator` or any allocator type rebound +from `Allocator`, concurrent invocations of the following operations on the same instance `al` of `Alloc` +are required to not introduce data races: + +* Copy construction from `al` of an allocator rebound from `Alloc` +* `std::allocator_traits::allocate` +* `std::allocator_traits::deallocate` +* `std::allocator_traits::construct` +* `std::allocator_traits::destroy` + +In general, these requirements on `Hash`, `Pred` and `Allocator` are met if these types +are not stateful or if the operations only involve constant access to internal data members. + +With the exception of destruction, concurrent invocations of any operation on the same instance of a +`concurrent_node_map` do not introduce data races — that is, they are thread-safe. + +If an operation *op* is explicitly designated as _blocking on_ `x`, where `x` is an instance of a `boost::concurrent_node_map`, +prior blocking operations on `x` synchronize with *op*. So, blocking operations on the same +`concurrent_node_map` execute sequentially in a multithreaded scenario. + +An operation is said to be _blocking on rehashing of_ ``__x__`` if it blocks on `x` +only when an internal rehashing is issued. + +When executed internally by a `boost::concurrent_node_map`, the following operations by a +user-provided visitation function on the element passed do not introduce data races: + +* Read access to the element. +* Non-mutable modification of the element. +* Mutable modification of the element: + ** Within a container function accepting two visitation functions, always for the first function. + ** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function. + +Any `boost::concurrent_node_map operation` that inserts or modifies an element `e` +synchronizes with the internal invocation of a visitation function on `e`. + +Visitation functions executed by a `boost::concurrent_node_map` `x` are not allowed to invoke any operation +on `x`; invoking operations on a different `boost::concurrent_node_map` instance `y` is allowed only +if concurrent outstanding operations on `y` do not access `x` directly or indirectly. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK` + +In debug builds (more precisely, when +link:../../../assert/doc/html/assert.html#boost_assert_is_void[`BOOST_ASSERT_IS_VOID`^] +is not defined), __container reentrancies__ (illegaly invoking an operation on `m` from within +a function visiting elements of `m`) are detected and signalled through `BOOST_ASSERT_MSG`. +When run-time speed is a concern, the feature can be disabled by globally defining +this macro. + +--- + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the table. Note +that this option decreases the overall performance of many operations. + +--- + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +A class for holding extracted table elements, modelling +https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle]. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ insert_return_type; +---- + +A specialization of an internal class template: + +[source,c++,subs=+quotes] +---- +template +struct _insert_return_type_ // name is exposition only +{ + bool inserted; + NodeType node; +}; +---- + +with `NodeType` = `node_type`. + +--- + +=== Constants + +```cpp +static constexpr size_type bulk_visit_size; +``` + +Chunk size internally used in xref:concurrent_node_map_bulk_visit[bulk visit] operations. + +--- + +=== Constructors + +==== Default Constructor +```c++ +concurrent_node_map(); +``` + +Constructs an empty table using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit concurrent_node_map(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + concurrent_node_map(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +concurrent_node_map(concurrent_node_map const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor +```c++ +concurrent_node_map(concurrent_node_map&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new table. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + concurrent_node_map(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty table using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit concurrent_node_map(Allocator const& a); +``` + +Constructs an empty table, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +concurrent_node_map(concurrent_node_map const& other, Allocator const& a); +``` + +Constructs a table, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor with Allocator +```c++ +concurrent_node_map(concurrent_node_map&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the elements of `other` are transferred directly to the new table; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:concurrent_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor from unordered_node_map + +```c++ +concurrent_node_map(unordered_node_map&& other); +``` + +Move construction from a xref:#unordered_node_map[`unordered_node_map`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; O(`bucket_count()`) + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +concurrent_node_map(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +concurrent_node_map(size_type n, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +concurrent_node_map(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + concurrent_node_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + concurrent_node_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +concurrent_node_map(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +concurrent_node_map(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +concurrent_node_map(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~concurrent_node_map(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +concurrent_node_map& operator=(concurrent_node_map const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Move Assignment +```c++ +concurrent_node_map& operator=(concurrent_node_map&& other) + noexcept((boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to `*this`; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:concurrent_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Initializer List Assignment +```c++ +concurrent_node_map& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this`. + +--- + +=== Visitation + +==== [c]visit + +```c++ +template size_t visit(const key_type& k, F f); +template size_t visit(const key_type& k, F f) const; +template size_t cvisit(const key_type& k, F f) const; +template size_t visit(const K& k, F f); +template size_t visit(const K& k, F f) const; +template size_t cvisit(const K& k, F f) const; +``` + +If an element `x` exists with key equivalent to `k`, invokes `f` with a reference to `x`. +Such reference is const iff `*this` is const. + +[horizontal] +Returns:;; The number of elements visited (0 or 1). +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Bulk visit + +```c++ +template + size_t visit(FwdIterator first, FwdIterator last, F f); +template + size_t visit(FwdIterator first, FwdIterator last, F f) const; +template + size_t cvisit(FwdIterator first, FwdIterator last, F f) const; +``` + +For each element `k` in the range [`first`, `last`), +if there is an element `x` in the container with key equivalent to `k`, +invokes `f` with a reference to `x`. +Such reference is const iff `*this` is const. + +Although functionally equivalent to individually invoking +xref:concurrent_node_map_cvisit[`[c\]visit`] for each key, bulk visitation +performs generally faster due to internal streamlining optimizations. +It is advisable that `std::distance(first,last)` be at least +xref:#concurrent_node_map_constants[`bulk_visit_size`] to enjoy +a performance gain: beyond this size, performance is not expected +to increase further. + +[horizontal] +Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^] +({cpp}11 to {cpp}17), +or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later). +For `K` = `std::iterator_traits::value_type`, either `K` is `key_type` or +else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. +In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. +This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +Returns:;; The number of elements visited. + +--- + +==== [c]visit_all + +```c++ +template size_t visit_all(F f); +template size_t visit_all(F f) const; +template size_t cvisit_all(F f) const; +``` + +Successively invokes `f` with references to each of the elements in the table. +Such references are const iff `*this` is const. + +[horizontal] +Returns:;; The number of elements visited. + +--- + +==== Parallel [c]visit_all + +```c++ +template void visit_all(ExecutionPolicy&& policy, F f); +template void visit_all(ExecutionPolicy&& policy, F f) const; +template void cvisit_all(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with references to each of the elements in the table. Such references are const iff `*this` is const. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== [c]visit_while + +```c++ +template bool visit_while(F f); +template bool visit_while(F f) const; +template bool cvisit_while(F f) const; +``` + +Successively invokes `f` with references to each of the elements in the table until `f` returns `false` +or all the elements are visited. +Such references to the elements are const iff `*this` is const. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. + +--- + +==== Parallel [c]visit_while + +```c++ +template bool visit_while(ExecutionPolicy&& policy, F f); +template bool visit_while(ExecutionPolicy&& policy, F f) const; +template bool cvisit_while(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with references to each of the elements in the table until `f` returns `false` +or all the elements are visited. +Such references to the elements are const iff `*this` is const. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + ++ +Parallelization implies that execution does not necessary finish as soon as `f` returns `false`, and as a result +`f` may be invoked with further elements for which the return value is also `false`. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; The number of elements in the table. + +[horizontal] +Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true size of the table right after execution. + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible table. + +--- + +=== Modifiers + +==== emplace +```c++ +template bool emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. + +--- + +==== Copy Insert +```c++ +bool insert(const value_type& obj); +bool insert(const init_type& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; A call of the form `insert(x)`, where `x` is equally convertible to both `const value_type&` and `const init_type&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Move Insert +```c++ +bool insert(value_type&& obj); +bool insert(init_type&& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; A call of the form `insert(x)`, where `x` is equally convertible to both `value_type&&` and `init_type&&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Insert Iterator Range +```c++ +template size_type insert(InputIterator first, InputIterator last); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_node_map_emplace[emplace](*first++); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List +```c++ +size_type insert(std::initializer_list il); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_node_map_insert_iterator_range[insert](il.begin(), il.end()); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Node +```c++ +insert_return_type insert(node_type&& nh); +``` + +If `nh` is not empty, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.key()`. +`nh` is empty when the function returns. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false` and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true and `node` is empty. +* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== emplace_or_[c]visit +```c++ +template bool emplace_or_visit(Args&&... args, F&& f); +template bool emplace_or_cvisit(Args&&... args, F&& f); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff `emplace_or_cvisit` is used. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; The interface is exposition only, as C++ does not allow to declare a parameter `f` after a variadic parameter pack. + +--- + +==== Copy insert_or_[c]visit +```c++ +template bool insert_or_visit(const value_type& obj, F f); +template bool insert_or_cvisit(const value_type& obj, F f); +template bool insert_or_visit(const init_type& obj, F f); +template bool insert_or_cvisit(const init_type& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; In a call of the form `insert_or_[c]visit(obj, f)`, the overloads accepting a `const value_type&` argument participate in overload resolution +only if `std::remove_cv::type>::type` is `value_type`. + +--- + +==== Move insert_or_[c]visit +```c++ +template bool insert_or_visit(value_type&& obj, F f); +template bool insert_or_cvisit(value_type&& obj, F f); +template bool insert_or_visit(init_type&& obj, F f); +template bool insert_or_cvisit(init_type&& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; In a call of the form `insert_or_[c]visit(obj, f)`, the overloads accepting a `value_type&&` argument participate in overload resolution +only if `std::remove_reference::type` is `value_type`. + +--- + +==== Insert Iterator Range or Visit +```c++ +template + size_type insert_or_visit(InputIterator first, InputIterator last, F f); +template + size_type insert_or_cvisit(InputIterator first, InputIterator last, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_node_map_emplace_or_cvisit[emplace_or_[c\]visit](*first++, f); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List or Visit +```c++ +template size_type insert_or_visit(std::initializer_list il, F f); +template size_type insert_or_cvisit(std::initializer_list il, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_node_map_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Node or Visit +```c++ +template insert_return_type insert_or_visit(node_type&& nh, F f); +template insert_return_type insert_or_cvisit(node_type&& nh, F f); +``` + +If `nh` is empty, does nothing. +Otherwise, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.key()`. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff `insert_or_cvisit` is used. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false` and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true and `node` is empty. +* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` or call to `f`, the function has no effect. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== emplace_and_[c]visit +```c++ +template + bool emplace_and_visit(Args&&... args, F1&& f1, F2&& f2); +template + bool emplace_and_cvisit(Args&&... args, F1&& f1, F2&& f2); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff `emplace_and_cvisit` is used. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack. + +--- + +==== Copy insert_and_[c]visit +```c++ +template bool insert_and_visit(const value_type& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(const value_type& obj, F1 f1, F2 f2); +template bool insert_and_visit(const init_type& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(const init_type& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `const value_type&` argument participate in overload resolution +only if `std::remove_cv::type>::type` is `value_type`. + +--- + +==== Move insert_and_[c]visit +```c++ +template bool insert_and_visit(value_type&& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2); +template bool insert_and_visit(init_type&& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(init_type&& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; In a call of the form `insert_and_[c]visit(obj, f1, f2)`, the overloads accepting a `value_type&&` argument participate in overload resolution +only if `std::remove_reference::type` is `value_type`. + +--- + +==== Insert Iterator Range and Visit +```c++ +template + size_type insert_or_visit(InputIterator first, InputIterator last, F1 f1, F2 f2); +template + size_type insert_or_cvisit(InputIterator first, InputIterator last, F1 f2, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_node_map_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List and Visit +```c++ +template + size_type insert_and_visit(std::initializer_list il, F1 f1, F2 f2); +template + size_type insert_and_cvisit(std::initializer_list il, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_node_map_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Node and Visit +```c++ +template + insert_return_type insert_and_visit(node_type&& nh, F1 f1, F2 f2); +template + insert_return_type insert_and_cvisit(node_type&& nh, F1 f1, F2 f2); +``` + +If `nh` is empty, does nothing. +Otherwise, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.key()`, +and then invokes `f1` with a non-const reference to the newly inserted element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff `insert_or_cvisit` is used. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false` and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true and `node` is empty. +* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` or call to `f1` or `f2`, the function has no effect. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== try_emplace +```c++ +template bool try_emplace(const key_type& k, Args&&... args); +template bool try_emplace(key_type&& k, Args&&... args); +template bool try_emplace(K&& k, Args&&... args); +``` + +Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it. + +[horizontal] +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; This function is similiar to xref:#concurrent_node_map_emplace[emplace], with the difference that no `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +unlike xref:#concurrent_node_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== try_emplace_or_[c]visit +```c++ +template + bool try_emplace_or_visit(const key_type& k, Args&&... args, F&& f); +template + bool try_emplace_or_cvisit(const key_type& k, Args&&... args, F&& f); +template + bool try_emplace_or_visit(key_type&& k, Args&&... args, F&& f); +template + bool try_emplace_or_cvisit(key_type&& k, Args&&... args, F&& f); +template + bool try_emplace_or_visit(K&& k, Args&&... args, F&& f); +template + bool try_emplace_or_cvisit(K&& k, Args&&... args, F&& f); +``` + +Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it. +Otherwise, invokes `f` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; No `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first four overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// last two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +The interface is exposition only, as C++ does not allow to declare a parameter `f` after a variadic parameter pack. + +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== try_emplace_and_[c]visit +```c++ +template + bool try_emplace_and_visit(const key_type& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_cvisit(const key_type& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_visit(key_type&& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_cvisit(key_type&& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_visit(K&& k, Args&&... args, F1&& f1, F2&& f2); +template + bool try_emplace_and_cvisit(K&& k, Args&&... args, F1&& f1, F2&& f2); +``` + +Inserts an element constructed from `k` and `args` into the table if there is no existing element with key `k` contained within it, +and then invokes `f1` with a non-const reference to the newly created element. +Otherwise, invokes `f2` with a reference to the equivalent element; such reference is const iff a `*_cvisit` overload is used. + +[horizontal] +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; No `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first four overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// last two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +The interface is exposition only, as C++ does not allow to declare parameter `f1` and `f2` after a variadic parameter pack. + +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== insert_or_assign +```c++ +template bool insert_or_assign(const key_type& k, M&& obj); +template bool insert_or_assign(key_type&& k, M&& obj); +template bool insert_or_assign(K&& k, M&& obj); +``` + +Inserts a new element into the table or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the table as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +[horizontal] +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase +```c++ +size_type erase(const key_type& k); +template size_type erase(const K& k); +``` + +Erases the element with key equivalent to `k` if it exists. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if by Key +```c++ +template size_type erase_if(const key_type& k, F f); +template size_type erase_if(const K& k, F f); +``` + +Erases the element `x` with key equivalent to `k` if it exists and `f(x)` is `true`. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher`, `key_equal` or `f`. +Notes:;; The `template` overload only participates in overload resolution if `std::is_execution_policy_v>` is `false`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if +```c++ +template size_type erase_if(F f); +``` + +Successively invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `f`. + +--- + +==== Parallel erase_if +```c++ +template void erase_if(ExecutionPolicy&& policy, F f); +``` + +Invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +This overload only participates in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== swap +```c++ +void swap(concurrent_node_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the table with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the tables' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== extract +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Extracts the element with key equivalent to `k`, if it exists. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== extract_if +```c++ +template node_type extract_if(const key_type& k, F f); +template node_type extract_if(K&& k, F f); +``` + +Extracts the element `x` with key equivalent to `k`, if it exists and `f(x)` is `true`. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal` or `f`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the table. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` +Concurrency:;; Blocking on `*this`. + +--- + +==== merge +```c++ +template + size_type merge(concurrent_node_map& source); +template + size_type merge(concurrent_node_map&& source); +``` + +Move-inserts all the elements from `source` whose key is not already present in `*this`, and erases them from `source`. + +[horizontal] +Returns:;; The number of elements inserted. +Concurrency:;; Blocking on `*this` and `source`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The table's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The table's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The table's key equality predicate. + +--- + +=== Map Operations + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k` (0 or 1). +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `k` in the table. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the table's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_map`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the table can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the table's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the table. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the table. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the table so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_node_map_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the table. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_node_map_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +table type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +==== __iter-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-key-type__ = std::remove_const_t< + std::tuple_element_t<0, xref:#concurrent_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +==== __iter-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-mapped-type__ = + std::tuple_element_t<1, xref:#concurrent_map_iter_value_type[__iter-value-type__]>; // exposition only +----- + +==== __iter-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-to-alloc-type__ = std::pair< + std::add_const_t>>, + std::tuple_element_t<1, xref:#concurrent_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const concurrent_node_map& x, + const concurrent_node_map& y); +``` + +Returns `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const concurrent_node_map& x, + const concurrent_node_map& y); +``` + +Returns `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(concurrent_node_map& x, + concurrent_node_map& y) + noexcept(noexcept(x.swap(y))); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +x.xref:#concurrent_node_map_swap[swap](y); +----- + +--- + +=== erase_if +```c++ +template + typename concurrent_node_map::size_type + erase_if(concurrent_node_map& c, Predicate pred); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +c.xref:#concurrent_node_map_erase_if[erase_if](pred); +----- + +=== Serialization + +``concurrent_node_map``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an concurrent_node_map to an archive + +Saves all the elements of a `concurrent_node_map` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `std::remove_const::type` and `std::remove_const::type` +are serializable (XML serializable), and they do support Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). +Concurrency:;; Blocking on `x`. + +--- + +==== Loading an concurrent_node_map from an archive + +Deletes all preexisting elements of a `concurrent_node_map` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `concurrent_node_map` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`. +Concurrency:;; Blocking on `x`. diff --git a/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc b/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc new file mode 100644 index 00000000..9757a680 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/concurrent_node_set.adoc @@ -0,0 +1,1757 @@ +[#concurrent_node_set] +== Class Template concurrent_node_set + +:idprefix: concurrent_node_set_ + +`boost::concurrent_node_set` — A node-based hash table that stores unique values and +allows for concurrent element insertion, erasure, lookup and access +without external synchronization mechanisms. + +Even though it acts as a container, `boost::concurrent_node_set` +does not model the standard C++ https://en.cppreference.com/w/cpp/named_req/Container[Container^] concept. +In particular, iterators and associated operations (`begin`, `end`, etc.) are not provided. +Element access is done through user-provided _visitation functions_ that are passed +to `concurrent_node_set` operations where they are executed internally in a controlled fashion. +Such visitation-based API allows for low-contention concurrent usage scenarios. + +The internal data structure of `boost::concurrent_node_set` is similar to that of +`boost::unordered_node_set`. Unlike `boost::concurrent_flat_set`, pointer stability and +node handling functionalities are provided, at the expense of potentially lower performance. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator> + class concurrent_node_set { + public: + // types + using key_type = Key; + using value_type = Key; + using init_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using node_type = _implementation-defined_; + using insert_return_type = _implementation-defined_; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:concurrent_node_set_boost_unordered_enable_stats[enabled] + + // constants + static constexpr size_type xref:#concurrent_node_set_constants[bulk_visit_size] = _implementation-defined_; + + // construct/copy/destroy + xref:#concurrent_node_set_default_constructor[concurrent_node_set](); + explicit xref:#concurrent_node_set_bucket_count_constructor[concurrent_node_set](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#concurrent_node_set_iterator_range_constructor[concurrent_node_set](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_node_set_copy_constructor[concurrent_node_set](const concurrent_node_set& other); + xref:#concurrent_node_set_move_constructor[concurrent_node_set](concurrent_node_set&& other); + template + xref:#concurrent_node_set_iterator_range_constructor_with_allocator[concurrent_node_set](InputIterator f, InputIterator l,const allocator_type& a); + explicit xref:#concurrent_node_set_allocator_constructor[concurrent_node_set](const Allocator& a); + xref:#concurrent_node_set_copy_constructor_with_allocator[concurrent_node_set](const concurrent_node_set& other, const Allocator& a); + xref:#concurrent_node_set_move_constructor_with_allocator[concurrent_node_set](concurrent_node_set&& other, const Allocator& a); + xref:#concurrent_node_set_move_constructor_from_unordered_node_set[concurrent_node_set](unordered_node_set&& other); + xref:#concurrent_node_set_initializer_list_constructor[concurrent_node_set](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#concurrent_node_set_bucket_count_constructor_with_allocator[concurrent_node_set](size_type n, const allocator_type& a); + xref:#concurrent_node_set_bucket_count_constructor_with_hasher_and_allocator[concurrent_node_set](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#concurrent_node_set_iterator_range_constructor_with_bucket_count_and_allocator[concurrent_node_set](InputIterator f, InputIterator l, size_type n, + const allocator_type& a); + template + xref:#concurrent_node_set_iterator_range_constructor_with_bucket_count_and_hasher[concurrent_node_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_node_set_initializer_list_constructor_with_allocator[concurrent_node_set](std::initializer_list il, const allocator_type& a); + xref:#concurrent_node_set_initializer_list_constructor_with_bucket_count_and_allocator[concurrent_node_set](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#concurrent_node_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[concurrent_node_set](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#concurrent_node_set_destructor[~concurrent_node_set](); + concurrent_node_set& xref:#concurrent_node_set_copy_assignment[operator++=++](const concurrent_node_set& other); + concurrent_node_set& xref:#concurrent_node_set_move_assignment[operator++=++](concurrent_node_set&& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value); + concurrent_node_set& xref:#concurrent_node_set_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#concurrent_node_set_get_allocator[get_allocator]() const noexcept; + + + // visitation + template size_t xref:#concurrent_node_set_cvisit[visit](const key_type& k, F f); + template size_t xref:#concurrent_node_set_cvisit[visit](const key_type& k, F f) const; + template size_t xref:#concurrent_node_set_cvisit[cvisit](const key_type& k, F f) const; + template size_t xref:#concurrent_node_set_cvisit[visit](const K& k, F f); + template size_t xref:#concurrent_node_set_cvisit[visit](const K& k, F f) const; + template size_t xref:#concurrent_node_set_cvisit[cvisit](const K& k, F f) const; + + template + size_t xref:concurrent_node_set_bulk_visit[visit](FwdIterator first, FwdIterator last, F f); + template + size_t xref:concurrent_node_set_bulk_visit[visit](FwdIterator first, FwdIterator last, F f) const; + template + size_t xref:concurrent_node_set_bulk_visit[cvisit](FwdIterator first, FwdIterator last, F f) const; + + template size_t xref:#concurrent_node_set_cvisit_all[visit_all](F f); + template size_t xref:#concurrent_node_set_cvisit_all[visit_all](F f) const; + template size_t xref:#concurrent_node_set_cvisit_all[cvisit_all](F f) const; + template + void xref:#concurrent_node_set_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f); + template + void xref:#concurrent_node_set_parallel_cvisit_all[visit_all](ExecutionPolicy&& policy, F f) const; + template + void xref:#concurrent_node_set_parallel_cvisit_all[cvisit_all](ExecutionPolicy&& policy, F f) const; + + template bool xref:#concurrent_node_set_cvisit_while[visit_while](F f); + template bool xref:#concurrent_node_set_cvisit_while[visit_while](F f) const; + template bool xref:#concurrent_node_set_cvisit_while[cvisit_while](F f) const; + template + bool xref:#concurrent_node_set_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f); + template + bool xref:#concurrent_node_set_parallel_cvisit_while[visit_while](ExecutionPolicy&& policy, F f) const; + template + bool xref:#concurrent_node_set_parallel_cvisit_while[cvisit_while](ExecutionPolicy&& policy, F f) const; + + // capacity + ++[[nodiscard]]++ bool xref:#concurrent_node_set_empty[empty]() const noexcept; + size_type xref:#concurrent_node_set_size[size]() const noexcept; + size_type xref:#concurrent_node_set_max_size[max_size]() const noexcept; + + // modifiers + template bool xref:#concurrent_node_set_emplace[emplace](Args&&... args); + bool xref:#concurrent_node_set_copy_insert[insert](const value_type& obj); + bool xref:#concurrent_node_set_move_insert[insert](value_type&& obj); + template bool xref:#concurrent_node_set_transparent_insert[insert](K&& k); + template size_type xref:#concurrent_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + size_type xref:#concurrent_node_set_insert_initializer_list[insert](std::initializer_list il); + insert_return_type xref:#concurrent_node_set_insert_node[insert](node_type&& nh); + + template bool xref:#concurrent_node_set_emplace_or_cvisit[emplace_or_visit](Args&&... args, F&& f); + template bool xref:#concurrent_node_set_emplace_or_cvisit[emplace_or_cvisit](Args&&... args, F&& f); + template bool xref:#concurrent_node_set_copy_insert_or_cvisit[insert_or_visit](const value_type& obj, F f); + template bool xref:#concurrent_node_set_copy_insert_or_cvisit[insert_or_cvisit](const value_type& obj, F f); + template bool xref:#concurrent_node_set_move_insert_or_cvisit[insert_or_visit](value_type&& obj, F f); + template bool xref:#concurrent_node_set_move_insert_or_cvisit[insert_or_cvisit](value_type&& obj, F f); + template bool xref:#concurrent_node_set_transparent_insert_or_cvisit[insert_or_visit](K&& k, F f); + template bool xref:#concurrent_node_set_transparent_insert_or_cvisit[insert_or_cvisit](K&& k, F f); + template + size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_visit](InputIterator first, InputIterator last, F f); + template + size_type xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_cvisit](InputIterator first, InputIterator last, F f); + template size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_visit](std::initializer_list il, F f); + template size_type xref:#concurrent_node_set_insert_initializer_list_or_visit[insert_or_cvisit](std::initializer_list il, F f); + template insert_return_type xref:#concurrent_node_set_insert_node_or_visit[insert_or_visit](node_type&& nh, F f); + template insert_return_type xref:#concurrent_node_set_insert_node_or_visit[insert_or_cvisit](node_type&& nh, F f); + + template + bool xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_visit](Args&&... args, F1&& f1, F2&& f2); + template + bool xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_cvisit](Args&&... args, F1&& f1, F2&& f2); + template bool xref:#concurrent_node_set_copy_insert_and_cvisit[insert_and_visit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_set_copy_insert_and_cvisit[insert_and_cvisit](const value_type& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_set_move_insert_and_cvisit[insert_and_visit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_set_move_insert_and_cvisit[insert_and_cvisit](value_type&& obj, F1 f1, F2 f2); + template bool xref:#concurrent_node_set_transparent_insert_and_cvisit[insert_and_visit](K&& k, F1 f1, F2 f2); + template bool xref:#concurrent_node_set_transparent_insert_and_cvisit[insert_and_cvisit](K&& k, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_visit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_cvisit](InputIterator first, InputIterator last, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_visit](std::initializer_list il, F1 f1, F2 f2); + template + size_type xref:#concurrent_node_set_insert_initializer_list_and_visit[insert_and_cvisit](std::initializer_list il, F1 f1, F2 f2); + template + insert_return_type xref:#concurrent_node_set_insert_node_and_visit[insert_and_visit](node_type&& nh, F1 f1, F2 f2); + template + insert_return_type xref:#concurrent_node_set_insert_node_and_visit[insert_and_cvisit](node_type&& nh, F1 f1, F2 f2); + + size_type xref:#concurrent_node_set_erase[erase](const key_type& k); + template size_type xref:#concurrent_node_set_erase[erase](const K& k); + + template size_type xref:#concurrent_node_set_erase_if_by_key[erase_if](const key_type& k, F f); + template size_type xref:#concurrent_node_set_erase_if_by_key[erase_if](const K& k, F f); + template size_type xref:#concurrent_node_set_erase_if[erase_if](F f); + template void xref:#concurrent_node_set_parallel_erase_if[erase_if](ExecutionPolicy&& policy, F f); + + void xref:#concurrent_node_set_swap[swap](concurrent_node_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + + node_type xref:#concurrent_node_set_extract[extract](const key_type& k); + template node_type xref:#concurrent_node_set_extract[extract](const K& k); + + template node_type xref:#concurrent_node_set_extract_if[extract_if](const key_type& k, F f); + template node_type xref:#concurrent_node_set_extract[extract_if](const K& k, F f); + + void xref:#concurrent_node_set_clear[clear]() noexcept; + + template + size_type xref:#concurrent_node_set_merge[merge](concurrent_node_set& source); + template + size_type xref:#concurrent_node_set_merge[merge](concurrent_node_set&& source); + + // observers + hasher xref:#concurrent_node_set_hash_function[hash_function]() const; + key_equal xref:#concurrent_node_set_key_eq[key_eq]() const; + + // set operations + size_type xref:#concurrent_node_set_count[count](const key_type& k) const; + template + size_type xref:#concurrent_node_set_count[count](const K& k) const; + bool xref:#concurrent_node_set_contains[contains](const key_type& k) const; + template + bool xref:#concurrent_node_set_contains[contains](const K& k) const; + + // bucket interface + size_type xref:#concurrent_node_set_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#concurrent_node_set_load_factor[load_factor]() const noexcept; + float xref:#concurrent_node_set_max_load_factor[max_load_factor]() const noexcept; + void xref:#concurrent_node_set_set_max_load_factor[max_load_factor](float z); + size_type xref:#concurrent_node_set_max_load[max_load]() const noexcept; + void xref:#concurrent_node_set_rehash[rehash](size_type n); + void xref:#concurrent_node_set_reserve[reserve](size_type n); + + // statistics (if xref:concurrent_node_set_boost_unordered_enable_stats[enabled]) + stats xref:#concurrent_node_set_get_stats[get_stats]() const; + void xref:#concurrent_node_set_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + concurrent_node_set(InputIterator, InputIterator, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type = xref:#concurrent_node_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_node_set, Hash, Pred, Allocator>; + + template, class Pred = std::equal_to, + class Allocator = std::allocator> + concurrent_node_set(std::initializer_list, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type = xref:#concurrent_node_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> concurrent_node_set; + + template + concurrent_node_set(InputIterator, InputIterator, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_set(InputIterator, InputIterator, Allocator) + -> concurrent_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + concurrent_node_set(InputIterator, InputIterator, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> concurrent_node_set, Hash, + std::equal_to>, Allocator>; + + template + concurrent_node_set(std::initializer_list, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Allocator) + -> concurrent_node_set, std::equal_to, Allocator>; + + template + concurrent_node_set(std::initializer_list, Allocator) + -> concurrent_node_set, std::equal_to, Allocator>; + + template + concurrent_node_set(std::initializer_list, typename xref:#concurrent_node_set_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> concurrent_node_set, Allocator>; + + // Equality Comparisons + template + bool xref:#concurrent_node_set_operator[operator==](const concurrent_node_set& x, + const concurrent_node_set& y); + + template + bool xref:#concurrent_node_set_operator_2[operator!=](const concurrent_node_set& x, + const concurrent_node_set& y); + + // swap + template + void xref:#concurrent_node_set_swap_2[swap](concurrent_node_set& x, + concurrent_node_set& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename concurrent_node_set::size_type + xref:#concurrent_node_set_erase_if_2[erase_if](concurrent_node_set& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using concurrent_node_set = + boost::concurrent_node_set>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^] into the container +and https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container. + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the table's value type. +`std::allocator_traits::pointer` and `std::allocator_traits::const_pointer` +must be convertible to/from `value_type*` and `const value_type*`, respectively. + +|=== + +The element nodes of the table are held into an internal _bucket array_. An node is inserted into a bucket determined by +the hash code of its element, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the table (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Concurrency Requirements and Guarantees + +Concurrent invocations of `operator()` on the same const instance of `Hash` or `Pred` are required +to not introduce data races. For `Alloc` being either `Allocator` or any allocator type rebound +from `Allocator`, concurrent invocations of the following operations on the same instance `al` of `Alloc` +are required to not introduce data races: + +* Copy construction from `al` of an allocator rebound from `Alloc` +* `std::allocator_traits::allocate` +* `std::allocator_traits::deallocate` +* `std::allocator_traits::construct` +* `std::allocator_traits::destroy` + +In general, these requirements on `Hash`, `Pred` and `Allocator` are met if these types +are not stateful or if the operations only involve constant access to internal data members. + +With the exception of destruction, concurrent invocations of any operation on the same instance of a +`concurrent_node_set` do not introduce data races — that is, they are thread-safe. + +If an operation *op* is explicitly designated as _blocking on_ `x`, where `x` is an instance of a `boost::concurrent_node_set`, +prior blocking operations on `x` synchronize with *op*. So, blocking operations on the same +`concurrent_node_set` execute sequentially in a multithreaded scenario. + +An operation is said to be _blocking on rehashing of_ ``__x__`` if it blocks on `x` +only when an internal rehashing is issued. + +When executed internally by a `boost::concurrent_node_set`, the following operations by a +user-provided visitation function on the element passed do not introduce data races: + +* Read access to the element. +* Non-mutable modification of the element. +* Mutable modification of the element: + ** Within a container function accepting two visitation functions, always for the first function. + ** Within a non-const container function whose name does not contain `cvisit`, for the last (or only) visitation function. + +Any `boost::concurrent_node_set operation` that inserts or modifies an element `e` +synchronizes with the internal invocation of a visitation function on `e`. + +Visitation functions executed by a `boost::concurrent_node_set` `x` are not allowed to invoke any operation +on `x`; invoking operations on a different `boost::concurrent_node_set` instance `y` is allowed only +if concurrent outstanding operations on `y` do not access `x` directly or indirectly. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_DISABLE_REENTRANCY_CHECK` + +In debug builds (more precisely, when +link:../../../assert/doc/html/assert.html#boost_assert_is_void[`BOOST_ASSERT_IS_VOID`^] +is not defined), __container reentrancies__ (illegaly invoking an operation on `m` from within +a function visiting elements of `m`) are detected and signalled through `BOOST_ASSERT_MSG`. +When run-time speed is a concern, the feature can be disabled by globally defining +this macro. + +--- + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the table. Note +that this option decreases the overall performance of many operations. + +--- + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +A class for holding extracted table elements, modelling +https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle]. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ insert_return_type; +---- + +A specialization of an internal class template: + +[source,c++,subs=+quotes] +---- +template +struct _insert_return_type_ // name is exposition only +{ + bool inserted; + NodeType node; +}; +---- + +with `NodeType` = `node_type`. + +--- + +=== Constants + +```cpp +static constexpr size_type bulk_visit_size; +``` + +Chunk size internally used in xref:concurrent_node_set_bulk_visit[bulk visit] operations. + +=== Constructors + +==== Default Constructor +```c++ +concurrent_node_set(); +``` + +Constructs an empty table using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit concurrent_node_set(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + concurrent_node_set(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +concurrent_node_set(concurrent_node_set const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor +```c++ +concurrent_node_set(concurrent_node_set&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new table. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + concurrent_node_set(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty table using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit concurrent_node_set(Allocator const& a); +``` + +Constructs an empty table, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +concurrent_node_set(concurrent_node_set const& other, Allocator const& a); +``` + +Constructs a table, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor with Allocator +```c++ +concurrent_node_set(concurrent_node_set&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the elements of `other` are transferred directly to the new table; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:concurrent_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `other`. + +--- + +==== Move Constructor from unordered_node_set + +```c++ +concurrent_node_set(unordered_node_set&& other); +``` + +Move construction from a xref:#unordered_node_set[`unordered_node_set`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:concurrent_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; O(`bucket_count()`) + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +concurrent_node_set(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +concurrent_node_set(size_type n, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +concurrent_node_set(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + concurrent_node_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + concurrent_node_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +concurrent_node_set(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty table using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +concurrent_node_set(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +concurrent_node_set(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty table with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~concurrent_node_set(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +concurrent_node_set& operator=(concurrent_node_set const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Move Assignment +```c++ +concurrent_node_set& operator=(concurrent_node_set&& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to `*this`; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:concurrent_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +[horizontal] +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== Initializer List Assignment +```c++ +concurrent_node_set& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] +Concurrency:;; Blocking on `*this`. + +--- + +=== Visitation + +==== [c]visit + +```c++ +template size_t visit(const key_type& k, F f); +template size_t visit(const key_type& k, F f) const; +template size_t cvisit(const key_type& k, F f) const; +template size_t visit(const K& k, F f); +template size_t visit(const K& k, F f) const; +template size_t cvisit(const K& k, F f) const; +``` + +If an element `x` exists with key equivalent to `k`, invokes `f` with a const reference to `x`. + +[horizontal] +Returns:;; The number of elements visited (0 or 1). +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Bulk visit + +```c++ +template + size_t visit(FwdIterator first, FwdIterator last, F f); +template + size_t visit(FwdIterator first, FwdIterator last, F f) const; +template + size_t cvisit(FwdIterator first, FwdIterator last, F f) const; +``` + +For each element `k` in the range [`first`, `last`), +if there is an element `x` in the container with key equivalent to `k`, +invokes `f` with a const reference to `x`. + +Although functionally equivalent to individually invoking +xref:concurrent_node_set_cvisit[`[c\]visit`] for each key, bulk visitation +performs generally faster due to internal streamlining optimizations. +It is advisable that `std::distance(first,last)` be at least +xref:#concurrent_node_set_constants[`bulk_visit_size`] to enjoy +a performance gain: beyond this size, performance is not expected +to increase further. + +[horizontal] +Requires:;; `FwdIterator` is a https://en.cppreference.com/w/cpp/named_req/ForwardIterator[LegacyForwardIterator^] +({cpp}11 to {cpp}17), +or satisfies https://en.cppreference.com/w/cpp/iterator/forward_iterator[std::forward_iterator^] ({cpp}20 and later). +For `K` = `std::iterator_traits::value_type`, either `K` is `key_type` or +else `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. +In the latter case, the library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. +This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +Returns:;; The number of elements visited. + +--- + +==== [c]visit_all + +```c++ +template size_t visit_all(F f); +template size_t visit_all(F f) const; +template size_t cvisit_all(F f) const; +``` + +Successively invokes `f` with const references to each of the elements in the table. + +[horizontal] +Returns:;; The number of elements visited. + +--- + +==== Parallel [c]visit_all + +```c++ +template void visit_all(ExecutionPolicy&& policy, F f); +template void visit_all(ExecutionPolicy&& policy, F f) const; +template void cvisit_all(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with const references to each of the elements in the table. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== [c]visit_while + +```c++ +template bool visit_while(F f); +template bool visit_while(F f) const; +template bool cvisit_while(F f) const; +``` + +Successively invokes `f` with const references to each of the elements in the table until `f` returns `false` +or all the elements are visited. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. + +--- + +==== Parallel [c]visit_while + +```c++ +template bool visit_while(ExecutionPolicy&& policy, F f); +template bool visit_while(ExecutionPolicy&& policy, F f) const; +template bool cvisit_while(ExecutionPolicy&& policy, F f) const; +``` + +Invokes `f` with const references to each of the elements in the table until `f` returns `false` +or all the elements are visited. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Returns:;; `false` iff `f` ever returns `false`. +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +These overloads only participate in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + ++ +Parallelization implies that execution does not necessary finish as soon as `f` returns `false`, and as a result +`f` may be invoked with further elements for which the return value is also `false`. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; The number of elements in the table. + +[horizontal] +Notes:;; In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true size of the table right after execution. + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible table. + +--- + +=== Modifiers + +==== emplace +```c++ +template bool emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Copy Insert +```c++ +bool insert(const value_type& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Move Insert +```c++ +bool insert(value_type&& obj); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Transparent Insert +```c++ +template bool insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range +```c++ +template size_type insert(InputIterator first, InputIterator last); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_node_set_emplace[emplace](*first++); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List +```c++ +size_type insert(std::initializer_list il); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_node_set_insert_iterator_range[insert](il.begin(), il.end()); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Node +```c++ +insert_return_type insert(node_type&& nh); +``` + +If `nh` is not empty, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.value()`. +`nh` is empty when the function returns. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false` and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true and `node` is empty. +* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== emplace_or_[c]visit +```c++ +template bool emplace_or_visit(Args&&... args, F&& f); +template bool emplace_or_cvisit(Args&&... args, F&& f); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; The interface is exposition only, as C++ does not allow to declare a parameter `f` after a variadic parameter pack. + +--- + +==== Copy insert_or_[c]visit +```c++ +template bool insert_or_visit(const value_type& obj, F f); +template bool insert_or_cvisit(const value_type& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Move insert_or_[c]visit +```c++ +template bool insert_or_visit(value_type&& obj, F f); +template bool insert_or_cvisit(value_type&& obj, F f); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Transparent insert_or_[c]visit +```c++ +template bool insert_or_visit(K&& k, F f); +template bool insert_or_cvisit(K&& k, F f); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; These overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range or Visit +```c++ +template + size_type insert_or_visit(InputIterator first, InputIterator last, F f); +template + size_type insert_or_cvisit(InputIterator first, InputIterator last, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_node_set_emplace_or_cvisit[emplace_or_[c\]visit](*first++, f); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List or Visit +```c++ +template size_type insert_or_visit(std::initializer_list il, F f); +template size_type insert_or_cvisit(std::initializer_list il, F f); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_node_set_insert_iterator_range_or_visit[insert_or_[c\]visit](il.begin(), il.end(), std::ref(f)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Node or Visit +```c++ +template insert_return_type insert_or_visit(node_type&& nh, F f); +template insert_return_type insert_or_cvisit(node_type&& nh, F f); +``` + +If `nh` is empty, does nothing. +Otherwise, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.value()`. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false` and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true and `node` is empty. +* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` or call to `f`, the function has no effect. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== emplace_and_[c]visit +```c++ +template + bool emplace_or_visit(Args&&... args, F1&& f1, F2&& f2); +template + bool emplace_or_cvisit(Args&&... args, F1&& f1, F2&& f2); +``` + +Inserts an object, constructed with the arguments `args`, in the table if there is no element in the table with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; The interface is exposition only, as C++ does not allow to declare parameters `f1` and `f2` after a variadic parameter pack. + +--- + +==== Copy insert_and_[c]visit +```c++ +template bool insert_and_visit(const value_type& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(const value_type& obj, F1 f2, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Move insert_and_[c]visit +```c++ +template bool insert_and_visit(value_type&& obj, F1 f1, F2 f2); +template bool insert_and_cvisit(value_type&& obj, F1 f1, F2 f2); +``` + +Inserts `obj` in the table if and only if there is no element in the table with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; `true` if an insert took place. + +Concurrency:;; Blocking on rehashing of `*this`. + +--- + +==== Transparent insert_and_[c]visit +```c++ +template bool insert_and_visit(K&& k, F1 f1, F2 f2); +template bool insert_and_cvisit(K&& k, F1 f1, F2 f2); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key, +and then invokes `f1` with a const reference to the newly created element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; `true` if an insert took place. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; These overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range and Visit +```c++ +template + size_type insert_and_visit(InputIterator first, InputIterator last, F1 f1, F2 f2); +template + size_type insert_and_cvisit(InputIterator first, InputIterator last, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + while(first != last) this->xref:#concurrent_node_set_emplace_and_cvisit[emplace_and_[c\]visit](*first++, f1, f2); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Initializer List and Visit +```c++ +template + size_type insert_and_visit(std::initializer_list il, F1 f1, F2 f2); +template + size_type insert_and_cvisit(std::initializer_list il, F1 f1, F2 f2); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- + this->xref:#concurrent_node_set_insert_iterator_range_and_visit[insert_and_[c\]visit](il.begin(), il.end(), std::ref(f1), std::ref(f2)); +----- + +[horizontal] +Returns:;; The number of elements inserted. + +--- + +==== Insert Node and Visit +```c++ +template + insert_return_type insert_and_visit(node_type&& nh, F1 f1, F2 f2); +template + insert_return_type insert_and_cvisit(node_type&& nh, F1 f1, F2 f2); +``` + +If `nh` is empty, does nothing. +Otherwise, inserts the associated element in the table if and only if there is no element in the table with a key equivalent to `nh.value()`, +and then invokes `f1` with a const reference to the newly inserted element. +Otherwise, invokes `f2` with a const reference to the equivalent element. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false` and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true and `node` is empty. +* If the insertion failed, `inserted` is false and `node` has the previous value of `nh`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` or call to `f1` or `f2`, the function has no effect. +Concurrency:;; Blocking on rehashing of `*this`. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== erase +```c++ +size_type erase(const key_type& k); +template size_type erase(const K& k); +``` + +Erases the element with key equivalent to `k` if it exists. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if by Key +```c++ +template size_type erase_if(const key_type& k, F f); +template size_type erase_if(const K& k, F f); +``` + +Erases the element `x` with key equivalent to `k` if it exists and `f(x)` is `true`. + +[horizontal] +Returns:;; The number of elements erased (0 or 1). +Throws:;; Only throws an exception if it is thrown by `hasher`, `key_equal` or `f`. +Notes:;; The `template` overload only participates in overload resolution if `std::is_execution_policy_v>` is `false`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== erase_if +```c++ +template size_type erase_if(F f); +``` + +Successively invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `f`. + +--- + +==== Parallel erase_if +```c++ +template void erase_if(ExecutionPolicy&& policy, F f); +``` + +Invokes `f` with references to each of the elements in the table, and erases those for which `f` returns `true`. +Execution is parallelized according to the semantics of the execution policy specified. + +[horizontal] +Throws:;; Depending on the exception handling mechanism of the execution policy used, may call `std::terminate` if an exception is thrown within `f`. +Notes:;; Only available in compilers supporting C++17 parallel algorithms. + ++ +This overload only participates in overload resolution if `std::is_execution_policy_v>` is `true`. + ++ +Unsequenced execution policies are not allowed. + +--- + +==== swap +```c++ +void swap(concurrent_node_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the table with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the tables' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. +Concurrency:;; Blocking on `*this` and `other`. + +--- + +==== extract +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Extracts the element with key equivalent to `k`, if it exists. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== extract_if +```c++ +template node_type extract_if(const key_type& k, F f); +template node_type extract_if(K&& k, F f); +``` + +Extracts the element `x` with key equivalent to `k`, if it exists and `f(x)` is `true`. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal` or `f`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the table. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` +Concurrency:;; Blocking on `*this`. + +--- + +==== merge +```c++ +template + size_type merge(concurrent_node_set& source); +template + size_type merge(concurrent_node_set&& source); +``` + +Move-inserts all the elements from `source` whose key is not already present in `*this`, and erases them from `source`. + +[horizontal] +Returns:;; The number of elements inserted. +Concurrency:;; Blocking on `*this` and `source`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The table's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The table's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The table's key equality predicate. + +--- + +=== Set Operations + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k` (0 or 1). +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `k` in the table. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the table's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_set`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the table can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the table's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + ++ +In the presence of concurrent insertion operations, the value returned may not accurately reflect +the true state of the table right after execution. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the table. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the table. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the table's hash function or comparison function. +Concurrency:;; Blocking on `*this`. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the table so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_node_set_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the table. +Notes:;; Only available if xref:stats[statistics calculation] is xref:concurrent_node_set_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const concurrent_node_set& x, + const concurrent_node_set& y); +``` + +Returns `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const concurrent_node_set& x, + const concurrent_node_set& y); +``` + +Returns `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Concurrency:;; Blocking on `x` and `y`. +Notes:;; Behavior is undefined if the two tables don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(concurrent_node_set& x, + concurrent_node_set& y) + noexcept(noexcept(x.swap(y))); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +x.xref:#concurrent_node_set_swap[swap](y); +----- + +--- + +=== erase_if +```c++ +template + typename concurrent_node_set::size_type + erase_if(concurrent_node_set& c, Predicate pred); +``` + +Equivalent to +[listing,subs="+macros,+quotes"] +----- +c.xref:#concurrent_node_set_erase_if[erase_if](pred); +----- + +=== Serialization + +``concurrent_node_set``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an concurrent_node_set to an archive + +Saves all the elements of a `concurrent_node_set` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `value_type` is serializable (XML serializable), and it supports Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). +Concurrency:;; Blocking on `x`. + +--- + +==== Loading an concurrent_node_set from an archive + +Deletes all preexisting elements of a `concurrent_node_set` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `concurrent_node_set` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`. +Concurrency:;; Blocking on `x`. diff --git a/doc/modules/ROOT/pages/reference/hash_traits.adoc b/doc/modules/ROOT/pages/reference/hash_traits.adoc new file mode 100644 index 00000000..5a60fa82 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/hash_traits.adoc @@ -0,0 +1,51 @@ +[#hash_traits] +== Hash traits + +:idprefix: hash_traits_ + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { +namespace unordered { + +template +struct xref:#hash_traits_hash_is_avalanching[hash_is_avalanching]; + +} // namespace unordered +} // namespace boost +----- + +--- + +=== hash_is_avalanching +```c++ +template +struct hash_is_avalanching; +``` + +A hash function is said to have the _avalanching property_ if small changes in the input translate to +large changes in the returned hash code —ideally, flipping one bit in the representation of +the input value results in each bit of the hash code flipping with probability 50%. Approaching +this property is critical for the proper behavior of open-addressing hash containers. + +`hash_is_avalanching::value` is: + + * `false` if `Hash::is_avalanching` is not present, + * `Hash::is_avalanching::value` if this is present and convertible at compile time to a `bool`, + * `true` if `Hash::is_avalanching` is `void` (this usage is deprecated), + * ill-formed otherwise. + +Users can then declare a hash function `Hash` as avalanching either by embedding an appropriate `is_avalanching` typedef +into the definition of `Hash`, or directly by specializing `hash_is_avalanching` to a class with +an embedded compile-time constant `value` set to `true`. + +Open-addressing and concurrent containers +use the provided hash function `Hash` as-is if `hash_is_avalanching::value` is `true`; otherwise, they +implement a bit-mixing post-processing stage to increase the quality of hashing at the expense of +extra computational cost. + +--- diff --git a/doc/modules/ROOT/pages/reference/stats.adoc b/doc/modules/ROOT/pages/reference/stats.adoc new file mode 100644 index 00000000..944b6069 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/stats.adoc @@ -0,0 +1,71 @@ +[#stats] +== Statistics + +:idprefix: stats_ + +Open-addressing and concurrent containers can be configured to keep running statistics +of some internal operations affected by the quality of the supplied hash function. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +struct xref:#stats_stats_summary_type[__stats-summary-type__] +{ + double average; + double variance; + double deviation; +}; + +struct xref:#stats_insertion_stats_type[__insertion-stats-type__] +{ + std::size_t count; + xref:#stats_stats_summary_type[__stats-summary-type__] probe_length; +}; + +struct xref:stats_lookup_stats_type[__lookup-stats-type__] +{ + std::size_t count; + xref:#stats_stats_summary_type[__stats-summary-type__] probe_length; + xref:#stats_stats_summary_type[__stats-summary-type__] num_comparisons; +}; + +struct xref:stats_stats_type[__stats-type__] +{ + xref:#stats_insertion_stats_type[__insertion-stats-type__] insertion; + xref:stats_lookup_stats_type[__lookup-stats-type__] successful_lookup, + unsuccessful_lookup; +}; +----- + +==== __stats-summary-type__ + +Provides the average value, variance and standard deviation of a sequence of numerical values. + +==== __insertion-stats-type__ + +Provides the number of insertion operations performed by a container and +statistics on the associated __probe length__ (number of +xref:#structures_open_addressing_containers[bucket groups] accessed per operation). + +==== __lookup-stats-type__ + +For successful (element found) or unsuccessful (not found) lookup, +provides the number of operations performed by a container and +statistics on the associated __probe length__ (number of +xref:#structures_open_addressing_containers[bucket groups] accessed) +and number of element comparisons per operation. + +==== __stats-type__ + +Provides statistics on insertion, successful and unsuccessful lookups performed by a container. +If the supplied hash function has good quality, then: + +* Average probe lenghts should be close to 1.0. +* For successful lookups, the average number of element comparisons should be close to 1.0. +* For unsuccessful lookups, the average number of element comparisons should be close to 0.0. + +These statistics can be used to determine if a given hash function +can be marked as xref:hash_traits_hash_is_avalanching[__avalanching__]. + +--- diff --git a/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc b/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc new file mode 100644 index 00000000..4b42ec26 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_flat_map.adoc @@ -0,0 +1,1584 @@ +[#unordered_flat_map] +== Class Template unordered_flat_map + +:idprefix: unordered_flat_map_ + +`boost::unordered_flat_map` — An open-addressing unordered associative container that associates unique keys with another value. + +The performance of `boost::unordered_flat_map` is much better than that of `boost::unordered_map` +or other implementations of `std::unordered_map`. Unlike standard unordered associative containers, +which are node-based, the elements of a `boost::unordered_flat_map` are held directly in the bucket +array, and insertions into an already occupied bucket are diverted to available buckets in the +vicinity of the original position. This type of data layout is known as _open addressing_. + +As a result of its using open addressing, the interface of `boost::unordered_flat_map` deviates in +a number of aspects from that of `boost::unordered_map`/`std::unordered_map`: + + - `value_type` must be move-constructible. + - Pointer stability is not kept under rehashing. + - `begin()` is not constant-time. + - There is no API for bucket handling (except `bucket_count`) or node extraction/insertion. + - The maximum load factor of the container is managed internally and can't be set by the user. + +Other than this, `boost::unordered_flat_map` is mostly a drop-in replacement of node-based standard +unordered associative containers. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + class unordered_flat_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using init_type = std::pair< + typename std::remove_const::type, + typename std::remove_const::type + >; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:unordered_flat_map_boost_unordered_enable_stats[enabled] + + // construct/copy/destroy + xref:#unordered_flat_map_default_constructor[unordered_flat_map](); + explicit xref:#unordered_flat_map_bucket_count_constructor[unordered_flat_map](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_flat_map_iterator_range_constructor[unordered_flat_map](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_flat_map_copy_constructor[unordered_flat_map](const unordered_flat_map& other); + xref:#unordered_flat_map_move_constructor[unordered_flat_map](unordered_flat_map&& other); + template + xref:#unordered_flat_map_iterator_range_constructor_with_allocator[unordered_flat_map](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_flat_map_allocator_constructor[unordered_flat_map](const Allocator& a); + xref:#unordered_flat_map_copy_constructor_with_allocator[unordered_flat_map](const unordered_flat_map& other, const Allocator& a); + xref:#unordered_flat_map_move_constructor_with_allocator[unordered_flat_map](unordered_flat_map&& other, const Allocator& a); + xref:#unordered_flat_map_move_constructor_from_concurrent_flat_map[unordered_flat_map](concurrent_flat_map&& other); + xref:#unordered_flat_map_initializer_list_constructor[unordered_flat_map](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_flat_map_bucket_count_constructor_with_allocator[unordered_flat_map](size_type n, const allocator_type& a); + xref:#unordered_flat_map_bucket_count_constructor_with_hasher_and_allocator[unordered_flat_map](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_flat_map_iterator_range_constructor_with_bucket_count_and_allocator[unordered_flat_map](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_flat_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_flat_map_initializer_list_constructor_with_allocator[unordered_flat_map](std::initializer_list il, const allocator_type& a); + xref:#unordered_flat_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_map](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#unordered_flat_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_flat_map](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_flat_map_destructor[~unordered_flat_map](); + unordered_flat_map& xref:#unordered_flat_map_copy_assignment[operator++=++](const unordered_flat_map& other); + unordered_flat_map& xref:#unordered_flat_map_move_assignment[operator++=++](unordered_flat_map&& other) ++noexcept( + (boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value);++ + unordered_flat_map& xref:#unordered_flat_map_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#unordered_flat_map_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_flat_map_begin[begin]() noexcept; + const_iterator xref:#unordered_flat_map_begin[begin]() const noexcept; + iterator xref:#unordered_flat_map_end[end]() noexcept; + const_iterator xref:#unordered_flat_map_end[end]() const noexcept; + const_iterator xref:#unordered_flat_map_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_flat_map_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_flat_map_empty[empty]() const noexcept; + size_type xref:#unordered_flat_map_size[size]() const noexcept; + size_type xref:#unordered_flat_map_max_size[max_size]() const noexcept; + + // modifiers + template std::pair xref:#unordered_flat_map_emplace[emplace](Args&&... args); + template iterator xref:#unordered_flat_map_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + std::pair xref:#unordered_flat_map_copy_insert[insert](const value_type& obj); + std::pair xref:#unordered_flat_map_copy_insert[insert](const init_type& obj); + std::pair xref:#unordered_flat_map_move_insert[insert](value_type&& obj); + std::pair xref:#unordered_flat_map_move_insert[insert](init_type&& obj); + iterator xref:#unordered_flat_map_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_flat_map_copy_insert_with_hint[insert](const_iterator hint, const init_type& obj); + iterator xref:#unordered_flat_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + iterator xref:#unordered_flat_map_copy_insert_with_hint[insert](const_iterator hint, init_type&& obj); + template void xref:#unordered_flat_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_flat_map_insert_initializer_list[insert](std::initializer_list); + + template + std::pair xref:#unordered_flat_map_try_emplace[try_emplace](const key_type& k, Args&&... args); + template + std::pair xref:#unordered_flat_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_flat_map_try_emplace[try_emplace](K&& k, Args&&... args); + template + iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); + template + iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_flat_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); + template + std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); + template + std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_flat_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); + template + iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); + template + iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_flat_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); + + _convertible-to-iterator_ xref:#unordered_flat_map_erase_by_position[erase](iterator position); + _convertible-to-iterator_ xref:#unordered_flat_map_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_flat_map_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_flat_map_erase_by_key[erase](K&& k); + iterator xref:#unordered_flat_map_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_flat_map_swap[swap](unordered_flat_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + void xref:#unordered_flat_map_clear[clear]() noexcept; + + template + void xref:#unordered_flat_map_merge[merge](unordered_flat_map& source); + template + void xref:#unordered_flat_map_merge[merge](unordered_flat_map&& source); + + // observers + hasher xref:#unordered_flat_map_hash_function[hash_function]() const; + key_equal xref:#unordered_flat_map_key_eq[key_eq]() const; + + // map operations + iterator xref:#unordered_flat_map_find[find](const key_type& k); + const_iterator xref:#unordered_flat_map_find[find](const key_type& k) const; + template + iterator xref:#unordered_flat_map_find[find](const K& k); + template + const_iterator xref:#unordered_flat_map_find[find](const K& k) const; + size_type xref:#unordered_flat_map_count[count](const key_type& k) const; + template + size_type xref:#unordered_flat_map_count[count](const K& k) const; + bool xref:#unordered_flat_map_contains[contains](const key_type& k) const; + template + bool xref:#unordered_flat_map_contains[contains](const K& k) const; + std::pair xref:#unordered_flat_map_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_flat_map_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_flat_map_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_flat_map_equal_range[equal_range](const K& k) const; + + // element access + mapped_type& xref:#unordered_flat_map_operator[operator[+]+](const key_type& k); + mapped_type& xref:#unordered_flat_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_flat_map_operator[operator[+]+](K&& k); + mapped_type& xref:#unordered_flat_map_at[at](const key_type& k); + const mapped_type& xref:#unordered_flat_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_flat_map_at[at](const K& k); + template const mapped_type& xref:#unordered_flat_map_at[at](const K& k) const; + + // bucket interface + size_type xref:#unordered_flat_map_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#unordered_flat_map_load_factor[load_factor]() const noexcept; + float xref:#unordered_flat_map_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_flat_map_set_max_load_factor[max_load_factor](float z); + size_type xref:#unordered_flat_map_max_load[max_load]() const noexcept; + void xref:#unordered_flat_map_rehash[rehash](size_type n); + void xref:#unordered_flat_map_reserve[reserve](size_type n); + + // statistics (if xref:unordered_flat_map_boost_unordered_enable_stats[enabled]) + stats xref:#unordered_flat_map_get_stats[get_stats]() const; + void xref:#unordered_flat_map_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_flat_map(InputIterator, InputIterator, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type = xref:#unordered_flat_map_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_map, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, + Pred, Allocator>; + + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + unordered_flat_map(std::initializer_list>, + typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type = xref:#unordered_flat_map_deduction_guides[__see below__], Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_map; + + template + unordered_flat_map(InputIterator, InputIterator, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_flat_map, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_map(InputIterator, InputIterator, Allocator) + -> unordered_flat_map, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_map(InputIterator, InputIterator, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_flat_map, xref:#unordered_flat_map_iter_mapped_type[__iter-mapped-type__], Hash, + std::equal_to>, Allocator>; + + template + unordered_flat_map(std::initializer_list>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, + Allocator) + -> unordered_flat_map, std::equal_to, Allocator>; + + template + unordered_flat_map(std::initializer_list>, Allocator) + -> unordered_flat_map, std::equal_to, Allocator>; + + template + unordered_flat_map(std::initializer_list>, typename xref:#unordered_flat_map_deduction_guides[__see below__]::size_type, + Hash, Allocator) + -> unordered_flat_map, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_flat_map_operator_2[operator==](const unordered_flat_map& x, + const unordered_flat_map& y); + + template + bool xref:#unordered_flat_map_operator_3[operator!=](const unordered_flat_map& x, + const unordered_flat_map& y); + + // swap + template + void xref:#unordered_flat_map_swap_2[swap](unordered_flat_map& x, + unordered_flat_map& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_flat_map::size_type + xref:#unordered_flat_map_erase_if[erase_if](unordered_flat_map& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_flat_map = + boost::unordered_flat_map>>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +.2+|`Key` and `T` must be https://en.cppreference.com/w/cpp/named_req/MoveConstructible[MoveConstructible^]. +`std::pair` must be https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] +into the container from any `std::pair` object convertible to it, and it also must be +https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container. + +|_T_ + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements of the container are held into an internal _bucket array_. An element is inserted into a bucket determined by its +hash code, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the container (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the container. Note +that this option decreases the overall performance of many operations. + +--- + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +An iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +=== Constructors + +==== Default Constructor +```c++ +unordered_flat_map(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_flat_map(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_flat_map(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_flat_map(unordered_flat_map const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_flat_map(unordered_flat_map&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_flat_map(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_flat_map(Allocator const& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_flat_map(unordered_flat_map const& other, Allocator const& a); +``` + +Constructs a container, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_flat_map(unordered_flat_map&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the elements of `other` are transferred directly to the new container; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:unordered_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Move Constructor from concurrent_flat_map + +```c++ +unordered_flat_map(concurrent_flat_map&& other); +``` + +Move construction from a xref:#concurrent_flat_map[`concurrent_flat_map`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; Constant time. +Concurrency:;; Blocking on `other`. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_flat_map(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_flat_map(size_type n, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_flat_map(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_flat_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + unordered_flat_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_flat_map(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_flat_map(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_flat_map(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_flat_map(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_flat_map& operator=(unordered_flat_map const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +--- + +==== Move Assignment +```c++ +unordered_flat_map& operator=(unordered_flat_map&& other) + noexcept((boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to the new container; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:unordered_flat_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Initializer List Assignment +```c++ +unordered_flat_map& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template std::pair emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. + +--- + +==== emplace_hint +```c++ + template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +`position` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. + +--- + +==== Copy Insert +```c++ +std::pair insert(const value_type& obj); +std::pair insert(const init_type& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(x)`, where `x` is equally convertible to both `const value_type&` and `const init_type&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Move Insert +```c++ +std::pair insert(value_type&& obj); +std::pair insert(init_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(x)`, where `x` is equally convertible to both `value_type&&` and `init_type&&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +iterator insert(const_iterator hint, const init_type& obj); +``` +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(hint, x)`, where `x` is equally convertible to both `const value_type&` and `const init_type&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +iterator insert(const_iterator hint, init_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(hint, x)`, where `x` is equally convertible to both `value_type&&` and `init_type&&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== try_emplace +```c++ +template + std::pair try_emplace(const key_type& k, Args&&... args); +template + std::pair try_emplace(key_type&& k, Args&&... args); +template + std::pair try_emplace(K&& k, Args&&... args); +``` + +Inserts a new element into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +[horizontal] +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_flat_map_emplace[emplace], with the difference that no `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +unlike xref:#unordered_flat_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor. + +Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== try_emplace with Hint +```c++ +template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); +``` + +Inserts a new element into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_flat_map_emplace_hint[emplace_hint], with the difference that no `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +unlike xref:#unordered_flat_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor. + +Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== insert_or_assign +```c++ +template + std::pair insert_or_assign(const key_type& k, M&& obj); +template + std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +[horizontal] +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== insert_or_assign with Hint +```c++ +template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + + +==== Erase by Position + +[source,c++,subs=+quotes] +---- +_convertible-to-iterator_ erase(iterator position); +_convertible-to-iterator_ erase(const_iterator position); +---- + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; An opaque object implicitly convertible to the `iterator` or `const_iterator` +immediately following `position` prior to the erasure. +Throws:;; Nothing. +Notes:;; The opaque object returned must only be discarded or immediately converted to `iterator` or `const_iterator`. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Nothing in this implementation (neither the `hasher` nor the `key_equal` objects are called). + +--- + +==== swap +```c++ +void swap(unordered_flat_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` + +--- + +==== merge +```c++ +template + void merge(unordered_flat_map& source); +template + void merge(unordered_flat_map&& source); +``` + +Move-inserts all the elements from `source` whose key is not already present in `*this`, and erases them from `source`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The container's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); + +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `end()` if no such element exists. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== operator++[++++]++ +```c++ +mapped_type& operator[](const key_type& k); +mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); +``` + +[horizontal] +Effects:;; If the container does not already contain an element with a key equivalent to `k`, inserts the value `std::pair(k, mapped_type())`. +Returns:;; A reference to `x.second` where `x` is the element already in the container, or the newly inserted element with a key equivalent to `k`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== at +```c++ +mapped_type& at(const key_type& k); +const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; +``` + +[horizontal] +Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. +Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the container's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_map`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the container can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the container's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed. + +Invalidates iterators, pointers and references, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators, pointers and references, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the container so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_flat_map_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the container. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_flat_map_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +==== __iter-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-key-type__ = std::remove_const_t< + std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +==== __iter-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-mapped-type__ = + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>; // exposition only +----- + +==== __iter-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-to-alloc-type__ = std::pair< + std::add_const_t>>, + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_flat_map& x, + const unordered_flat_map& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_flat_map& x, + const unordered_flat_map& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +=== Swap +```c++ +template + void swap(unordered_flat_map& x, + unordered_flat_map& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +=== erase_if +```c++ +template + typename unordered_flat_map::size_type + erase_if(unordered_flat_map& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_flat_map``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_flat_map to an archive + +Saves all the elements of an `unordered_flat_map` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `std::remove_const::type` and `std::remove_const::type` +are serializable (XML serializable), and they do support Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_flat_map from an archive + +Deletes all preexisting elements of an `unordered_flat_map` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_flat_map` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_flat_map` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_flat_map` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc b/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc new file mode 100644 index 00000000..caa58586 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_flat_set.adoc @@ -0,0 +1,1332 @@ +[#unordered_flat_set] +== Class Template unordered_flat_set + +:idprefix: unordered_flat_set_ + +`boost::unordered_flat_set` — An open-addressing unordered associative container that stores unique values. + +The performance of `boost::unordered_flat_set` is much better than that of `boost::unordered_set` +or other implementations of `std::unordered_set`. Unlike standard unordered associative containers, +which are node-based, the elements of a `boost::unordered_flat_set` are held directly in the bucket +array, and insertions into an already occupied bucket are diverted to available buckets in the +vicinity of the original position. This type of data layout is known as _open addressing_. + +As a result of its using open addressing, the interface of `boost::unordered_flat_set` deviates in +a number of aspects from that of `boost::unordered_flat_set`/`std::unordered_flat_set`: + + - `value_type` must be move-constructible. + - Pointer stability is not kept under rehashing. + - `begin()` is not constant-time. + - There is no API for bucket handling (except `bucket_count`) or node extraction/insertion. + - The maximum load factor of the container is managed internally and can't be set by the user. + +Other than this, `boost::unordered_flat_set` is mostly a drop-in replacement of node-based standard +unordered associative containers. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator> + class unordered_flat_set { + public: + // types + using key_type = Key; + using value_type = Key; + using init_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:unordered_flat_set_boost_unordered_enable_stats[enabled] + + // construct/copy/destroy + xref:#unordered_flat_set_default_constructor[unordered_flat_set](); + explicit xref:#unordered_flat_set_bucket_count_constructor[unordered_flat_set](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_flat_set_iterator_range_constructor[unordered_flat_set](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_flat_set_copy_constructor[unordered_flat_set](const unordered_flat_set& other); + xref:#unordered_flat_set_move_constructor[unordered_flat_set](unordered_flat_set&& other); + template + xref:#unordered_flat_set_iterator_range_constructor_with_allocator[unordered_flat_set](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_flat_set_allocator_constructor[unordered_flat_set](const Allocator& a); + xref:#unordered_flat_set_copy_constructor_with_allocator[unordered_flat_set](const unordered_flat_set& other, const Allocator& a); + xref:#unordered_flat_set_move_constructor_from_concurrent_flat_set[unordered_flat_set](concurrent_flat_set&& other); + xref:#unordered_flat_set_initializer_list_constructor[unordered_flat_set](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_flat_set_bucket_count_constructor_with_allocator[unordered_flat_set](size_type n, const allocator_type& a); + xref:#unordered_flat_set_bucket_count_constructor_with_hasher_and_allocator[unordered_flat_set](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_flat_set_iterator_range_constructor_with_bucket_count_and_allocator[unordered_flat_set](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_flat_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_flat_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_flat_set_initializer_list_constructor_with_allocator[unordered_flat_set](std::initializer_list il, const allocator_type& a); + xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_flat_set](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#unordered_flat_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_flat_set](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_flat_set_destructor[~unordered_flat_set](); + unordered_flat_set& xref:#unordered_flat_set_copy_assignment[operator++=++](const unordered_flat_set& other); + unordered_flat_set& xref:#unordered_flat_set_move_assignment[operator++=++](unordered_flat_set&& other) ++noexcept( + (boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value);++ + unordered_flat_set& xref:#unordered_flat_set_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#unordered_flat_set_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_flat_set_begin[begin]() noexcept; + const_iterator xref:#unordered_flat_set_begin[begin]() const noexcept; + iterator xref:#unordered_flat_set_end[end]() noexcept; + const_iterator xref:#unordered_flat_set_end[end]() const noexcept; + const_iterator xref:#unordered_flat_set_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_flat_set_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_flat_set_empty[empty]() const noexcept; + size_type xref:#unordered_flat_set_size[size]() const noexcept; + size_type xref:#unordered_flat_set_max_size[max_size]() const noexcept; + + // modifiers + template std::pair xref:#unordered_flat_set_emplace[emplace](Args&&... args); + template iterator xref:#unordered_flat_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + std::pair xref:#unordered_flat_set_copy_insert[insert](const value_type& obj); + std::pair xref:#unordered_flat_set_move_insert[insert](value_type&& obj); + template std::pair xref:#unordered_flat_set_transparent_insert[insert](K&& k); + iterator xref:#unordered_flat_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_flat_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_flat_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); + template void xref:#unordered_flat_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_flat_set_insert_initializer_list[insert](std::initializer_list); + + _convertible-to-iterator_ xref:#unordered_flat_set_erase_by_position[erase](iterator position); + _convertible-to-iterator_ xref:#unordered_flat_set_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_flat_set_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_flat_set_erase_by_key[erase](K&& k); + iterator xref:#unordered_flat_set_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_flat_set_swap[swap](unordered_flat_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + void xref:#unordered_flat_set_clear[clear]() noexcept; + + template + void xref:#unordered_flat_set_merge[merge](unordered_flat_set& source); + template + void xref:#unordered_flat_set_merge[merge](unordered_flat_set&& source); + + // observers + hasher xref:#unordered_flat_set_hash_function[hash_function]() const; + key_equal xref:#unordered_flat_set_key_eq[key_eq]() const; + + // set operations + iterator xref:#unordered_flat_set_find[find](const key_type& k); + const_iterator xref:#unordered_flat_set_find[find](const key_type& k) const; + template + iterator xref:#unordered_flat_set_find[find](const K& k); + template + const_iterator xref:#unordered_flat_set_find[find](const K& k) const; + size_type xref:#unordered_flat_set_count[count](const key_type& k) const; + template + size_type xref:#unordered_flat_set_count[count](const K& k) const; + bool xref:#unordered_flat_set_contains[contains](const key_type& k) const; + template + bool xref:#unordered_flat_set_contains[contains](const K& k) const; + std::pair xref:#unordered_flat_set_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_flat_set_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_flat_set_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_flat_set_equal_range[equal_range](const K& k) const; + + // bucket interface + size_type xref:#unordered_flat_set_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#unordered_flat_set_load_factor[load_factor]() const noexcept; + float xref:#unordered_flat_set_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_flat_set_set_max_load_factor[max_load_factor](float z); + size_type xref:#unordered_flat_set_max_load[max_load]() const noexcept; + void xref:#unordered_flat_set_rehash[rehash](size_type n); + void xref:#unordered_flat_set_reserve[reserve](size_type n); + + // statistics (if xref:unordered_flat_set_boost_unordered_enable_stats[enabled]) + stats xref:#unordered_flat_set_get_stats[get_stats]() const; + void xref:#unordered_flat_set_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_set, Hash, Pred, Allocator>; + + template, class Pred = std::equal_to, + class Allocator = std::allocator> + unordered_flat_set(std::initializer_list, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type = xref:#unordered_flat_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_flat_set; + + template + unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_set(InputIterator, InputIterator, Allocator) + -> unordered_flat_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_flat_set(InputIterator, InputIterator, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_flat_set, Hash, + std::equal_to>, Allocator>; + + template + unordered_flat_set(std::initializer_list, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_flat_set, std::equal_to, Allocator>; + + template + unordered_flat_set(std::initializer_list, Allocator) + -> unordered_flat_set, std::equal_to, Allocator>; + + template + unordered_flat_set(std::initializer_list, typename xref:#unordered_flat_set_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> unordered_flat_set, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_flat_set_operator_2[operator==](const unordered_flat_set& x, + const unordered_flat_set& y); + + template + bool xref:#unordered_flat_set_operator_3[operator!=](const unordered_flat_set& x, + const unordered_flat_set& y); + + // swap + template + void xref:#unordered_flat_set_swap_2[swap](unordered_flat_set& x, + unordered_flat_set& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_flat_set::size_type + xref:#unordered_flat_set_erase_if[erase_if](unordered_flat_set& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_flat_set = + boost::unordered_flat_set>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^] into the container +and https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container. + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements of the container are held into an internal _bucket array_. An element is inserted into a bucket determined by its +hash code, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the container (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the container. Note +that this option decreases the overall performance of many operations. + +--- + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +=== Constructors + +==== Default Constructor +```c++ +unordered_flat_set(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_flat_set(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_flat_set(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_flat_set(unordered_flat_set const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_flat_set(unordered_flat_set&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_flat_set(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_flat_set(Allocator const& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_flat_set(unordered_flat_set const& other, Allocator const& a); +``` + +Constructs a container, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_flat_set(unordered_flat_set&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the elements of `other` are transferred directly to the new container; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:unordered_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Move Constructor from concurrent_flat_set + +```c++ +unordered_flat_set(concurrent_flat_set&& other); +``` + +Move construction from a xref:#concurrent_flat_set[`concurrent_flat_set`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; Constant time. +Concurrency:;; Blocking on `other`. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_flat_set(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_flat_set(size_type n, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_flat_set(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_flat_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + unordered_flat_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_flat_set(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_flat_set(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_flat_set(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_flat_set(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_flat_set& operator=(unordered_flat_set const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +--- + +==== Move Assignment +```c++ +unordered_flat_set& operator=(unordered_flat_set&& other) + noexcept((boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to the new container; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:unordered_flat_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Initializer List Assignment +```c++ +unordered_flat_set& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template std::pair emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + + +--- + +==== emplace_hint +```c++ + template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +`position` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + + +--- + +==== Copy Insert +```c++ +std::pair insert(const value_type& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Move Insert +```c++ +std::pair insert(value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +``` +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Transparent Insert with Hint +```c++ +template std::pair insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Erase by Position + +[source,c++,subs=+quotes] +---- +_convertible-to-iterator_ erase(iterator position); +_convertible-to-iterator_ erase(const_iterator position); +---- + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; An opaque object implicitly convertible to the `iterator` or `const_iterator` +immediately following `position` prior to the erasure. +Throws:;; Nothing. +Notes:;; The opaque object returned must only be discarded or immediately converted to `iterator` or `const_iterator`. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Nothing in this implementation (neither the `hasher` nor the `key_equal` objects are called). + +--- + +==== swap +```c++ +void swap(unordered_flat_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` + +--- + +==== merge +```c++ +template + void merge(unordered_flat_set& source); +template + void merge(unordered_flat_set&& source); +``` + +Move-inserts all the elements from `source` whose key is not already present in `*this`, and erases them from `source`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The container's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); + +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `end()` if no such element exists. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the container's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_set`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the container can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the container's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed. + +Invalidates iterators, pointers and references, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators, pointers and references, and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the container so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_flat_set_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the container. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_flat_set_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_flat_set& x, + const unordered_flat_set& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_flat_set& x, + const unordered_flat_set& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +=== Swap +```c++ +template + void swap(unordered_flat_set& x, + unordered_flat_set& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +=== erase_if +```c++ +template + typename unordered_flat_set::size_type + erase_if(unordered_flat_set& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_flat_set``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_flat_set to an archive + +Saves all the elements of an `unordered_flat_set` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `value_type` +is serializable (XML serializable), and it supports Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_flat_set from an archive + +Deletes all preexisting elements of an `unordered_flat_set` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_flat_set` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `x.key_equal()` is functionally equivalent to `other.key_equal()`. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_flat_set` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_flat_set` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_map.adoc b/doc/modules/ROOT/pages/reference/unordered_map.adoc new file mode 100644 index 00000000..b165eb4a --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_map.adoc @@ -0,0 +1,1853 @@ +[#unordered_map] +== Class Template unordered_map + +:idprefix: unordered_map_ + +`boost::unordered_map` — An unordered associative container that associates unique keys with another value. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + class unordered_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + using local_iterator = _implementation-defined_; + using const_local_iterator = _implementation-defined_; + using node_type = _implementation-defined_; + using insert_return_type = _implementation-defined_; + + // construct/copy/destroy + xref:#unordered_map_default_constructor[unordered_map](); + explicit xref:#unordered_map_bucket_count_constructor[unordered_map](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_map_iterator_range_constructor[unordered_map](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_map_copy_constructor[unordered_map](const unordered_map& other); + xref:#unordered_map_move_constructor[unordered_map](unordered_map&& other); + template + xref:#unordered_map_iterator_range_constructor_with_allocator[unordered_map](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_map_allocator_constructor[unordered_map](const Allocator& a); + xref:#unordered_map_copy_constructor_with_allocator[unordered_map](const unordered_map& other, const Allocator& a); + xref:#unordered_map_move_constructor_with_allocator[unordered_map](unordered_map&& other, const Allocator& a); + xref:#unordered_map_initializer_list_constructor[unordered_map](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_map_bucket_count_constructor_with_allocator[unordered_map](size_type n, const allocator_type& a); + xref:#unordered_map_bucket_count_constructor_with_hasher_and_allocator[unordered_map](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_map_iterator_range_constructor_with_bucket_count_and_allocator[unordered_map](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_map_initializer_list_constructor_with_allocator[unordered_map](std::initializer_list il, const allocator_type& a); + xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_map](std::initializer_list il, size_type n, const allocator_type& a); + xref:#unordered_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_map](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_map_destructor[~unordered_map](); + unordered_map& xref:#unordered_map_copy_assignment[operator++=++](const unordered_map& other); + unordered_map& xref:#unordered_map_move_assignment[operator++=++](unordered_map&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); + unordered_map& xref:#unordered_map_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#unordered_map_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_map_begin[begin]() noexcept; + const_iterator xref:#unordered_map_begin[begin]() const noexcept; + iterator xref:#unordered_map_end[end]() noexcept; + const_iterator xref:#unordered_map_end[end]() const noexcept; + const_iterator xref:#unordered_map_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_map_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_map_empty[empty]() const noexcept; + size_type xref:#unordered_map_size[size]() const noexcept; + size_type xref:#unordered_map_max_size[max_size]() const noexcept; + + // modifiers + template std::pair xref:#unordered_map_emplace[emplace](Args&&... args); + template iterator xref:#unordered_map_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + std::pair xref:#unordered_map_copy_insert[insert](const value_type& obj); + std::pair xref:#unordered_map_move_insert[insert](value_type&& obj); + template std::pair xref:#unordered_map_emplace_insert[insert](P&& obj); + iterator xref:#unordered_map_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_map_emplace_insert_with_hint[insert](const_iterator hint, P&& obj); + template void xref:#unordered_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_map_insert_initializer_list[insert](std::initializer_list); + + template + std::pair xref:#unordered_map_try_emplace[try_emplace](const key_type& k, Args&&... args); + template + std::pair xref:#unordered_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_map_try_emplace[try_emplace](K&& k, Args&&... args); + template + iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); + template + iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); + template + std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); + template + std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); + template + iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); + template + iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); + + node_type xref:#unordered_map_extract_by_iterator[extract](const_iterator position); + node_type xref:#unordered_map_extract_by_key[extract](const key_type& k); + template node_type xref:#unordered_map_extract_by_key[extract](K&& k); + insert_return_type xref:#unordered_map_insert_with_node_handle[insert](node_type&& nh); + iterator xref:#unordered_map_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); + + iterator xref:#unordered_map_erase_by_position[erase](iterator position); + iterator xref:#unordered_map_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_map_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_map_erase_by_key[erase](K&& k); + iterator xref:#unordered_map_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_map_quick_erase[quick_erase](const_iterator position); + void xref:#unordered_map_erase_return_void[erase_return_void](const_iterator position); + void xref:#unordered_map_swap[swap](unordered_map& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); + void xref:#unordered_map_clear[clear]() noexcept; + + template + void xref:#unordered_map_merge[merge](unordered_map& source); + template + void xref:#unordered_map_merge[merge](unordered_map&& source); + template + void xref:#unordered_map_merge[merge](unordered_multimap& source); + template + void xref:#unordered_map_merge[merge](unordered_multimap&& source); + + // observers + hasher xref:#unordered_map_hash_function[hash_function]() const; + key_equal xref:#unordered_map_key_eq[key_eq]() const; + + // map operations + iterator xref:#unordered_map_find[find](const key_type& k); + const_iterator xref:#unordered_map_find[find](const key_type& k) const; + template + iterator xref:#unordered_map_find[find](const K& k); + template + const_iterator xref:#unordered_map_find[find](const K& k) const; + template + iterator xref:#unordered_map_find[find](CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq); + template + const_iterator xref:#unordered_map_find[find](CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq) const; + size_type xref:#unordered_map_count[count](const key_type& k) const; + template + size_type xref:#unordered_map_count[count](const K& k) const; + bool xref:#unordered_map_contains[contains](const key_type& k) const; + template + bool xref:#unordered_map_contains[contains](const K& k) const; + std::pair xref:#unordered_map_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_map_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_map_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_map_equal_range[equal_range](const K& k) const; + + // element access + mapped_type& xref:#unordered_map_operator[operator[+]+](const key_type& k); + mapped_type& xref:#unordered_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_map_operator[operator[+]+](K&& k); + mapped_type& xref:#unordered_map_at[at](const key_type& k); + const mapped_type& xref:#unordered_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_map_at[at](const K& k); + template const mapped_type& xref:#unordered_map_at[at](const K& k) const; + + // bucket interface + size_type xref:#unordered_map_bucket_count[bucket_count]() const noexcept; + size_type xref:#unordered_map_max_bucket_count[max_bucket_count]() const noexcept; + size_type xref:#unordered_map_bucket_size[bucket_size](size_type n) const; + size_type xref:#unordered_map_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_map_bucket[bucket](const K& k) const; + local_iterator xref:#unordered_map_begin_2[begin](size_type n); + const_local_iterator xref:#unordered_map_begin_2[begin](size_type n) const; + local_iterator xref:#unordered_map_end_2[end](size_type n); + const_local_iterator xref:#unordered_map_end_2[end](size_type n) const; + const_local_iterator xref:#unordered_map_cbegin_2[cbegin](size_type n) const; + const_local_iterator xref:#unordered_map_cend_2[cend](size_type n) const; + + // hash policy + float xref:#unordered_map_load_factor[load_factor]() const noexcept; + float xref:#unordered_map_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_map_set_max_load_factor[max_load_factor](float z); + void xref:#unordered_map_rehash[rehash](size_type n); + void xref:#unordered_map_reserve[reserve](size_type n); + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_map, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__], Hash, Pred, + Allocator>; + + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + unordered_map(std::initializer_list>, + typename xref:#unordered_map_deduction_guides[__see below__]::size_type = xref:#unordered_map_deduction_guides[__see below__], Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> unordered_map; + + template + unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_map, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_map(InputIterator, InputIterator, Allocator) + -> unordered_map, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_map(InputIterator, InputIterator, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> unordered_map, xref:#unordered_map_iter_mapped_type[__iter-mapped-type__], Hash, + std::equal_to>, Allocator>; + + template + unordered_map(std::initializer_list>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, + Allocator) + -> unordered_map, std::equal_to, Allocator>; + + template + unordered_map(std::initializer_list>, Allocator) + -> unordered_map, std::equal_to, Allocator>; + + template + unordered_map(std::initializer_list>, typename xref:#unordered_map_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_map, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_map_operator_2[operator==](const unordered_map& x, + const unordered_map& y); + + template + bool xref:#unordered_map_operator_3[operator!=](const unordered_map& x, + const unordered_map& y); + + // swap + template + void xref:#unordered_map_swap_2[swap](unordered_map& x, + unordered_map& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_map::size_type + xref:#unordered_map_erase_if[erase_if](unordered_map& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_map = + boost::unordered_map>>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container (i.e. `allocator_traits` can destroy it). + +|_T_ +|`T` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container (i.e. `allocator_traits` can destroy it). + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that implements an equivalence relation on values of type `Key`. A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type bool. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements are organized into buckets. Keys with the same hash code are stored in the same bucket. + +The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash. + +=== Configuration macros + +==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` + +Globally define this macro to support loading of ``unordered_map``s saved to +a Boost.Serialization archive with a version of Boost prior to Boost 1.84. + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +An iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ local_iterator; +---- + +An iterator with the same value type, difference type and pointer and reference type as iterator. + +A `local_iterator` object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_local_iterator; +---- + +A constant iterator with the same value type, difference type and pointer and reference type as const_iterator. + +A const_local_iterator object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +A class for holding extracted container elements, modelling +https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle]. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ insert_return_type; +---- + +A specialization of an internal class template: + +[source,c++,subs=+quotes] +---- +template +struct _insert_return_type_ // name is exposition only +{ + Iterator position; + bool inserted; + NodeType node; +}; +---- + +with `Iterator` = `iterator` and `NodeType` = `node_type`. + +--- + +=== Constructors + +==== Default Constructor +```c++ +unordered_map(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate, `allocator_type()` as the allocator +and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_map(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, `a` as the allocator and a maximum +load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_map(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_map(unordered_map const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_map(unordered_map&& other); +``` + +The move constructor. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move-constructible. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_map(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_map(Allocator const& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_map(unordered_map const& other, Allocator const& a); +``` + +Constructs an container, copying ``other``'s contained elements, hash function, predicate, maximum load factor, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_map(unordered_map&& other, Allocator const& a); +``` + +Construct a container moving ``other``'s contained elements, and having the hash function, predicate and maximum load factor, but using allocate `a`. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move insertable. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_map(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_map(size_type n, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_map(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + unordered_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_map(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_map(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_map(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_map(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_map& operator=(unordered_map const& other); +``` + +The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + +If `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, the allocator is overwritten, if not the copied elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Assignment +```c++ +unordered_map& operator=(unordered_map&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); +``` +The move assignment operator. + +If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is move constructible. + +--- + +==== Initializer List Assignment +```c++ +unordered_map& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container and https://en.cppreference.com/w/cpp/named_req/CopyAssignable[CopyAssignable^]. + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template std::pair emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. This optimization happens when the map's `key_type` is move constructible or when the `k` argument is a `key_type`. + +--- + +==== emplace_hint +```c++ + template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +`position` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. This optimization happens when the map's `key_type` is move constructible or when the `k` argument is a `key_type`. + +--- + +==== Copy Insert +```c++ +std::pair insert(const value_type& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert +```c++ +std::pair insert(value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Emplace Insert +```c++ +template std::pair insert(P&& obj); +``` + +Inserts an element into the container by performing `emplace(std::forward

(value))`. + +Only participates in overload resolution if `std::is_constructible::value` is `true`. + +[horizontal] +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +``` +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Emplace Insert with Hint + +```c++ +template iterator insert(const_iterator hint, P&& obj); +``` + +Inserts an element into the container by performing `emplace_hint(hint, std::forward

(value))`. + +Only participates in overload resolution if `std::is_constructible::value` is `true`. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== try_emplace +```c++ +template + std::pair try_emplace(const key_type& k, Args&&... args); +template + std::pair try_emplace(key_type&& k, Args&&... args); +template + std::pair try_emplace(K&& k, Args&&... args) +``` + +Inserts a new element into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +[horizontal] +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_map_emplace[emplace] except the `value_type` is constructed using: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +instead of xref:#unordered_map_emplace[emplace] which simply forwards all arguments to ``value_type``'s constructor. + +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + +Pointers and references to elements are never invalidated. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +-- + +--- + +==== try_emplace with Hint +```c++ +template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); +``` + +Inserts a new element into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_map_emplace_hint[emplace_hint] except the `value_type` is constructed using: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +instead of xref:#unordered_map_emplace_hint[emplace_hint] which simply forwards all arguments to ``value_type``'s constructor. + +The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + +Pointers and references to elements are never invalidated. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. +-- + +--- + +==== insert_or_assign +```c++ +template + std::pair insert_or_assign(const key_type& k, M&& obj); +template + std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +[horizontal] +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== insert_or_assign with Hint +```c++ +template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Extract by Iterator +```c++ +node_type extract(const_iterator position); +``` + +Removes the element pointed to by `position`. + +[horizontal] +Returns:;; A `node_type` owning the element. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. + +--- + +==== Extract by Key +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Removes an element with key equivalent to `k`. + +[horizontal] +Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_multimap`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert with `node_handle` +```c++ +insert_return_type insert(node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh` if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty, returns an `insert_return_type` with: `inserted` equal to `false`, `position` equal to `end()` and `node` empty. + ++ +Otherwise if there was already an element with an equivalent key, returns an `insert_return_type` with: `inserted` equal to `false`, `position` pointing to a matching element and `node` contains the node from `nh`. + ++ +Otherwise if the insertion succeeded, returns an `insert_return_type` with: `inserted` equal to `true`, `position` pointing to the newly inserted element and `node` empty. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_multimap`. + +--- + +==== Insert with Hint and `node_handle` +```c++ +iterator insert(const_iterator hint, node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh` if and only if there is no element in the container with an equivalent key. + +If there is already an element in the container with an equivalent key has no effect on `nh` (i.e. `nh` still contains the node.) + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty returns `end()`. + ++ +If there was already an element in the container with an equivalent key returns an iterator pointing to that. + ++ +Otherwise returns an iterator pointing to the newly inserted element. +Throws:;; If an exception is thrown by an operation other than a call to hasher the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_multimap`. + +--- + +==== Erase by Position + +```c++ +iterator erase(iterator position); +iterator erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; The iterator following `position` before the erasure. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; In older versions this could be inefficient because it had to search through several buckets to find the position of the returned iterator. The data structure has been changed so that this is no longer the case, and the alternative erase methods have been deprecated. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + +--- + +==== quick_erase +```c++ +void quick_erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== erase_return_void +```c++ +void erase_return_void(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== swap +```c++ +void swap(unordered_map& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +==== clear +```c++ +void clear(); +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0` +Throws:;; Never throws an exception. + +--- + +==== merge +```c++ +template + void merge(unordered_map& source); +template + void merge(unordered_map&& source); +template + void merge(unordered_multimap& source); +template + void merge(unordered_multimap&& source); +``` + +Attempt to "merge" two containers by iterating `source` and extracting any node in `source` that is not contained +in `*this` and then inserting it into `*this`. + +Because `source` can have a different hash function and key equality predicate, the key of each node in +`source` is rehashed using `this\->hash_function()` and then, if required, compared using `this\->key_eq()`. + +The behavior of this function is undefined if `this\->get_allocator() != source.get_allocator()`. + +This function does not copy or move any elements and instead simply relocates the nodes from `source` +into `*this`. + +[horizontal] +Notes:;; ++ +-- +* Pointers and references to transferred elements remain valid. +* Invalidates iterators to transferred elements. +* Invalidates iterators belonging to `*this`. +* Iterators to non-transferred elements in `source` remain valid. +-- + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const; +``` + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); +template + const_iterator find(const K& k) const; +template + iterator find(CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq); +template + const_iterator find(CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq) const; + +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `b.end()` if no such element exists. +Notes:;; The templated overloads containing `CompatibleKey`, `CompatibleHash` and `CompatiblePredicate` are non-standard extensions which allow you to use a compatible hash function and equality predicate for a key of a different type in order to avoid an expensive type cast. In general, its use is not encouraged and instead the `K` member function templates should be used. + ++ +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== operator++[++++]++ +```c++ +mapped_type& operator[](const key_type& k); +mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); +``` + +[horizontal] +Effects:;; If the container does not already contain an elements with a key equivalent to `k`, inserts the value `std::pair(k, mapped_type())`. +Returns:;; A reference to `x.second` where `x` is the element already in the container, or the newly inserted element with a key equivalent to `k`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== at +```c++ +mapped_type& at(const key_type& k); +const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; +``` + +[horizontal] +Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. +Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The number of buckets. + +--- + +==== max_bucket_count +```c++ +size_type max_bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; An upper bound on the number of buckets. + +--- + +==== bucket_size +```c++ +size_type bucket_size(size_type n) const; +``` + +[horizontal] +Requires:;; `n < bucket_count()` +Returns:;; The number of elements in bucket `n`. + +--- + +==== bucket +```c++ +size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; +``` + +[horizontal] +Returns:;; The index of the bucket which would contain an element with key `k`. +Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== begin + +```c++ +local_iterator begin(size_type n); +const_local_iterator begin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the first element in the bucket with index `n`. + +--- + +==== end +```c++ +local_iterator end(size_type n); +const_local_iterator end(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +==== cbegin +```c++ +const_local_iterator cbegin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the first element in the bucket with index `n`. + +--- + +==== cend +```c++ +const_local_iterator cend(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; The average number of elements per bucket. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the current maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Changes the container's maximum load factor, using `z` as a hint. + +--- + + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits::infinity()`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +==== __iter-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-key-type__ = std::remove_const_t< + std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +==== __iter-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-mapped-type__ = + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>; // exposition only +----- + +==== __iter-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-to-alloc-type__ = std::pair< + std::add_const_t>>, + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_map& x, + const unordered_map& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_map& x, + const unordered_map& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +=== Swap +```c++ +template + void swap(unordered_map& x, + unordered_map& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +=== erase_if +```c++ +template + typename unordered_map::size_type + erase_if(unordered_map& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_map``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_map to an archive + +Saves all the elements of an `unordered_map` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `std::remove_const::type` and `std::remove_const::type` +are serializable (XML serializable), and they do support Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_map from an archive + +Deletes all preexisting elements of an `unordered_map` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_map` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] +from `(std::remove_const::type&&, std::remove_const::type&&)`. +`x.key_equal()` is functionally equivalent to `other.key_equal()`. +Note:;; If the archive was saved using a release of Boost prior to Boost 1.84, +the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` +has to be globally defined for this operation to succeed; otherwise, an exception is thrown. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_map` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_map` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_multimap.adoc b/doc/modules/ROOT/pages/reference/unordered_multimap.adoc new file mode 100644 index 00000000..2c6d50b5 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_multimap.adoc @@ -0,0 +1,1572 @@ +[#unordered_multimap] +== Class Template unordered_multimap + +:idprefix: unordered_multimap_ + +`boost::unordered_multimap` — An unordered associative container that associates keys with another value. The same key can be stored multiple times. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + class unordered_multimap { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + using local_iterator = _implementation-defined_; + using const_local_iterator = _implementation-defined_; + using node_type = _implementation-defined_; + + // construct/copy/destroy + xref:#unordered_multimap_default_constructor[unordered_multimap](); + explicit xref:#unordered_multimap_bucket_count_constructor[unordered_multimap](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_multimap_iterator_range_constructor[unordered_multimap](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_multimap_copy_constructor[unordered_multimap](const unordered_multimap& other); + xref:#unordered_multimap_move_constructor[unordered_multimap](unordered_multimap&& other); + template + xref:#unordered_multimap_iterator_range_constructor_with_allocator[unordered_multimap](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_multimap_allocator_constructor[unordered_multimap](const Allocator& a); + xref:#unordered_multimap_copy_constructor_with_allocator[unordered_multimap](const unordered_multimap& other, const Allocator& a); + xref:#unordered_multimap_move_constructor_with_allocator[unordered_multimap](unordered_multimap&& other, const Allocator& a); + xref:#unordered_multimap_initializer_list_constructor[unordered_multimap](std::initializer_list il, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_multimap_bucket_count_constructor_with_allocator[unordered_multimap](size_type n, const allocator_type& a); + xref:#unordered_multimap_bucket_count_constructor_with_hasher_and_allocator[unordered_multimap](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_multimap_iterator_range_constructor_with_bucket_count_and_allocator[unordered_multimap](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_multimap_iterator_range_constructor_with_bucket_count_and_hasher[unordered_multimap](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_multimap_initializer_list_constructor_with_allocator[unordered_multimap](std::initializer_list il, const allocator_type& a); + xref:#unordered_multimap_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multimap](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#unordered_multimap_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_multimap](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_multimap_destructor[~unordered_multimap](); + unordered_multimap& xref:#unordered_multimap_copy_assignment[operator++=++](const unordered_multimap& other); + unordered_multimap& xref:#unordered_multimap_move_assignment[operator++=++](unordered_multimap&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); + unordered_multimap& xref:#unordered_multimap_initializer_list_assignment[operator++=++](std::initializer_list il); + allocator_type xref:#unordered_multimap_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_multimap_begin[begin]() noexcept; + const_iterator xref:#unordered_multimap_begin[begin]() const noexcept; + iterator xref:#unordered_multimap_end[end]() noexcept; + const_iterator xref:#unordered_multimap_end[end]() const noexcept; + const_iterator xref:#unordered_multimap_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_multimap_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_multimap_empty[empty]() const noexcept; + size_type xref:#unordered_multimap_size[size]() const noexcept; + size_type xref:#unordered_multimap_max_size[max_size]() const noexcept; + + // modifiers + template iterator xref:#unordered_multimap_emplace[emplace](Args&&... args); + template iterator xref:#unordered_multimap_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + iterator xref:#unordered_multimap_copy_insert[insert](const value_type& obj); + iterator xref:#unordered_multimap_move_insert[insert](value_type&& obj); + template iterator xref:#unordered_multimap_emplace_insert[insert](P&& obj); + iterator xref:#unordered_multimap_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_multimap_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_multimap_emplace_insert_with_hint[insert](const_iterator hint, P&& obj); + template void xref:#unordered_multimap_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_multimap_insert_initializer_list[insert](std::initializer_list il); + + node_type xref:#unordered_multimap_extract_by_iterator[extract](const_iterator position); + node_type xref:#unordered_multimap_extract_by_key[extract](const key_type& k); + template node_type xref:#unordered_multimap_extract_by_key[extract](K&& k); + iterator xref:#unordered_multimap_insert_with_node_handle[insert](node_type&& nh); + iterator xref:#unordered_multimap_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); + + iterator xref:#unordered_multimap_erase_by_position[erase](iterator position); + iterator xref:#unordered_multimap_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_multimap_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_multimap_erase_by_key[erase](K&& k); + iterator xref:#unordered_multimap_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_multimap_quick_erase[quick_erase](const_iterator position); + void xref:#unordered_multimap_erase_return_void[erase_return_void](const_iterator position); + void xref:#unordered_multimap_swap[swap](unordered_multimap& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); + void xref:#unordered_multimap_clear[clear]() noexcept; + + template + void xref:#unordered_multimap_merge[merge](unordered_multimap& source); + template + void xref:#unordered_multimap_merge[merge](unordered_multimap&& source); + template + void xref:#unordered_multimap_merge[merge](unordered_map& source); + template + void xref:#unordered_multimap_merge[merge](unordered_map&& source); + + // observers + hasher xref:#unordered_multimap_hash_function[hash_function]() const; + key_equal xref:#unordered_multimap_key_eq[key_eq]() const; + + // map operations + iterator xref:#unordered_multimap_find[find](const key_type& k); + const_iterator xref:#unordered_multimap_find[find](const key_type& k) const; + template + iterator xref:#unordered_multimap_find[find](const K& k); + template + const_iterator xref:#unordered_multimap_find[find](const K& k) const; + template + iterator xref:#unordered_multimap_find[find](CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq); + template + const_iterator xref:#unordered_multimap_find[find](CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq) const; + size_type xref:#unordered_multimap_count[count](const key_type& k) const; + template + size_type xref:#unordered_multimap_count[count](const K& k) const; + bool xref:#unordered_multimap_contains[contains](const key_type& k) const; + template + bool xref:#unordered_multimap_contains[contains](const K& k) const; + std::pair xref:#unordered_multimap_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_multimap_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_multimap_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_multimap_equal_range[equal_range](const K& k) const; + + // bucket interface + size_type xref:#unordered_multimap_bucket_count[bucket_count]() const noexcept; + size_type xref:#unordered_multimap_max_bucket_count[max_bucket_count]() const noexcept; + size_type xref:#unordered_multimap_bucket_size[bucket_size](size_type n) const; + size_type xref:#unordered_multimap_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_multimap_bucket[bucket](const K& k) const; + local_iterator xref:#unordered_multimap_begin_2[begin](size_type n); + const_local_iterator xref:#unordered_multimap_begin_2[begin](size_type n) const; + local_iterator xref:#unordered_multimap_end_2[end](size_type n); + const_local_iterator xref:#unordered_multimap_end_2[end](size_type n) const; + const_local_iterator xref:#unordered_multimap_cbegin_2[cbegin](size_type n) const; + const_local_iterator xref:#unordered_multimap_cend_2[cend](size_type n) const; + + // hash policy + float xref:#unordered_multimap_load_factor[load_factor]() const noexcept; + float xref:#unordered_multimap_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_multimap_max_load_factor[max_load_factor](float z); + void xref:#unordered_multimap_rehash[rehash](size_type n); + void xref:#unordered_multimap_reserve[reserve](size_type n); + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_multimap(InputIterator, InputIterator, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type = xref:#unordered_multimap_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multimap, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__], Hash, + Pred, Allocator>; + + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + unordered_multimap(std::initializer_list>, + typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type = xref:#unordered_multimap_deduction_guides[__see below__], Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> unordered_multimap; + + template + unordered_multimap(InputIterator, InputIterator, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_multimap, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multimap(InputIterator, InputIterator, Allocator) + -> unordered_multimap, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multimap(InputIterator, InputIterator, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_multimap, xref:#unordered_multimap_iter_mapped_type[__iter-mapped-type__], Hash, + std::equal_to>, Allocator>; + + template + unordered_multimap(std::initializer_list>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, + Allocator) + -> unordered_multimap, std::equal_to, Allocator>; + + template + unordered_multimap(std::initializer_list>, Allocator) + -> unordered_multimap, std::equal_to, Allocator>; + + template + unordered_multimap(std::initializer_list>, typename xref:#unordered_multimap_deduction_guides[__see below__]::size_type, + Hash, Allocator) + -> unordered_multimap, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_multimap_operator[operator++==++](const unordered_multimap& x, + const unordered_multimap& y); + + template + bool xref:#unordered_multimap_operator_2[operator!=](const unordered_multimap& x, + const unordered_multimap& y); + + // swap + template + void xref:#unordered_multimap_swap_2[swap](unordered_multimap& x, + unordered_multimap& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_multimap::size_type + xref:#unordered_multimap_erase_if[erase_if](unordered_multimap& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_multimap = + boost::unordered_multimap>>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container (i.e. `allocator_traits` can destroy it). + +|_T_ +|`T` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container (i.e. `allocator_traits` can destroy it). + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that implements an equivalence relation on values of type `Key`. A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type bool. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements are organized into buckets. Keys with the same hash code are stored in the same bucket. + +The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash. + +=== Configuration macros + +==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` + +Globally define this macro to support loading of ``unordered_multimap``s saved to +a Boost.Serialization archive with a version of Boost prior to Boost 1.84. + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +An iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ local_iterator; +---- + +An iterator with the same value type, difference type and pointer and reference type as iterator. + +A `local_iterator` object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_local_iterator; +---- + +A constant iterator with the same value type, difference type and pointer and reference type as const_iterator. + +A const_local_iterator object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +See node_handle_map for details. + +--- + +=== Constructors + +==== Default Constructor +```c++ +unordered_multimap(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate, `allocator_type()` as the allocator +and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_multimap(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, `a` as the allocator and a maximum +load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template +unordered_multimap(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_multimap(const unordered_multimap& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_multimap(unordered_multimap&& other); +``` + +The move constructor. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move-constructible. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_multimap(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_multimap(const Allocator& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_multimap(const unordered_multimap& other, const Allocator& a); +``` + +Constructs an container, copying ``other``'s contained elements, hash function, predicate, maximum load factor, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_multimap(unordered_multimap&& other, const Allocator& a); +``` + +Construct a container moving ``other``'s contained elements, and having the hash function, predicate and maximum load factor, but using allocate `a`. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move insertable. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_multimap(std::initializer_list il, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- +==== Bucket Count Constructor with Allocator +```c++ +unordered_multimap(size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_multimap(size_type n, const hasher& hf, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_multimap(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- +template + unordered_multimap(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_multimap(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_multimap(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_multimap(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_multimap(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_multimap& operator=(const unordered_multimap& other); +``` + +The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + +If `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, the allocator is overwritten, if not the copied elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Assignment +```c++ +unordered_multimap& operator=(unordered_multimap&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); +``` +The move assignment operator. + +If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is move constructible. + +--- + +==== Initializer List Assignment +```c++ +unordered_multimap& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container and https://en.cppreference.com/w/cpp/named_req/CopyAssignable[CopyAssignable^]. + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template iterator emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== emplace_hint +```c++ +template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments args, in the container. + +`position` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Copy Insert +```c++ +iterator insert(const value_type& obj); +``` + +Inserts `obj` in the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert +```c++ +iterator insert(value_type&& obj); +``` + +Inserts `obj` in the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Emplace Insert +```c++ +template iterator insert(P&& obj); +``` + +Inserts an element into the container by performing `emplace(std::forward

(value))`. + +Only participates in overload resolution if `std::is_constructible::value` is `true`. + +[horizontal] +Returns:;; An iterator pointing to the inserted element. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +``` +Inserts `obj` in the container. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +``` + +Inserts `obj` in the container. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Emplace Insert with Hint +```c++ +template iterator insert(const_iterator hint, P&& obj); +``` + +Inserts an element into the container by performing `emplace_hint(hint, std::forward

(value))`. + +Only participates in overload resolution if `std::is_constructible::value` is `true`. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Returns:;; An iterator pointing to the inserted element. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list il); +``` + +Inserts a range of elements into the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Extract by Iterator +```c++ +node_type extract(const_iterator position); +``` + +Removes the element pointed to by `position`. + +[horizontal] +Returns:;; A `node_type` owning the element. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. + +--- + +==== Extract by Key +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Removes an element with key equivalent to `k`. + +[horizontal] +Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_map`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert with `node_handle` +```c++ +iterator insert(node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh`. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty, returns `end()`. + ++ +Otherwise returns an iterator pointing to the newly inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_map`. + +--- + +==== Insert with Hint and `node_handle` +```c++ +iterator insert(const_iterator hint, node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh`. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty, returns `end()`. + ++ +Otherwise returns an iterator pointing to the newly inserted element. +Throws:;; If an exception is thrown by an operation other than a call to hasher the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_map`. + +--- + +==== Erase by Position + +```c++ +iterator erase(iterator position); +iterator erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; The iterator following `position` before the erasure. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; In older versions this could be inefficient because it had to search through several buckets to find the position of the returned iterator. The data structure has been changed so that this is no longer the case, and the alternative erase methods have been deprecated. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + +--- + +==== quick_erase +```c++ +void quick_erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== erase_return_void +```c++ +void erase_return_void(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== swap +```c++ +void swap(unordered_multimap& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0` +Throws:;; Never throws an exception. + +--- + +==== merge +```c++ +template + void merge(unordered_multimap& source); +template + void merge(unordered_multimap&& source); +template + void merge(unordered_map& source); +template + void merge(unordered_map&& source); +``` + +Attempt to "merge" two containers by iterating `source` and extracting all nodes in `source` and inserting them into `*this`. + +Because `source` can have a different hash function and key equality predicate, the key of each node in +`source` is rehashed using `this\->hash_function()` and then, if required, compared using `this\->key_eq()`. + +The behavior of this function is undefined if `this\->get_allocator() != source.get_allocator()`. + +This function does not copy or move any elements and instead simply relocates the nodes from `source` +into `*this`. + +[horizontal] +Notes:;; ++ +-- +* Pointers and references to transferred elements remain valid. +* Invalidates iterators to transferred elements. +* Invalidates iterators belonging to `*this`. +* Iterators to non-transferred elements in `source` remain valid. +-- + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const; +``` + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); +template + const_iterator find(const K& k) const; +template + iterator find(CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq); +template + const_iterator find(CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq) const; + +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `b.end()` if no such element exists. +Notes:;; The templated overloads containing `CompatibleKey`, `CompatibleHash` and `CompatiblePredicate` are non-standard extensions which allow you to use a compatible hash function and equality predicate for a key of a different type in order to avoid an expensive type cast. In general, its use is not encouraged and instead the `K` member function templates should be used. + ++ +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The number of buckets. + +--- + +==== max_bucket_count +```c++ +size_type max_bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; An upper bound on the number of buckets. + +--- + +==== bucket_size +```c++ +size_type bucket_size(size_type n) const; +``` + +[horizontal] +Requires:;; `n < bucket_count()` +Returns:;; The number of elements in bucket `n`. + +--- + +==== bucket +```c++ +size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; +``` + +[horizontal] +Returns:;; The index of the bucket which would contain an element with key `k`. +Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== begin + +```c++ +local_iterator begin(size_type n); +const_local_iterator begin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the first element in the bucket with index `n`. + +--- + +==== end +```c++ +local_iterator end(size_type n); +const_local_iterator end(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +==== cbegin +```c++ +const_local_iterator cbegin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the first element in the bucket with index `n`. + +--- + +==== cend +```c++ +const_local_iterator cend(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; The average number of elements per bucket. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the current maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Changes the container's maximum load factor, using `z` as a hint. + +--- + + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits::infinity()`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +==== __iter-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-key-type__ = std::remove_const_t< + std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +==== __iter-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-mapped-type__ = + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>; // exposition only +----- + +==== __iter-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-to-alloc-type__ = std::pair< + std::add_const_t>>, + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_multimap& x, + const unordered_multimap& y); +``` + +Return `true` if `x.size() == y.size()` and for every equivalent key group in `x`, there is a group in `y` for the same key, which is a permutation (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_multimap& x, + const unordered_multimap& y); +``` + +Return `false` if `x.size() == y.size()` and for every equivalent key group in `x`, there is a group in `y` for the same key, which is a permutation (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(unordered_multimap& x, + unordered_multimap& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +=== erase_if +```c++ +template + typename unordered_multimap::size_type + erase_if(unordered_multimap& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_multimap``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_multimap to an archive + +Saves all the elements of an `unordered_multimap` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `std::remove_const::type` and `std::remove_const::type` +are serializable (XML serializable), and they do support Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_multimap from an archive + +Deletes all preexisting elements of an `unordered_multimap` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_multimap` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] +from `(std::remove_const::type&&, std::remove_const::type&&)`. +`x.key_equal()` is functionally equivalent to `other.key_equal()`. +Note:;; If the archive was saved using a release of Boost prior to Boost 1.84, +the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` +has to be globally defined for this operation to succeed; otherwise, an exception is thrown. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_multimap` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_multimap` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_multiset.adoc b/doc/modules/ROOT/pages/reference/unordered_multiset.adoc new file mode 100644 index 00000000..510d4fdf --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_multiset.adoc @@ -0,0 +1,1502 @@ +[#unordered_multiset] +== Class Template unordered_multiset + +:idprefix: unordered_multiset_ + +`boost::unordered_multiset` — An unordered associative container that stores values. The same key can be stored multiple times. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator> + class unordered_multiset { + public: + // types + using key_type = Key; + using value_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + using local_iterator = _implementation-defined_; + using const_local_iterator = _implementation-defined_; + using node_type = _implementation-defined_; + + // construct/copy/destroy + xref:#unordered_multiset_default_constructor[unordered_multiset](); + explicit xref:#unordered_multiset_bucket_count_constructor[unordered_multiset](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_multiset_iterator_range_constructor[unordered_multiset](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_multiset_copy_constructor[unordered_multiset](const unordered_multiset& other); + xref:#unordered_multiset_move_constructor[unordered_multiset](unordered_multiset&& other); + template + xref:#unordered_multiset_iterator_range_constructor_with_allocator[unordered_multiset](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_multiset_allocator_constructor[unordered_multiset](const Allocator& a); + xref:#unordered_multiset_copy_constructor_with_allocator[unordered_multiset](const unordered_multiset& other, const Allocator& a); + xref:#unordered_multiset_move_constructor_with_allocator[unordered_multiset](unordered_multiset&& other, const Allocator& a); + xref:#unordered_multiset_initializer_list_constructor[unordered_multiset](std::initializer_list il, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_multiset_bucket_count_constructor_with_allocator[unordered_multiset](size_type n, const allocator_type& a); + xref:#unordered_multiset_bucket_count_constructor_with_hasher_and_allocator[unordered_multiset](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_multiset_iterator_range_constructor_with_bucket_count_and_allocator[unordered_multiset](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_multiset_iterator_range_constructor_with_bucket_count_and_hasher[unordered_multiset](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_multiset_initializer_list_constructor_with_allocator[unordered_multiset](std::initializer_list il, const allocator_type& a); + xref:#unordered_multiset_initializer_list_constructor_with_bucket_count_and_allocator[unordered_multiset](std::initializer_list il, size_type n, + const allocator_type& a) + xref:#unordered_multiset_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_multiset](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_multiset_destructor[~unordered_multiset()]; + unordered_multiset& xref:#unordered_multiset_copy_assignment[operator++=++](const unordered_multiset& other); + unordered_multiset& xref:#unordered_multiset_move_assignment[operator++=++](unordered_multiset&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); + unordered_multiset& xref:#unordered_multiset_initializer_list_assignment[operator++=++](std::initializer_list il); + allocator_type xref:#unordered_multiset_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_multiset_begin[begin]() noexcept; + const_iterator xref:#unordered_multiset_begin[begin]() const noexcept; + iterator xref:#unordered_multiset_end[end]() noexcept; + const_iterator xref:#unordered_multiset_end[end]() const noexcept; + const_iterator xref:#unordered_multiset_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_multiset_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_multiset_empty[empty]() const noexcept; + size_type xref:#unordered_multiset_size[size]() const noexcept; + size_type xref:#unordered_multiset_max_size[max_size]() const noexcept; + + // modifiers + template iterator xref:#unordered_multiset_emplace[emplace](Args&&... args); + template iterator xref:#unordered_multiset_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + iterator xref:#unordered_multiset_copy_insert[insert](const value_type& obj); + iterator xref:#unordered_multiset_move_insert[insert](value_type&& obj); + iterator xref:#unordered_multiset_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_multiset_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template void xref:#unordered_multiset_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_multiset_insert_initializer_list[insert](std::initializer_list il); + + node_type xref:#unordered_multiset_extract_by_iterator[extract](const_iterator position); + node_type xref:#unordered_multiset_extract_by_value[extract](const key_type& k); + template node_type xref:#unordered_multiset_extract_by_value[extract](K&& k); + iterator xref:#unordered_multiset_insert_with_node_handle[insert](node_type&& nh); + iterator xref:#unordered_multiset_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); + + iterator xref:#unordered_multiset_erase_by_position[erase](iterator position); + iterator xref:#unordered_multiset_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_multiset_erase_by_value[erase](const key_type& k); + template size_type xref:#unordered_multiset_erase_by_value[erase](K&& x); + iterator xref:#unordered_multiset_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_multiset_quick_erase[quick_erase](const_iterator position); + void xref:#unordered_multiset_erase_return_void[erase_return_void](const_iterator position); + void xref:#unordered_multiset_swap[swap](unordered_multiset&) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); + void xref:#unordered_multiset_clear[clear]() noexcept; + + template + void xref:#unordered_multiset_merge[merge](unordered_multiset& source); + template + void xref:#unordered_multiset_merge[merge](unordered_multiset&& source); + template + void xref:#unordered_multiset_merge[merge](unordered_set& source); + template + void xref:#unordered_multiset_merge[merge](unordered_set&& source); + + // observers + hasher xref:#unordered_multiset_hash_function[hash_function]() const; + key_equal xref:#unordered_multiset_key_eq[key_eq]() const; + + // set operations + iterator xref:#unordered_multiset_find[find](const key_type& k); + const_iterator xref:#unordered_multiset_find[find](const key_type& k) const; + template + iterator xref:#unordered_multiset_find[find](const K& k); + template + const_iterator xref:#unordered_multiset_find[find](const K& k) const; + template + iterator xref:#unordered_multiset_find[find](CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&); + template + const_iterator xref:#unordered_multiset_find[find](CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&) const; + size_type xref:#unordered_multiset_count[count](const key_type& k) const; + template + size_type xref:#unordered_multiset_count[count](const K& k) const; + bool xref:#unordered_multiset_contains[contains](const key_type& k) const; + template + bool xref:#unordered_multiset_contains[contains](const K& k) const; + std::pair xref:#unordered_multiset_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_multiset_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_multiset_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_multiset_equal_range[equal_range](const K& k) const; + + // bucket interface + size_type xref:#unordered_multiset_bucket_count[bucket_count]() const noexcept; + size_type xref:#unordered_multiset_max_bucket_count[max_bucket_count]() const noexcept; + size_type xref:#unordered_multiset_bucket_size[bucket_size](size_type n) const; + size_type xref:#unordered_multiset_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_multiset_bucket[bucket](const K& k) const; + local_iterator xref:#unordered_multiset_begin_2[begin](size_type n); + const_local_iterator xref:#unordered_multiset_begin_2[begin](size_type n) const; + local_iterator xref:#unordered_multiset_end_2[end](size_type n); + const_local_iterator xref:#unordered_multiset_end_2[end](size_type n) const; + const_local_iterator xref:#unordered_multiset_cbegin_2[cbegin](size_type n) const; + const_local_iterator xref:#unordered_multiset_cend_2[cend](size_type n) const; + + // hash policy + float xref:#unordered_multiset_load_factor[load_factor]() const noexcept; + float xref:#unordered_multiset_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_multiset_set_max_load_factor[max_load_factor](float z); + void xref:#unordered_multiset_rehash[rehash](size_type n); + void xref:#unordered_multiset_reserve[reserve](size_type n); + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_multiset(InputIterator, InputIterator, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset, Hash, Pred, Allocator>; + + template, class Pred = std::equal_to, + class Allocator = std::allocator> + unordered_multiset(std::initializer_list, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type = xref:#unordered_multiset_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_multiset; + + template + unordered_multiset(InputIterator, InputIterator, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_multiset, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multiset(InputIterator, InputIterator, Allocator) + -> unordered_multiset, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_multiset(InputIterator, InputIterator, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_multiset, Hash, + std::equal_to>, Allocator>; + + template + unordered_multiset(std::initializer_list, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_multiset, std::equal_to, Allocator>; + + template + unordered_multiset(std::initializer_list, Allocator) + -> unordered_multiset, std::equal_to, Allocator>; + + template + unordered_multiset(std::initializer_list, typename xref:#unordered_multiset_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> unordered_multiset, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_multiset_operator[operator++==++](const unordered_multiset& x, + const unordered_multiset& y); + + template + bool xref:#unordered_multiset_operator_2[operator!=](const unordered_multiset& x, + const unordered_multiset& y); + + // swap + template + void xref:#unordered_multiset_swap_2[swap](unordered_multiset& x, + unordered_multiset& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_multiset::size_type + xref:#unordered_multiset_erase_if[erase_if](unordered_multiset& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_multiset = + boost::unordered_multiset>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container (i.e. `allocator_traits` can destroy it). + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that implements an equivalence relation on values of type `Key`. A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type bool. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements are organized into buckets. Keys with the same hash code are stored in the same bucket and elements with equivalent keys are stored next to each other. + +The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash. + +=== Configuration macros + +==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` + +Globally define this macro to support loading of ``unordered_multiset``s saved to +a Boost.Serialization archive with a version of Boost prior to Boost 1.84. + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ local_iterator; +---- + +An iterator with the same value type, difference type and pointer and reference type as iterator. + +A `local_iterator` object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_local_iterator; +---- + +A constant iterator with the same value type, difference type and pointer and reference type as const_iterator. + +A const_local_iterator object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +See node_handle_set for details. + +--- + +=== Constructors + +==== Default Constructor +```c++ +unordered_multiset(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate, `allocator_type()` as the allocator +and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_multiset(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, `a` as the allocator and a maximum +load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_multiset(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_multiset(const unordered_multiset& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_multiset(unordered_multiset&& other); +``` + +The move constructor. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move-constructible. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_multiset(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_multiset(const Allocator& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_multiset(const unordered_multiset& other, const Allocator& a); +``` + +Constructs an container, copying ``other``'s contained elements, hash function, predicate, maximum load factor, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_multiset(unordered_multiset&& other, const Allocator& a); +``` + +Construct a container moving ``other``'s contained elements, and having the hash function, predicate and maximum load factor, but using allocate `a`. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move insertable. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_multiset(std::initializer_list il, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_multiset(size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_multiset(size_type n, const hasher& hf, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_multiset(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- +template + unordered_multiset(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_multiset(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_multiset(std::initializer_list il, size_type n, const allocator_type& a) +``` + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ + unordered_multiset(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_multiset(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_multiset& operator=(const unordered_multiset& other); +``` + +The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + +If `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, the allocator is overwritten, if not the copied elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Assignment +```c++ +unordered_multiset& operator=(unordered_multiset&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); +``` +The move assignment operator. + +If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is move constructible. + +--- + +==== Initializer List Assignment +```c++ +unordered_multiset& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container and https://en.cppreference.com/w/cpp/named_req/CopyAssignable[CopyAssignable^]. + +--- + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template iterator emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments args, in the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== emplace_hint +```c++ +template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments args, in the container. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Copy Insert +```c++ +iterator insert(const value_type& obj); +``` + +Inserts `obj` in the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert +```c++ +iterator insert(value_type&& obj); +``` + +Inserts `obj` in the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +``` + +Inserts `obj` in the container. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +``` + +Inserts `obj` in the container. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; An iterator pointing to the inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list il); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Extract by Iterator +```c++ +node_type extract(const_iterator position); +``` + +Removes the element pointed to by `position`. + +[horizontal] +Returns:;; A `node_type` owning the element. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. + +--- + +==== Extract by Value +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Removes an element with key equivalent to `k`. + +[horizontal] +Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; A node extracted using this method can be inserted into a compatible `unordered_set`. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert with `node_handle` +```c++ +iterator insert(node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh`. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty, returns `end()`. + ++ +Otherwise returns an iterator pointing to the newly inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_set`. + +--- + +==== Insert with Hint and `node_handle` +```c++ +iterator insert(const_iterator hint, node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh`. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty, returns `end()`. + ++ +Otherwise returns an iterator pointing to the newly inserted element. +Throws:;; If an exception is thrown by an operation other than a call to hasher the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_set`. + +--- + +==== Erase by Position + +```c++ +iterator erase(iterator position); +iterator erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; The iterator following `position` before the erasure. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; In older versions this could be inefficient because it had to search through several buckets to find the position of the returned iterator. The data structure has been changed so that this is no longer the case, and the alternative erase methods have been deprecated. + +--- + +==== Erase by Value +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& x); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + +--- + +==== quick_erase +```c++ +void quick_erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== erase_return_void +```c++ +void erase_return_void(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== swap +```c++ +void swap(unordered_multiset&) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0` +Throws:;; Never throws an exception. + +--- + +==== merge +```c++ +template + void merge(unordered_multiset& source); +template + void merge(unordered_multiset&& source); +template + void merge(unordered_set& source); +template + void merge(unordered_set&& source); +``` + +Attempt to "merge" two containers by iterating `source` and extracting all nodes in `source` and inserting them into `*this`. + +Because `source` can have a different hash function and key equality predicate, the key of each node in +`source` is rehashed using `this\->hash_function()` and then, if required, compared using `this\->key_eq()`. + +The behavior of this function is undefined if `this\->get_allocator() != source.get_allocator()`. + +This function does not copy or move any elements and instead simply relocates the nodes from `source` +into `*this`. + +[horizontal] +Notes:;; ++ +-- +* Pointers and references to transferred elements remain valid. +* Invalidates iterators to transferred elements. +* Invalidates iterators belonging to `*this`. +* Iterators to non-transferred elements in `source` remain valid. +-- + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq + +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); +template + const_iterator find(const K& k) const; +template + iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&); +template + const_iterator find(CompatibleKey const&, CompatibleHash const&, + CompatiblePredicate const&) const; +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `b.end()` if no such element exists. +Notes:;; The templated overloads containing `CompatibleKey`, `CompatibleHash` and `CompatiblePredicate` are non-standard extensions which allow you to use a compatible hash function and equality predicate for a key of a different type in order to avoid an expensive type cast. In general, its use is not encouraged and instead the `K` member function templates should be used. + ++ +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The number of buckets. + +--- + +==== max_bucket_count +```c++ +size_type max_bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; An upper bound on the number of buckets. + +--- + +==== bucket_size +```c++ +size_type bucket_size(size_type n) const; +``` + +[horizontal] +Requires:;; `n < bucket_count()` +Returns:;; The number of elements in bucket `n`. + +--- + +==== bucket +```c++ +size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; +``` + +[horizontal] +Returns:;; The index of the bucket which would contain an element with key `k`. +Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== begin + +```c++ +local_iterator begin(size_type n); +const_local_iterator begin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the first element in the bucket with index `n`. + +--- + +==== end +```c++ +local_iterator end(size_type n); +const_local_iterator end(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +==== cbegin +```c++ +const_local_iterator cbegin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the first element in the bucket with index `n`. + +--- + +==== cend +```c++ +const_local_iterator cend(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; The average number of elements per bucket. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the current maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Changes the container's maximum load factor, using `z` as a hint. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits::infinity()`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_multiset& x, + const unordered_multiset& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_multiset& x, + const unordered_multiset& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(unordered_multiset& x, + unordered_multiset& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +=== erase_if +```c++ +template + typename unordered_multiset::size_type + erase_if(unordered_multiset& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_multiset``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_multiset to an archive + +Saves all the elements of an `unordered_multiset` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `value_type` +is serializable (XML serializable), and it supports Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_multiset from an archive + +Deletes all preexisting elements of an `unordered_multiset` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_multiset` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +`x.key_equal()` is functionally equivalent to `other.key_equal()`. +Note:;; If the archive was saved using a release of Boost prior to Boost 1.84, +the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` +has to be globally defined for this operation to succeed; otherwise, an exception is thrown. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_multiset` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_multiset` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_node_map.adoc b/doc/modules/ROOT/pages/reference/unordered_node_map.adoc new file mode 100644 index 00000000..21f7c392 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_node_map.adoc @@ -0,0 +1,1691 @@ +[#unordered_node_map] +== Class Template unordered_node_map + +:idprefix: unordered_node_map_ + +`boost::unordered_node_map` — A node-based, open-addressing unordered associative container that associates unique keys with another value. + +`boost::unordered_node_map` uses an open-addressing layout like `boost::unordered_flat_map`, but, +being node-based, it provides pointer stability and node handling functionalities. +Its performance lies between those of `boost::unordered_map` and `boost::unordered_flat_map`. + +As a result of its using open addressing, the interface of `boost::unordered_node_map` deviates in +a number of aspects from that of `boost::unordered_map`/`std::unordered_map`: + + - `begin()` is not constant-time. + - There is no API for bucket handling (except `bucket_count`). + - The maximum load factor of the container is managed internally and can't be set by the user. + +Other than this, `boost::unordered_node_map` is mostly a drop-in replacement of standard +unordered associative containers. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + class unordered_node_map { + public: + // types + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using init_type = std::pair< + typename std::remove_const::type, + typename std::remove_const::type + >; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + + using node_type = _implementation-defined_; + using insert_return_type = _implementation-defined_; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:unordered_node_map_boost_unordered_enable_stats[enabled] + + // construct/copy/destroy + xref:#unordered_node_map_default_constructor[unordered_node_map](); + explicit xref:#unordered_node_map_bucket_count_constructor[unordered_node_map](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_node_map_iterator_range_constructor[unordered_node_map](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_node_map_copy_constructor[unordered_node_map](const unordered_node_map& other); + xref:#unordered_node_map_move_constructor[unordered_node_map](unordered_node_map&& other); + template + xref:#unordered_node_map_iterator_range_constructor_with_allocator[unordered_node_map](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_node_map_allocator_constructor[unordered_node_map](const Allocator& a); + xref:#unordered_node_map_copy_constructor_with_allocator[unordered_node_map](const unordered_node_map& other, const Allocator& a); + xref:#unordered_node_map_move_constructor_with_allocator[unordered_node_map](unordered_node_map&& other, const Allocator& a); + xref:#unordered_node_map_move_constructor_from_concurrent_node_map[unordered_node_map](concurrent_node_map&& other); + xref:#unordered_node_map_initializer_list_constructor[unordered_node_map](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_node_map_bucket_count_constructor_with_allocator[unordered_node_map](size_type n, const allocator_type& a); + xref:#unordered_node_map_bucket_count_constructor_with_hasher_and_allocator[unordered_node_map](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_node_map_iterator_range_constructor_with_bucket_count_and_allocator[unordered_node_map](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_node_map_iterator_range_constructor_with_bucket_count_and_hasher[unordered_node_map](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_node_map_initializer_list_constructor_with_allocator[unordered_node_map](std::initializer_list il, const allocator_type& a); + xref:#unordered_node_map_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_map](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#unordered_node_map_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_node_map](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_node_map_destructor[~unordered_node_map](); + unordered_node_map& xref:#unordered_node_map_copy_assignment[operator++=++](const unordered_node_map& other); + unordered_node_map& xref:#unordered_node_map_move_assignment[operator++=++](unordered_node_map&& other) ++noexcept( + (boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value);++ + unordered_node_map& xref:#unordered_node_map_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#unordered_node_map_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_node_map_begin[begin]() noexcept; + const_iterator xref:#unordered_node_map_begin[begin]() const noexcept; + iterator xref:#unordered_node_map_end[end]() noexcept; + const_iterator xref:#unordered_node_map_end[end]() const noexcept; + const_iterator xref:#unordered_node_map_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_node_map_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_node_map_empty[empty]() const noexcept; + size_type xref:#unordered_node_map_size[size]() const noexcept; + size_type xref:#unordered_node_map_max_size[max_size]() const noexcept; + + // modifiers + template std::pair xref:#unordered_node_map_emplace[emplace](Args&&... args); + template iterator xref:#unordered_node_map_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + std::pair xref:#unordered_node_map_copy_insert[insert](const value_type& obj); + std::pair xref:#unordered_node_map_copy_insert[insert](const init_type& obj); + std::pair xref:#unordered_node_map_move_insert[insert](value_type&& obj); + std::pair xref:#unordered_node_map_move_insert[insert](init_type&& obj); + iterator xref:#unordered_node_map_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_node_map_copy_insert_with_hint[insert](const_iterator hint, const init_type& obj); + iterator xref:#unordered_node_map_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + iterator xref:#unordered_node_map_copy_insert_with_hint[insert](const_iterator hint, init_type&& obj); + template void xref:#unordered_node_map_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_node_map_insert_initializer_list[insert](std::initializer_list); + insert_return_type xref:#unordered_node_map_insert_node[insert](node_type&& nh); + iterator xref:#unordered_node_map_insert_node_with_hint[insert](const_iterator hint, node_type&& nh); + + template + std::pair xref:#unordered_node_map_try_emplace[try_emplace](const key_type& k, Args&&... args); + template + std::pair xref:#unordered_node_map_try_emplace[try_emplace](key_type&& k, Args&&... args); + template + std::pair xref:#unordered_node_map_try_emplace[try_emplace](K&& k, Args&&... args); + template + iterator xref:#unordered_node_map_try_emplace_with_hint[try_emplace](const_iterator hint, const key_type& k, Args&&... args); + template + iterator xref:#unordered_node_map_try_emplace_with_hint[try_emplace](const_iterator hint, key_type&& k, Args&&... args); + template + iterator xref:#unordered_node_map_try_emplace_with_hint[try_emplace](const_iterator hint, K&& k, Args&&... args); + template + std::pair xref:#unordered_node_map_insert_or_assign[insert_or_assign](const key_type& k, M&& obj); + template + std::pair xref:#unordered_node_map_insert_or_assign[insert_or_assign](key_type&& k, M&& obj); + template + std::pair xref:#unordered_node_map_insert_or_assign[insert_or_assign](K&& k, M&& obj); + template + iterator xref:#unordered_node_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, const key_type& k, M&& obj); + template + iterator xref:#unordered_node_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, key_type&& k, M&& obj); + template + iterator xref:#unordered_node_map_insert_or_assign_with_hint[insert_or_assign](const_iterator hint, K&& k, M&& obj); + + _convertible-to-iterator_ xref:#unordered_node_map_erase_by_position[erase](iterator position); + _convertible-to-iterator_ xref:#unordered_node_map_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_node_map_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_node_map_erase_by_key[erase](K&& k); + iterator xref:#unordered_node_map_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_node_map_swap[swap](unordered_node_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + node_type xref:#unordered_node_map_extract_by_position[extract](const_iterator position); + node_type xref:#unordered_node_map_extract_by_key[extract](const key_type& key); + template node_type xref:#unordered_node_map_extract_by_key[extract](K&& key); + void xref:#unordered_node_map_clear[clear]() noexcept; + + template + void xref:#unordered_node_map_merge[merge](unordered_node_map& source); + template + void xref:#unordered_node_map_merge[merge](unordered_node_map&& source); + + // observers + hasher xref:#unordered_node_map_hash_function[hash_function]() const; + key_equal xref:#unordered_node_map_key_eq[key_eq]() const; + + // map operations + iterator xref:#unordered_node_map_find[find](const key_type& k); + const_iterator xref:#unordered_node_map_find[find](const key_type& k) const; + template + iterator xref:#unordered_node_map_find[find](const K& k); + template + const_iterator xref:#unordered_node_map_find[find](const K& k) const; + size_type xref:#unordered_node_map_count[count](const key_type& k) const; + template + size_type xref:#unordered_node_map_count[count](const K& k) const; + bool xref:#unordered_node_map_contains[contains](const key_type& k) const; + template + bool xref:#unordered_node_map_contains[contains](const K& k) const; + std::pair xref:#unordered_node_map_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_node_map_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_node_map_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_node_map_equal_range[equal_range](const K& k) const; + + // element access + mapped_type& xref:#unordered_node_map_operator[operator[+]+](const key_type& k); + mapped_type& xref:#unordered_node_map_operator[operator[+]+](key_type&& k); + template mapped_type& xref:#unordered_node_map_operator[operator[+]+](K&& k); + mapped_type& xref:#unordered_node_map_at[at](const key_type& k); + const mapped_type& xref:#unordered_node_map_at[at](const key_type& k) const; + template mapped_type& xref:#unordered_node_map_at[at](const K& k); + template const mapped_type& xref:#unordered_node_map_at[at](const K& k) const; + + // bucket interface + size_type xref:#unordered_node_map_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#unordered_node_map_load_factor[load_factor]() const noexcept; + float xref:#unordered_node_map_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_node_map_set_max_load_factor[max_load_factor](float z); + size_type xref:#unordered_node_map_max_load[max_load]() const noexcept; + void xref:#unordered_node_map_rehash[rehash](size_type n); + void xref:#unordered_node_map_reserve[reserve](size_type n); + + // statistics (if xref:unordered_node_map_boost_unordered_enable_stats[enabled]) + stats xref:#unordered_node_map_get_stats[get_stats]() const; + void xref:#unordered_node_map_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_node_map(InputIterator, InputIterator, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type = xref:#unordered_node_map_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_node_map, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__], Hash, + Pred, Allocator>; + + template, + class Pred = std::equal_to, + class Allocator = std::allocator>> + unordered_node_map(std::initializer_list>, + typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type = xref:#unordered_node_map_deduction_guides[__see below__], Hash = Hash(), + Pred = Pred(), Allocator = Allocator()) + -> unordered_node_map; + + template + unordered_node_map(InputIterator, InputIterator, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_node_map, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_map(InputIterator, InputIterator, Allocator) + -> unordered_node_map, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__], + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_map(InputIterator, InputIterator, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_node_map, xref:#unordered_node_map_iter_mapped_type[__iter-mapped-type__], Hash, + std::equal_to>, Allocator>; + + template + unordered_node_map(std::initializer_list>, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, + Allocator) + -> unordered_node_map, std::equal_to, Allocator>; + + template + unordered_node_map(std::initializer_list>, Allocator) + -> unordered_node_map, std::equal_to, Allocator>; + + template + unordered_node_map(std::initializer_list>, typename xref:#unordered_node_map_deduction_guides[__see below__]::size_type, + Hash, Allocator) + -> unordered_node_map, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_node_map_operator_2[operator==](const unordered_node_map& x, + const unordered_node_map& y); + + template + bool xref:#unordered_node_map_operator_3[operator!=](const unordered_node_map& x, + const unordered_node_map& y); + + // swap + template + void xref:#unordered_node_map_swap_2[swap](unordered_node_map& x, + unordered_node_map& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_node_map::size_type + xref:#unordered_node_map_erase_if[erase_if](unordered_node_map& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_node_map = + boost::unordered_node_map>>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +.2+|`std::pair` must be https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] +into the container from any `std::pair` object convertible to it, and it also must be +https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container. + +|_T_ + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The element nodes of the container are held into an internal _bucket array_. A node is inserted into a bucket determined by the +hash code of its element, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the container (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the container. Note +that this option decreases the overall performance of many operations. + +--- + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +An iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +A class for holding extracted container elements, modelling +https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle]. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ insert_return_type; +---- + +A specialization of an internal class template: + +[source,c++,subs=+quotes] +---- +template +struct _insert_return_type_ // name is exposition only +{ + Iterator position; + bool inserted; + NodeType node; +}; +---- + +with `Iterator` = `iterator` and `NodeType` = `node_type`. + +--- + +=== Constructors + +==== Default Constructor +```c++ +unordered_node_map(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_node_map(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_node_map(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_node_map(unordered_node_map const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +--- + +==== Move Constructor +```c++ +unordered_node_map(unordered_node_map&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_node_map(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_node_map(Allocator const& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_node_map(unordered_node_map const& other, Allocator const& a); +``` + +Constructs a container, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_node_map(unordered_node_map&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the element nodes of `other` are transferred directly to the new container; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:unordered_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Move Constructor from concurrent_node_map + +```c++ +unordered_node_map(concurrent_node_map&& other); +``` + +Move construction from a xref:#concurrent_node_map[`concurrent_node_map`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; Constant time. +Concurrency:;; Blocking on `other`. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_node_map(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_node_map(size_type n, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_node_map(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_node_map(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + unordered_node_map(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_node_map(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_node_map(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_node_map(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_node_map(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_node_map& operator=(unordered_node_map const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +--- + +==== Move Assignment +```c++ +unordered_node_map& operator=(unordered_node_map&& other) + noexcept((boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to the new container; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:unordered_node_map_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Initializer List Assignment +```c++ +unordered_node_map& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template std::pair emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. This optimization happens when `key_type` is move constructible or when the `k` argument is a `key_type`. + +--- + +==== emplace_hint +```c++ + template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +`position` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +If `args...` is of the form `k,v`, it delays constructing the whole object until it is certain that an element should be inserted, using only the `k` argument to check. This optimization happens when `key_type` is move constructible or when the `k` argument is a `key_type`. + +--- + +==== Copy Insert +```c++ +std::pair insert(const value_type& obj); +std::pair insert(const init_type& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(x)`, where `x` is equally convertible to both `const value_type&` and `const init_type&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Move Insert +```c++ +std::pair insert(value_type&& obj); +std::pair insert(init_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(x)`, where `x` is equally convertible to both `value_type&&` and `init_type&&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +iterator insert(const_iterator hint, const init_type& obj); +``` +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(hint, x)`, where `x` is equally convertible to both `const value_type&` and `const init_type&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +iterator insert(const_iterator hint, init_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +A call of the form `insert(hint, x)`, where `x` is equally convertible to both `value_type&&` and `init_type&&`, is not ambiguous and selects the `init_type` overload. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Insert Node +```c++ +insert_return_type insert(node_type&& nh); +``` + +If `nh` is not empty, inserts the associated element in the container if and only if there is no element in the container with a key equivalent to `nh.key()`. +`nh` is empty when the function returns. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `position`, `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false`, `position` is `end()`, and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true, `position` points to the inserted element, and `node` is empty. +* If the insertion failed, `inserted` is false, `node` has the previous value of `nh`, and `position` points to an element with a key equivalent to `nh.key()`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== Insert Node with Hint +```c++ +iterator insert(const_iterator hint, node_type&& nh); +``` + +If `nh` is not empty, inserts the associated element in the container if and only if there is no element in the container with a key equivalent to `nh.key()`. +`nh` becomes empty if insertion took place, otherwise it is not changed. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Returns:;; The iterator returned is `end()` if `nh` is empty. +If insertion took place, then the iterator points to the newly inserted element; otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== try_emplace +```c++ +template + std::pair try_emplace(const key_type& k, Args&&... args); +template + std::pair try_emplace(key_type&& k, Args&&... args); +template + std::pair try_emplace(K&& k, Args&&... args); +``` + +Inserts a new element into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +[horizontal] +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_node_map_emplace[emplace], with the difference that no `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +unlike xref:#unordered_node_map_emplace[emplace], which simply forwards all arguments to ``value_type``'s constructor. + +Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== try_emplace with Hint +```c++ +template + iterator try_emplace(const_iterator hint, const key_type& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, key_type&& k, Args&&... args); +template + iterator try_emplace(const_iterator hint, K&& k, Args&&... args); +``` + +Inserts a new element into the container if there is no existing element with key `k` contained within it. + +If there is an existing element with key `k` this function does nothing. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; This function is similiar to xref:#unordered_node_map_emplace_hint[emplace_hint], with the difference that no `value_type` is constructed +if there is an element with an equivalent key; otherwise, the construction is of the form: + ++ +-- +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(args)...)) +``` + +unlike xref:#unordered_node_map_emplace_hint[emplace_hint], which simply forwards all arguments to ``value_type``'s constructor. + +Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +-- + +--- + +==== insert_or_assign +```c++ +template + std::pair insert_or_assign(const key_type& k, M&& obj); +template + std::pair insert_or_assign(key_type&& k, M&& obj); +template + std::pair insert_or_assign(K&& k, M&& obj); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +[horizontal] +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== insert_or_assign with Hint +```c++ +template + iterator insert_or_assign(const_iterator hint, const key_type& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, key_type&& k, M&& obj); +template + iterator insert_or_assign(const_iterator hint, K&& k, M&& obj); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `std::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +// first two overloads +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) + +// third overload +value_type(std::piecewise_construct, + std::forward_as_tuple(std::forward(k)), + std::forward_as_tuple(std::forward(obj))) +``` + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + + +==== Erase by Position + +[source,c++,subs=+quotes] +---- +_convertible-to-iterator_ erase(iterator position); +_convertible-to-iterator_ erase(const_iterator position); +---- + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; An opaque object implicitly convertible to the `iterator` or `const_iterator` +immediately following `position` prior to the erasure. +Throws:;; Nothing. +Notes:;; The opaque object returned must only be discarded or immediately converted to `iterator` or `const_iterator`. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Nothing in this implementation (neither the `hasher` nor the `key_equal` objects are called). + +--- + +==== swap +```c++ +void swap(unordered_node_map& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +==== Extract by Position +```c++ +node_type extract(const_iterator position); +``` + +Extracts the element pointed to by `position`. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element. +Throws:;; Nothing. + +--- + +==== Extract by Key +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Extracts the element with key equivalent to `k`, if it exists. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` + +--- + +==== merge +```c++ +template + void merge(unordered_node_map& source); +template + void merge(unordered_node_map&& source); +``` + +Transfers all the element nodes from `source` whose key is not already present in `*this`. + +[horizontal] +Requires:;; `this\->get_allocator() == source.get_allocator()`. +Notes:;; Invalidates iterators to the elements transferred. +If the resulting size of `*this` is greater than its original maximum load, +invalidates all iterators associated to `*this`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The container's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); + +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `end()` if no such element exists. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== operator++[++++]++ +```c++ +mapped_type& operator[](const key_type& k); +mapped_type& operator[](key_type&& k); +template mapped_type& operator[](K&& k); +``` + +[horizontal] +Effects:;; If the container does not already contain an element with a key equivalent to `k`, inserts the value `std::pair(k, mapped_type())`. +Returns:;; A reference to `x.second` where `x` is the element already in the container, or the newly inserted element with a key equivalent to `k`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== at +```c++ +mapped_type& at(const key_type& k); +const mapped_type& at(const key_type& k) const; +template mapped_type& at(const K& k); +template const mapped_type& at(const K& k) const; +``` + +[horizontal] +Returns:;; A reference to `x.second` where `x` is the (unique) element whose key is equivalent to `k`. +Throws:;; An exception object of type `std::out_of_range` if no such element is present. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the container's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_map`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the container can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the container's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed. + +Invalidates iterators and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the container so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_node_map_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the container. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_node_map_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +==== __iter-key-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-key-type__ = std::remove_const_t< + std::tuple_element_t<0, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +==== __iter-mapped-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-mapped-type__ = + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>; // exposition only +----- + +==== __iter-to-alloc-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-to-alloc-type__ = std::pair< + std::add_const_t>>, + std::tuple_element_t<1, xref:#unordered_map_iter_value_type[__iter-value-type__]>>; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_node_map& x, + const unordered_node_map& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_node_map& x, + const unordered_node_map& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +=== Swap +```c++ +template + void swap(unordered_node_map& x, + unordered_node_map& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +=== erase_if +```c++ +template + typename unordered_node_map::size_type + erase_if(unordered_node_map& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_node_map``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_node_map to an archive + +Saves all the elements of an `unordered_node_map` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `std::remove_const::type` and `std::remove_const::type` +are serializable (XML serializable), and they do support Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_node_map from an archive + +Deletes all preexisting elements of an `unordered_node_map` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_node_map` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `key_type` and `mapped_type` are constructible from +`std::remove_const::type&&` and `std::remove_const::type&&`, +respectively. +`x.key_equal()` is functionally equivalent to `other.key_equal()`. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_node_map` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_node_map` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_node_set.adoc b/doc/modules/ROOT/pages/reference/unordered_node_set.adoc new file mode 100644 index 00000000..7b52cc1b --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_node_set.adoc @@ -0,0 +1,1441 @@ +[#unordered_node_set] +== Class Template unordered_node_set + +:idprefix: unordered_node_set_ + +`boost::unordered_node_set` — A node-based, open-addressing unordered associative container that stores unique values. + +`boost::unordered_node_set` uses an open-addressing layout like `boost::unordered_flat_set`, but, +being node-based, it provides pointer stability and node handling functionalities. +Its performance lies between those of `boost::unordered_set` and `boost::unordered_flat_set`. + +As a result of its using open addressing, the interface of `boost::unordered_node_set` deviates in +a number of aspects from that of `boost::unordered_set`/`std::unordered_set`: + + - `begin()` is not constant-time. + - There is no API for bucket handling (except `bucket_count`). + - The maximum load factor of the container is managed internally and can't be set by the user. + +Other than this, `boost::unordered_node_set` is mostly a drop-in replacement of standard +unordered associative containers. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator> + class unordered_node_set { + public: + // types + using key_type = Key; + using value_type = Key; + using init_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + + using node_type = _implementation-defined_; + using insert_return_type = _implementation-defined_; + + using stats = xref:stats_stats_type[__stats-type__]; // if statistics are xref:unordered_node_set_boost_unordered_enable_stats[enabled] + + // construct/copy/destroy + xref:#unordered_node_set_default_constructor[unordered_node_set](); + explicit xref:#unordered_node_set_bucket_count_constructor[unordered_node_set](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_node_set_iterator_range_constructor[unordered_node_set](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_node_set_copy_constructor[unordered_node_set](const unordered_node_set& other); + xref:#unordered_node_set_move_constructor[unordered_node_set](unordered_node_set&& other); + template + xref:#unordered_node_set_iterator_range_constructor_with_allocator[unordered_node_set](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_node_set_allocator_constructor[unordered_node_set](const Allocator& a); + xref:#unordered_node_set_copy_constructor_with_allocator[unordered_node_set](const unordered_node_set& other, const Allocator& a); + xref:#unordered_node_set_move_constructor_with_allocator[unordered_node_set](unordered_node_set&& other, const Allocator& a); + xref:#unordered_node_set_move_constructor_from_concurrent_node_set[unordered_node_set](concurrent_node_set&& other); + xref:#unordered_node_set_initializer_list_constructor[unordered_node_set](std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_node_set_bucket_count_constructor_with_allocator[unordered_node_set](size_type n, const allocator_type& a); + xref:#unordered_node_set_bucket_count_constructor_with_hasher_and_allocator[unordered_node_set](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_node_set_iterator_range_constructor_with_bucket_count_and_allocator[unordered_node_set](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_node_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_node_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_node_set_initializer_list_constructor_with_allocator[unordered_node_set](std::initializer_list il, const allocator_type& a); + xref:#unordered_node_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_node_set](std::initializer_list il, size_type n, + const allocator_type& a); + xref:#unordered_node_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_node_set](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_node_set_destructor[~unordered_node_set](); + unordered_node_set& xref:#unordered_node_set_copy_assignment[operator++=++](const unordered_node_set& other); + unordered_node_set& xref:#unordered_node_set_move_assignment[operator++=++](unordered_node_set&& other) ++noexcept( + (boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value);++ + unordered_node_set& xref:#unordered_node_set_initializer_list_assignment[operator++=++](std::initializer_list); + allocator_type xref:#unordered_node_set_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_node_set_begin[begin]() noexcept; + const_iterator xref:#unordered_node_set_begin[begin]() const noexcept; + iterator xref:#unordered_node_set_end[end]() noexcept; + const_iterator xref:#unordered_node_set_end[end]() const noexcept; + const_iterator xref:#unordered_node_set_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_node_set_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_node_set_empty[empty]() const noexcept; + size_type xref:#unordered_node_set_size[size]() const noexcept; + size_type xref:#unordered_node_set_max_size[max_size]() const noexcept; + + // modifiers + template std::pair xref:#unordered_node_set_emplace[emplace](Args&&... args); + template iterator xref:#unordered_node_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + std::pair xref:#unordered_node_set_copy_insert[insert](const value_type& obj); + std::pair xref:#unordered_node_set_move_insert[insert](value_type&& obj); + template std::pair xref:#unordered_node_set_transparent_insert[insert](K&& k); + iterator xref:#unordered_node_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_node_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_node_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); + template void xref:#unordered_node_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_node_set_insert_initializer_list[insert](std::initializer_list); + insert_return_type xref:#unordered_node_set_insert_node[insert](node_type&& nh); + iterator xref:#unordered_node_set_insert_node_with_hint[insert](const_iterator hint, node_type&& nh); + + _convertible-to-iterator_ xref:#unordered_node_set_erase_by_position[erase](iterator position); + _convertible-to-iterator_ xref:#unordered_node_set_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_node_set_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_node_set_erase_by_key[erase](K&& k); + iterator xref:#unordered_node_set_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_node_set_swap[swap](unordered_node_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); + node_type xref:#unordered_node_set_extract_by_position[extract](const_iterator position); + node_type xref:#unordered_node_set_extract_by_key[extract](const key_type& key); + template node_type xref:#unordered_node_set_extract_by_key[extract](K&& key); + void xref:#unordered_node_set_clear[clear]() noexcept; + + template + void xref:#unordered_node_set_merge[merge](unordered_node_set& source); + template + void xref:#unordered_node_set_merge[merge](unordered_node_set&& source); + + // observers + hasher xref:#unordered_node_set_hash_function[hash_function]() const; + key_equal xref:#unordered_node_set_key_eq[key_eq]() const; + + // set operations + iterator xref:#unordered_node_set_find[find](const key_type& k); + const_iterator xref:#unordered_node_set_find[find](const key_type& k) const; + template + iterator xref:#unordered_node_set_find[find](const K& k); + template + const_iterator xref:#unordered_node_set_find[find](const K& k) const; + size_type xref:#unordered_node_set_count[count](const key_type& k) const; + template + size_type xref:#unordered_node_set_count[count](const K& k) const; + bool xref:#unordered_node_set_contains[contains](const key_type& k) const; + template + bool xref:#unordered_node_set_contains[contains](const K& k) const; + std::pair xref:#unordered_node_set_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_node_set_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_node_set_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_node_set_equal_range[equal_range](const K& k) const; + + // bucket interface + size_type xref:#unordered_node_set_bucket_count[bucket_count]() const noexcept; + + // hash policy + float xref:#unordered_node_set_load_factor[load_factor]() const noexcept; + float xref:#unordered_node_set_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_node_set_set_max_load_factor[max_load_factor](float z); + size_type xref:#unordered_node_set_max_load[max_load]() const noexcept; + void xref:#unordered_node_set_rehash[rehash](size_type n); + void xref:#unordered_node_set_reserve[reserve](size_type n); + + // statistics (if xref:unordered_node_set_boost_unordered_enable_stats[enabled]) + stats xref:#unordered_node_set_get_stats[get_stats]() const; + void xref:#unordered_node_set_reset_stats[reset_stats]() noexcept; + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_node_set(InputIterator, InputIterator, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type = xref:#unordered_node_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_node_set, Hash, Pred, Allocator>; + + template, class Pred = std::equal_to, + class Allocator = std::allocator> + unordered_node_set(std::initializer_list, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type = xref:#unordered_node_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_node_set; + + template + unordered_node_set(InputIterator, InputIterator, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_set(InputIterator, InputIterator, Allocator) + -> unordered_node_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_node_set(InputIterator, InputIterator, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Hash, + Allocator) + -> unordered_node_set, Hash, + std::equal_to>, Allocator>; + + template + unordered_node_set(std::initializer_list, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_node_set, std::equal_to, Allocator>; + + template + unordered_node_set(std::initializer_list, Allocator) + -> unordered_node_set, std::equal_to, Allocator>; + + template + unordered_node_set(std::initializer_list, typename xref:#unordered_node_set_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> unordered_node_set, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_node_set_operator_2[operator==](const unordered_node_set& x, + const unordered_node_set& y); + + template + bool xref:#unordered_node_set_operator_3[operator!=](const unordered_node_set& x, + const unordered_node_set& y); + + // swap + template + void xref:#unordered_node_set_swap_2[swap](unordered_node_set& x, + unordered_node_set& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_node_set::size_type + xref:#unordered_node_set_erase_if[erase_if](unordered_node_set& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_node_set = + boost::unordered_node_set>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container. + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type `bool`. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The element nodes of the container are held into an internal _bucket array_. A node is inserted into a bucket determined by +the hash code of its element, but if the bucket is already occupied (a _collision_), an available one in the vicinity of the +original position is used. + +The size of the bucket array can be automatically increased by a call to `insert`/`emplace`, or as a result of calling +`rehash`/`reserve`. The _load factor_ of the container (number of elements divided by number of buckets) is never +greater than `max_load_factor()`, except possibly for small sizes where the implementation may decide to +allow for higher loads. + +If `xref:hash_traits_hash_is_avalanching[hash_is_avalanching]::value` is `true`, the hash function +is used as-is; otherwise, a bit-mixing post-processing stage is added to increase the quality of hashing +at the expense of extra computational cost. + +--- + +=== Configuration Macros + +==== `BOOST_UNORDERED_ENABLE_STATS` + +Globally define this macro to enable xref:#stats[statistics calculation] for the container. Note +that this option decreases the overall performance of many operations. + +--- + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +A class for holding extracted container elements, modelling +https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle]. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ insert_return_type; +---- + +A specialization of an internal class template: + +[source,c++,subs=+quotes] +---- +template +struct _insert_return_type_ // name is exposition only +{ + Iterator position; + bool inserted; + NodeType node; +}; +---- + +with `Iterator` = `iterator` and `NodeType` = `node_type`. + +--- + +=== Constructors + +==== Default Constructor +```c++ +unordered_node_set(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate and `allocator_type()` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_node_set(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_node_set(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a` as the allocator, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_node_set(unordered_node_set const& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_node_set(unordered_node_set&& other); +``` + +The move constructor. The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_node_set(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_node_set(Allocator const& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_node_set(unordered_node_set const& other, Allocator const& a); +``` + +Constructs a container, copying ``other``'s contained elements, hash function, and predicate, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_node_set(unordered_node_set&& other, Allocator const& a); +``` + +If `a == other.get_allocator()`, the element nodes of `other` are transferred directly to the new container; +otherwise, elements are moved-constructed from those of `other`. The hash function and predicate are moved-constructed +from `other`, and the allocator is copy-constructed from `a`. +If statistics are xref:unordered_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff `a == other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Move Constructor from concurrent_node_set + +```c++ +unordered_node_set(concurrent_node_set&& other); +``` + +Move construction from a xref:#concurrent_node_set[`concurrent_node_set`]. +The internal bucket array of `other` is transferred directly to the new container. +The hash function, predicate and allocator are moved-constructed from `other`. +If statistics are xref:unordered_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` and calls `other.reset_stats()`. + +[horizontal] +Complexity:;; Constant time. +Concurrency:;; Blocking on `other`. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_node_set(std::initializer_list il, + size_type n = _implementation-defined_ + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate and `a`, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_node_set(size_type n, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_node_set(size_type n, hasher const& hf, allocator_type const& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate and `a` as the allocator. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_node_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and default hash function and key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- + template + unordered_node_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate, and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_node_set(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_node_set(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` and default hash function and key equality predicate, and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_node_set(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and default key equality predicate,and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_node_set(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_node_set& operator=(unordered_node_set const& other); +``` + +The assignment operator. Destroys previously existing elements, copy-assigns the hash function and predicate from `other`, +copy-assigns the allocator from `other` if `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, +and finally inserts copies of the elements of `other`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +--- + +==== Move Assignment +```c++ +unordered_node_set& operator=(unordered_node_set&& other) + noexcept((boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_move_assignment::value) && + std::is_same::value); +``` +The move assignment operator. Destroys previously existing elements, swaps the hash function and predicate from `other`, +and move-assigns the allocator from `other` if `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`. +If at this point the allocator is equal to `other.get_allocator()`, the internal bucket array of `other` is transferred directly to the new container; +otherwise, inserts move-constructed copies of the elements of `other`. +If statistics are xref:unordered_node_set_boost_unordered_enable_stats[enabled], +transfers the internal statistical information from `other` iff the final allocator is equal to `other.get_allocator()`, +and always calls `other.reset_stats()`. + +--- + +==== Initializer List Assignment +```c++ +unordered_node_set& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All previously existing elements are destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. +Complexity:;; O(`bucket_count()`) + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template std::pair emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + + +--- + +==== emplace_hint +```c++ + template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent key. + +`position` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is constructible from `args`. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + + +--- + +==== Copy Insert +```c++ +std::pair insert(const value_type& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Move Insert +```c++ +std::pair insert(value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +``` +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The `bool` component of the return type is `true` if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Transparent Insert with Hint +```c++ +template std::pair insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into the container from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load to be greater than the maximum load. + +--- + +==== Insert Node +```c++ +insert_return_type insert(node_type&& nh); +``` + +If `nh` is not empty, inserts the associated element in the container if and only if there is no element in the container with a key equivalent to `nh.value()`. +`nh` is empty when the function returns. + +[horizontal] +Returns:;; An `insert_return_type` object constructed from `position`, `inserted` and `node`: + +* If `nh` is empty, `inserted` is `false`, `position` is `end()`, and `node` is empty. +* Otherwise if the insertion took place, `inserted` is true, `position` points to the inserted element, and `node` is empty. +* If the insertion failed, `inserted` is false, `node` has the previous value of `nh`, and `position` points to an element with a key equivalent to `nh.value()`. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== Insert Node with Hint +```c++ +iterator insert(const_iterator hint, node_type&& nh); +``` + +If `nh` is not empty, inserts the associated element in the container if and only if there is no element in the container with a key equivalent to `nh.value()`. +`nh` becomes empty if insertion took place, otherwise it is not changed. + +`hint` is a suggestion to where the element should be inserted. This implementation ignores it. + +[horizontal] +Returns:;; The iterator returned is `end()` if `nh` is empty. +If insertion took place, then the iterator points to the newly inserted element; otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Behavior is undefined if `nh` is not empty and the allocators of `nh` and the container are not equal. + +--- + +==== Erase by Position + +[source,c++,subs=+quotes] +---- +_convertible-to-iterator_ erase(iterator position); +_convertible-to-iterator_ erase(const_iterator position); +---- + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; An opaque object implicitly convertible to the `iterator` or `const_iterator` +immediately following `position` prior to the erasure. +Throws:;; Nothing. +Notes:;; The opaque object returned must only be discarded or immediately converted to `iterator` or `const_iterator`. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Nothing in this implementation (neither the `hasher` nor the `key_equal` objects are called). + +--- + +==== swap +```c++ +void swap(unordered_node_set& other) + noexcept(boost::allocator_traits::is_always_equal::value || + boost::allocator_traits::propagate_on_container_swap::value); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +==== Extract by Position +```c++ +node_type extract(const_iterator position); +``` + +Extracts the element pointed to by `position`. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element. +Throws:;; Nothing. + +--- + +==== Extract by Key +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Extracts the element with key equivalent to `k`, if it exists. + +[horizontal] +Returns:;; A `node_type` object holding the extracted element, or empty if no element was extracted. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0`, `max_load() >= max_load_factor() * bucket_count()` + +--- + +==== merge +```c++ +template + void merge(unordered_node_set& source); +template + void merge(unordered_node_set&& source); +``` + +Transfers all the element nodes from `source` whose key is not already present in `*this`. + +[horizontal] +Requires:;; `this\->get_allocator() == source.get_allocator()`. +Notes:;; Invalidates iterators to the elements transferred. +If the resulting size of `*this` is greater than its original maximum load, +invalidates all iterators associated to `*this`. + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const noexcept; +``` + +[horizontal] +Returns:;; The container's allocator. + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); + +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `end()` if no such element exists. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The size of the bucket array. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; `static_cast(size())/static_cast(bucket_count())`, or `0` if `bucket_count() == 0`. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the container's maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Does nothing, as the user is not allowed to change this parameter. Kept for compatibility with `boost::unordered_set`. + +--- + + +==== max_load + +```c++ +size_type max_load() const noexcept; +``` + +[horizontal] +Returns:;; The maximum number of elements the container can hold without rehashing, assuming that no further elements will be erased. +Note:;; After construction, rehash or clearance, the container's maximum load is at least `max_load_factor() * bucket_count()`. +This number may decrease on erasure under high-load conditions. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes if necessary the size of the bucket array so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. If the provided Allocator uses fancy pointers, a default allocation is subsequently performed. + +Invalidates iterators and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators and changes the order of elements. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +=== Statistics + +==== get_stats +```c++ +stats get_stats() const; +``` + +[horizontal] +Returns:;; A statistical description of the insertion and lookup operations performed by the container so far. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_node_set_boost_unordered_enable_stats[enabled]. + +--- + +==== reset_stats +```c++ +void reset_stats() noexcept; +``` + +[horizontal] +Effects:;; Sets to zero the internal statistics kept by the container. +Notes:;; Only available if xref:stats[statistics calculation] is xref:unordered_node_set_boost_unordered_enable_stats[enabled]. + +--- + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_node_set& x, + const unordered_node_set& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_node_set& x, + const unordered_node_set& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +=== Swap +```c++ +template + void swap(unordered_node_set& x, + unordered_node_set& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Nothing unless `key_equal` or `hasher` throw on swapping. + +--- + +=== erase_if +```c++ +template + typename unordered_node_set::size_type + erase_if(unordered_node_set& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_node_set``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_node_set to an archive + +Saves all the elements of an `unordered_node_set` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `value_type` +is serializable (XML serializable), and it supports Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_node_set from an archive + +Deletes all preexisting elements of an `unordered_node_set` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_node_set` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +`x.key_equal()` is functionally equivalent to `other.key_equal()`. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_node_set` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_node_set` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/reference/unordered_set.adoc b/doc/modules/ROOT/pages/reference/unordered_set.adoc new file mode 100644 index 00000000..2a3f5217 --- /dev/null +++ b/doc/modules/ROOT/pages/reference/unordered_set.adoc @@ -0,0 +1,1580 @@ +[#unordered_set] +== Class Template unordered_set + +:idprefix: unordered_set_ + +`boost::unordered_set` — An unordered associative container that stores unique values. + +=== Synopsis + +[listing,subs="+macros,+quotes"] +----- +// #include + +namespace boost { + template, + class Pred = std::equal_to, + class Allocator = std::allocator> + class unordered_set { + public: + // types + using key_type = Key; + using value_type = Key; + using hasher = Hash; + using key_equal = Pred; + using allocator_type = Allocator; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + using reference = value_type&; + using const_reference = const value_type&; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + + using iterator = _implementation-defined_; + using const_iterator = _implementation-defined_; + using local_iterator = _implementation-defined_; + using const_local_iterator = _implementation-defined_; + using node_type = _implementation-defined_; + using insert_return_type = _implementation-defined_; + + // construct/copy/destroy + xref:#unordered_set_default_constructor[unordered_set](); + explicit xref:#unordered_set_bucket_count_constructor[unordered_set](size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + template + xref:#unordered_set_iterator_range_constructor[unordered_set](InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_set_copy_constructor[unordered_set](const unordered_set& other); + xref:#unordered_set_move_constructor[unordered_set](unordered_set&& other); + template + xref:#unordered_set_iterator_range_constructor_with_allocator[unordered_set](InputIterator f, InputIterator l, const allocator_type& a); + explicit xref:#unordered_set_allocator_constructor[unordered_set](const Allocator& a); + xref:#unordered_set_copy_constructor_with_allocator[unordered_set](const unordered_set& other, const Allocator& a); + xref:#unordered_set_move_constructor_with_allocator[unordered_set](unordered_set&& other, const Allocator& a); + xref:#unordered_set_initializer_list_constructor[unordered_set](std::initializer_list il, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); + xref:#unordered_set_bucket_count_constructor_with_allocator[unordered_set](size_type n, const allocator_type& a); + xref:#unordered_set_bucket_count_constructor_with_hasher_and_allocator[unordered_set](size_type n, const hasher& hf, const allocator_type& a); + template + xref:#unordered_set_iterator_range_constructor_with_bucket_count_and_allocator[unordered_set](InputIterator f, InputIterator l, size_type n, const allocator_type& a); + template + xref:#unordered_set_iterator_range_constructor_with_bucket_count_and_hasher[unordered_set](InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_set_initializer_list_constructor_with_allocator[unordered_set](std::initializer_list il, const allocator_type& a); + xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_allocator[unordered_set](std::initializer_list il, size_type n, const allocator_type& a); + xref:#unordered_set_initializer_list_constructor_with_bucket_count_and_hasher_and_allocator[unordered_set](std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); + xref:#unordered_set_destructor[~unordered_set](); + unordered_set& xref:#unordered_set_copy_assignment[operator++=++](const unordered_set& other); + unordered_set& xref:#unordered_set_move_assignment[operator++=++](unordered_set&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); + unordered_set& xref:#unordered_set_initializer_list_assignment[operator++=++](std::initializer_list il); + allocator_type xref:#unordered_set_get_allocator[get_allocator]() const noexcept; + + // iterators + iterator xref:#unordered_set_begin[begin]() noexcept; + const_iterator xref:#unordered_set_begin[begin]() const noexcept; + iterator xref:#unordered_set_end[end]() noexcept; + const_iterator xref:#unordered_set_end[end]() const noexcept; + const_iterator xref:#unordered_set_cbegin[cbegin]() const noexcept; + const_iterator xref:#unordered_set_cend[cend]() const noexcept; + + // capacity + ++[[nodiscard]]++ bool xref:#unordered_set_empty[empty]() const noexcept; + size_type xref:#unordered_set_size[size]() const noexcept; + size_type xref:#unordered_set_max_size[max_size]() const noexcept; + + // modifiers + template std::pair xref:#unordered_set_emplace[emplace](Args&&... args); + template iterator xref:#unordered_set_emplace_hint[emplace_hint](const_iterator position, Args&&... args); + std::pair xref:#unordered_set_copy_insert[insert](const value_type& obj); + std::pair xref:#unordered_set_move_insert[insert](value_type&& obj); + template std::pair xref:#unordered_set_transparent_insert[insert](K&& k); + iterator xref:#unordered_set_copy_insert_with_hint[insert](const_iterator hint, const value_type& obj); + iterator xref:#unordered_set_move_insert_with_hint[insert](const_iterator hint, value_type&& obj); + template iterator xref:#unordered_set_transparent_insert_with_hint[insert](const_iterator hint, K&& k); + template void xref:#unordered_set_insert_iterator_range[insert](InputIterator first, InputIterator last); + void xref:#unordered_set_insert_initializer_list[insert](std::initializer_list); + + node_type xref:#unordered_set_extract_by_iterator[extract](const_iterator position); + node_type xref:#unordered_set_extract_by_value[extract](const key_type& k); + template node_type xref:#unordered_set_extract_by_value[extract](K&& k); + insert_return_type xref:#unordered_set_insert_with_node_handle[insert](node_type&& nh); + iterator xref:#unordered_set_insert_with_hint_and_node_handle[insert](const_iterator hint, node_type&& nh); + + iterator xref:#unordered_set_erase_by_position[erase](iterator position); + iterator xref:#unordered_set_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_set_erase_by_value[erase](const key_type& k); + template size_type xref:#unordered_set_erase_by_value[erase](K&& k); + iterator xref:#unordered_set_erase_range[erase](const_iterator first, const_iterator last); + void xref:#unordered_set_quick_erase[quick_erase](const_iterator position); + void xref:#unordered_set_erase_return_void[erase_return_void](const_iterator position); + void xref:#unordered_set_swap[swap](unordered_set& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); + void xref:#unordered_set_clear[clear]() noexcept; + + template + void xref:#unordered_set_merge[merge](unordered_set& source); + template + void xref:#unordered_set_merge[merge](unordered_set&& source); + template + void xref:#unordered_set_merge[merge](unordered_multiset& source); + template + void xref:#unordered_set_merge[merge](unordered_multiset&& source); + + // observers + hasher xref:#unordered_set_hash_function[hash_function]() const; + key_equal xref:#unordered_set_key_eq[key_eq]() const; + + // set operations + iterator xref:#unordered_set_find[find](const key_type& k); + const_iterator xref:#unordered_set_find[find](const key_type& k) const; + template + iterator xref:#unordered_set_find[find](const K& k); + template + const_iterator xref:#unordered_set_find[find](const K& k) const; + template + iterator xref:#unordered_set_find[find](CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq); + template + const_iterator xref:#unordered_set_find[find](CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq) const; + size_type xref:#unordered_set_count[count](const key_type& k) const; + template + size_type xref:#unordered_set_count[count](const K& k) const; + bool xref:#unordered_set_contains[contains](const key_type& k) const; + template + bool xref:#unordered_set_contains[contains](const K& k) const; + std::pair xref:#unordered_set_equal_range[equal_range](const key_type& k); + std::pair xref:#unordered_set_equal_range[equal_range](const key_type& k) const; + template + std::pair xref:#unordered_set_equal_range[equal_range](const K& k); + template + std::pair xref:#unordered_set_equal_range[equal_range](const K& k) const; + + // bucket interface + size_type xref:#unordered_set_bucket_count[bucket_count]() const noexcept; + size_type xref:#unordered_set_max_bucket_count[max_bucket_count]() const noexcept; + size_type xref:#unordered_set_bucket_size[bucket_size](size_type n) const; + size_type xref:#unordered_set_bucket[bucket](const key_type& k) const; + template size_type xref:#unordered_set_bucket[bucket](const K& k) const; + local_iterator xref:#unordered_set_begin_2[begin](size_type n); + const_local_iterator xref:#unordered_set_begin_2[begin](size_type n) const; + local_iterator xref:#unordered_set_end_2[end](size_type n); + const_local_iterator xref:#unordered_set_end_2[end](size_type n) const; + const_local_iterator xref:#unordered_set_cbegin_2[cbegin](size_type n) const; + const_local_iterator xref:#unordered_set_cend_2[cend](size_type n) const; + + // hash policy + float xref:#unordered_set_load_factor[load_factor]() const noexcept; + float xref:#unordered_set_max_load_factor[max_load_factor]() const noexcept; + void xref:#unordered_set_set_max_load_factor[max_load_factor](float z); + void xref:#unordered_set_rehash[rehash](size_type n); + void xref:#unordered_set_reserve[reserve](size_type n); + }; + + // Deduction Guides + template>, + class Pred = std::equal_to>, + class Allocator = std::allocator>> + unordered_set(InputIterator, InputIterator, typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set, Hash, Pred, Allocator>; + + template, class Pred = std::equal_to, + class Allocator = std::allocator> + unordered_set(std::initializer_list, typename xref:#unordered_set_deduction_guides[__see below__]::size_type = xref:#unordered_set_deduction_guides[__see below__], + Hash = Hash(), Pred = Pred(), Allocator = Allocator()) + -> unordered_set; + + template + unordered_set(InputIterator, InputIterator, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_set(InputIterator, InputIterator, Allocator) + -> unordered_set, + boost::hash>, + std::equal_to>, Allocator>; + + template + unordered_set(InputIterator, InputIterator, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> unordered_set, Hash, + std::equal_to>, Allocator>; + + template + unordered_set(std::initializer_list, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Allocator) + -> unordered_set, std::equal_to, Allocator>; + + template + unordered_set(std::initializer_list, Allocator) + -> unordered_set, std::equal_to, Allocator>; + + template + unordered_set(std::initializer_list, typename xref:#unordered_set_deduction_guides[__see below__]::size_type, Hash, Allocator) + -> unordered_set, Allocator>; + + // Equality Comparisons + template + bool xref:#unordered_set_operator[operator++==++](const unordered_set& x, + const unordered_set& y); + + template + bool xref:#unordered_set_operator_2[operator!=](const unordered_set& x, + const unordered_set& y); + + // swap + template + void xref:#unordered_set_swap_2[swap](unordered_set& x, + unordered_set& y) + noexcept(noexcept(x.swap(y))); + + // Erasure + template + typename unordered_set::size_type + xref:#unordered_set_erase_if[erase_if](unordered_set& c, Predicate pred); + + // Pmr aliases (C++17 and up) + namespace unordered::pmr { + template, + class Pred = std::equal_to> + using unordered_set = + boost::unordered_set>; + } +} +----- + +--- + +=== Description + +*Template Parameters* + +[cols="1,1"] +|=== + +|_Key_ +|`Key` must be https://en.cppreference.com/w/cpp/named_req/Erasable[Erasable^] from the container (i.e. `allocator_traits` can destroy it). + +|_Hash_ +|A unary function object type that acts a hash function for a `Key`. It takes a single argument of type `Key` and returns a value of type `std::size_t`. + +|_Pred_ +|A binary function object that implements an equivalence relation on values of type `Key`. A binary function object that induces an equivalence relation on values of type `Key`. It takes two arguments of type `Key` and returns a value of type bool. + +|_Allocator_ +|An allocator whose value type is the same as the container's value type. +Allocators using https://en.cppreference.com/w/cpp/named_req/Allocator#Fancy_pointers[fancy pointers] are supported. + +|=== + +The elements are organized into buckets. Keys with the same hash code are stored in the same bucket. + +The number of buckets can be automatically increased by a call to insert, or as the result of calling rehash. + +=== Configuration macros + +==== `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` + +Globally define this macro to support loading of ``unordered_set``s saved to +a Boost.Serialization archive with a version of Boost prior to Boost 1.84. + +=== Typedefs + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +Convertible to `const_iterator`. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_iterator; +---- + +A constant iterator whose value type is `value_type`. + +The iterator category is at least a forward iterator. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ local_iterator; +---- + +An iterator with the same value type, difference type and pointer and reference type as iterator. + +A `local_iterator` object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ const_local_iterator; +---- + +A constant iterator with the same value type, difference type and pointer and reference type as const_iterator. + +A const_local_iterator object can be used to iterate through a single bucket. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ node_type; +---- + +A class for holding extracted container elements, modelling +https://en.cppreference.com/w/cpp/container/node_handle[NodeHandle]. + +--- + +[source,c++,subs=+quotes] +---- +typedef _implementation-defined_ insert_return_type; +---- + +A specialization of an internal class template: + +[source,c++,subs=+quotes] +---- +template +struct _insert_return_type_ // name is exposition only +{ + Iterator position; + bool inserted; + NodeType node; +}; +---- + +with `Iterator` = `iterator` and `NodeType` = `node_type`. + +--- + +=== Constructors + +==== Default Constructor +```c++ +unordered_set(); +``` + +Constructs an empty container using `hasher()` as the hash function, +`key_equal()` as the key equality predicate, `allocator_type()` as the allocator +and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor +```c++ +explicit unordered_set(size_type n, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash +function, `eql` as the key equality predicate, `a` as the allocator and a maximum +load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor +[source,c++,subs="+quotes"] +---- +template + unordered_set(InputIterator f, InputIterator l, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Copy Constructor +```c++ +unordered_set(const unordered_set& other); +``` + +The copy constructor. Copies the contained elements, hash function, predicate, maximum load factor and allocator. + +If `Allocator::select_on_container_copy_construction` exists and has the right signature, the allocator will be constructed from its result. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Constructor +```c++ +unordered_set(unordered_set&& other); +``` + +The move constructor. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move-constructible. + +--- + +==== Iterator Range Constructor with Allocator +```c++ +template + unordered_set(InputIterator f, InputIterator l, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Allocator Constructor +```c++ +explicit unordered_set(const Allocator& a); +``` + +Constructs an empty container, using allocator `a`. + +--- + +==== Copy Constructor with Allocator +```c++ +unordered_set(const unordered_set& other, const Allocator& a); +``` + +Constructs an container, copying ``other``'s contained elements, hash function, predicate, maximum load factor, but using allocator `a`. + +--- + +==== Move Constructor with Allocator +```c++ +unordered_set(unordered_set&& other, const Allocator& a); +``` + +Construct a container moving ``other``'s contained elements, and having the hash function, predicate and maximum load factor, but using allocate `a`. + +[horizontal] +Notes:;; This is implemented using Boost.Move. +Requires:;; `value_type` is move insertable. + +--- + +==== Initializer List Constructor +[source,c++,subs="+quotes"] +---- +unordered_set(std::initializer_list il, + size_type n = _implementation-defined_, + const hasher& hf = hasher(), + const key_equal& eql = key_equal(), + const allocator_type& a = allocator_type()); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `eql` as the key equality predicate, `a` as the allocator and a maximum load factor of `1.0` and inserts the elements from `il` into it. + +[horizontal] +Requires:;; If the defaults are used, `hasher`, `key_equal` and `allocator_type` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Allocator +```c++ +unordered_set(size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default hash function and key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Bucket Count Constructor with Hasher and Allocator +```c++ +unordered_set(size_type n, const hasher& hf, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, the default key equality predicate, `a` as the allocator and a maximum load factor of `1.0`. + +[horizontal] +Postconditions:;; `size() == 0` +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Allocator +[source,c++,subs="+quotes"] +---- +template + unordered_set(InputIterator f, InputIterator l, size_type n, const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `a` as the allocator, with the default hash function and key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `hasher`, `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== Iterator Range Constructor with Bucket Count and Hasher +[source,c++,subs="+quotes"] +---- +template + unordered_set(InputIterator f, InputIterator l, size_type n, const hasher& hf, + const allocator_type& a); +---- + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator, with the default key equality predicate and a maximum load factor of `1.0` and inserts the elements from `[f, l)` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Allocator + +```c++ +unordered_set(std::initializer_list il, const allocator_type& a); +``` + +Constructs an empty container using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Allocator + +```c++ +unordered_set(std::initializer_list il, size_type n, const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `hasher` and `key_equal` need to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +==== initializer_list Constructor with Bucket Count and Hasher and Allocator + +```c++ +unordered_set(std::initializer_list il, size_type n, const hasher& hf, + const allocator_type& a); +``` + +Constructs an empty container with at least `n` buckets, using `hf` as the hash function, `a` as the allocator and a maximum load factor of 1.0 and inserts the elements from `il` into it. + +[horizontal] +Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^]. + +--- + +=== Destructor + +```c++ +~unordered_set(); +``` + +[horizontal] +Note:;; The destructor is applied to every element, and all memory is deallocated + +--- + +=== Assignment + +==== Copy Assignment + +```c++ +unordered_set& operator=(const unordered_set& other); +``` + +The assignment operator. Copies the contained elements, hash function, predicate and maximum load factor but not the allocator. + +If `Alloc::propagate_on_container_copy_assignment` exists and `Alloc::propagate_on_container_copy_assignment::value` is `true`, the allocator is overwritten, if not the copied elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is copy constructible + +--- + +==== Move Assignment +```c++ +unordered_set& operator=(unordered_set&& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); +``` +The move assignment operator. + +If `Alloc::propagate_on_container_move_assignment` exists and `Alloc::propagate_on_container_move_assignment::value` is `true`, the allocator is overwritten, if not the moved elements are created using the existing allocator. + +[horizontal] +Requires:;; `value_type` is move constructible. + +--- + +==== Initializer List Assignment +```c++ +unordered_set& operator=(std::initializer_list il); +``` + +Assign from values in initializer list. All existing elements are either overwritten by the new elements or destroyed. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container and https://en.cppreference.com/w/cpp/named_req/CopyAssignable[CopyAssignable^]. + +--- + +=== Iterators + +==== begin +```c++ +iterator begin() noexcept; +const_iterator begin() const noexcept; +``` + +[horizontal] +Returns:;; An iterator referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== end +```c++ +iterator end() noexcept; +const_iterator end() const noexcept; +``` + +[horizontal] +Returns:;; An iterator which refers to the past-the-end value for the container. + +--- + +==== cbegin +```c++ +const_iterator cbegin() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` referring to the first element of the container, or if the container is empty the past-the-end value for the container. + +--- + +==== cend +```c++ +const_iterator cend() const noexcept; +``` + +[horizontal] +Returns:;; A `const_iterator` which refers to the past-the-end value for the container. + +--- + +=== Size and Capacity + +==== empty + +```c++ +[[nodiscard]] bool empty() const noexcept; +``` + +[horizontal] +Returns:;; `size() == 0` + +--- + +==== size + +```c++ +size_type size() const noexcept; +``` + +[horizontal] +Returns:;; `std::distance(begin(), end())` + +--- + +==== max_size + +```c++ +size_type max_size() const noexcept; +``` + +[horizontal] +Returns:;; `size()` of the largest possible container. + +--- + +=== Modifiers + +==== emplace +```c++ +template std::pair emplace(Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent value. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent value. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== emplace_hint +```c++ +template iterator emplace_hint(const_iterator position, Args&&... args); +``` + +Inserts an object, constructed with the arguments `args`, in the container if and only if there is no element in the container with an equivalent value. + +`position` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `args`. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Copy Insert +```c++ +std::pair insert(const value_type& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert +```c++ +std::pair insert(value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Transparent Insert +```c++ +template std::pair insert(K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; The bool component of the return type is true if an insert took place. + ++ +If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Copy Insert with Hint +```c++ +iterator insert(const_iterator hint, const value_type& obj); +``` +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^]. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Move Insert with Hint +```c++ +iterator insert(const_iterator hint, value_type&& obj); +``` + +Inserts `obj` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Transparent Insert with Hint +```c++ +template iterator insert(const_iterator hint, K&& k); +``` + +Inserts an element constructed from `std::forward(k)` in the container if and only if there is no element in the container with an equivalent key. + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] from `k`. +Returns:;; If an insert took place, then the iterator points to the newly inserted element. Otherwise, it points to the element with equivalent key. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert Iterator Range +```c++ +template void insert(InputIterator first, InputIterator last); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `*first`. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Insert Initializer List +```c++ +void insert(std::initializer_list); +``` + +Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container. +Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + +--- + +==== Extract by Iterator +```c++ +node_type extract(const_iterator position); +``` + +Removes the element pointed to by `position`. + +[horizontal] +Returns:;; A `node_type` owning the element. +Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. + +--- + +==== Extract by Value +```c++ +node_type extract(const key_type& k); +template node_type extract(K&& k); +``` + +Removes an element with key equivalent to `k`. + +[horizontal] +Returns:;; A `node_type` owning the element if found, otherwise an empty `node_type`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; In C++17 a node extracted using this method can be inserted into a compatible `unordered_multiset`, but that is not supported yet. + ++ +The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Insert with `node_handle` +```c++ +insert_return_type insert(node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh` if and only if there is no element in the container with an equivalent key. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty, returns an `insert_return_type` with: `inserted` equal to `false`, `position` equal to `end()` and `node` empty. + ++ +Otherwise if there was already an element with an equivalent key, returns an `insert_return_type` with: `inserted` equal to `false`, `position` pointing to a matching element and `node` contains the node from `nh`. + ++ +Otherwise if the insertion succeeded, returns an `insert_return_type` with: `inserted` equal to `true`, `position` pointing to the newly inserted element and `node` empty. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +In C++17 this can be used to insert a node extracted from a compatible `unordered_multiset`, but that is not supported yet. + +--- + +==== Insert with Hint and `node_handle` +```c++ +iterator insert(const_iterator hint, node_type&& nh); +``` + +If `nh` is empty, has no effect. + +Otherwise inserts the element owned by `nh` if and only if there is no element in the container with an equivalent key. + +If there is already an element in the container with an equivalent key has no effect on `nh` (i.e. `nh` still contains the node.) + +`hint` is a suggestion to where the element should be inserted. + +[horizontal] +Requires:;; `nh` is empty or `nh.get_allocator()` is equal to the container's allocator. +Returns:;; If `nh` was empty returns `end()`. + ++ +If there was already an element in the container with an equivalent key returns an iterator pointing to that. + ++ +Otherwise returns an iterator pointing to the newly inserted element. +Throws:;; If an exception is thrown by an operation other than a call to `hasher` the function has no effect. +Notes:;; The standard is fairly vague on the meaning of the hint. But the only practical way to use it, and the only way that Boost.Unordered supports is to point to an existing element with the same key. + ++ +Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. + ++ +Pointers and references to elements are never invalidated. + ++ +This can be used to insert a node extracted from a compatible `unordered_multiset`. + +--- + +==== Erase by Position + +```c++ +iterator erase(iterator position); +iterator erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Returns:;; The iterator following `position` before the erasure. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; In older versions this could be inefficient because it had to search through several buckets to find the position of the returned iterator. The data structure has been changed so that this is no longer the case, and the alternative erase methods have been deprecated. + +--- + +==== Erase by Value +```c++ +size_type erase(const key_type& k); +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== Erase Range + +```c++ +iterator erase(const_iterator first, const_iterator last); +``` + +Erases the elements in the range from `first` to `last`. + +[horizontal] +Returns:;; The iterator following the erased elements - i.e. `last`. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. + +--- + +==== quick_erase +```c++ +void quick_erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== erase_return_void +```c++ +void erase_return_void(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + ++ +In this implementation, this overload doesn't call either function object's methods so it is no throw, but this might not be true in other implementations. +Notes:;; This method was implemented because returning an iterator to the next element from erase was expensive, but the container has been redesigned so that is no longer the case. So this method is now deprecated. + +--- + +==== swap +```c++ +void swap(unordered_set& other) + noexcept(boost::allocator_traits::is_always_equal::value && + boost::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); +``` + +Swaps the contents of the container with the parameter. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +==== clear +```c++ +void clear() noexcept; +``` + +Erases all elements in the container. + +[horizontal] +Postconditions:;; `size() == 0` +Throws:;; Never throws an exception. + +--- + +==== merge +```c++ +template + void merge(unordered_set& source); +template + void merge(unordered_set&& source); +template + void merge(unordered_multiset& source); +template + void merge(unordered_multiset&& source); +``` + +Attempt to "merge" two containers by iterating `source` and extracting any node in `source` that is not contained +in `*this` and then inserting it into `*this`. + +Because `source` can have a different hash function and key equality predicate, the key of each node in +`source` is rehashed using `this\->hash_function()` and then, if required, compared using `this\->key_eq()`. + +The behavior of this function is undefined if `this\->get_allocator() != source.get_allocator()`. + +This function does not copy or move any elements and instead simply relocates the nodes from `source` +into `*this`. + +[horizontal] +Notes:;; ++ +-- +* Pointers and references to transferred elements remain valid. +* Invalidates iterators to transferred elements. +* Invalidates iterators belonging to `*this`. +* Iterators to non-transferred elements in `source` remain valid. +-- + +--- + +=== Observers + +==== get_allocator +``` +allocator_type get_allocator() const; +``` + +--- + +==== hash_function +``` +hasher hash_function() const; +``` + +[horizontal] +Returns:;; The container's hash function. + +--- + +==== key_eq + +``` +key_equal key_eq() const; +``` + +[horizontal] +Returns:;; The container's key equality predicate + +--- + +=== Lookup + +==== find +```c++ +iterator find(const key_type& k); +const_iterator find(const key_type& k) const; +template + iterator find(const K& k); +template + const_iterator find(const K& k) const; +template + iterator find(CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq); +template + const_iterator find(CompatibleKey const& k, CompatibleHash const& hash, + CompatiblePredicate const& eq) const; +``` + +[horizontal] +Returns:;; An iterator pointing to an element with key equivalent to `k`, or `b.end()` if no such element exists. +Notes:;; The templated overloads containing `CompatibleKey`, `CompatibleHash` and `CompatiblePredicate` are non-standard extensions which allow you to use a compatible hash function and equality predicate for a key of a different type in order to avoid an expensive type cast. In general, its use is not encouraged and instead the `K` member function templates should be used. + ++ +The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== count +```c++ +size_type count(const key_type& k) const; +template + size_type count(const K& k) const; +``` + +[horizontal] +Returns:;; The number of elements with key equivalent to `k`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== contains +```c++ +bool contains(const key_type& k) const; +template + bool contains(const K& k) const; +``` + +[horizontal] +Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== equal_range +```c++ +std::pair equal_range(const key_type& k); +std::pair equal_range(const key_type& k) const; +template + std::pair equal_range(const K& k); +template + std::pair equal_range(const K& k) const; +``` + +[horizontal] +Returns:;; A range containing all elements with key equivalent to `k`. If the container doesn't contain any such elements, returns `std::make_pair(b.end(), b.end())`. +Notes:;; The `template` overloads only participate in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +=== Bucket Interface + +==== bucket_count +```c++ +size_type bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; The number of buckets. + +--- + +==== max_bucket_count +```c++ +size_type max_bucket_count() const noexcept; +``` + +[horizontal] +Returns:;; An upper bound on the number of buckets. + +--- + +==== bucket_size +```c++ +size_type bucket_size(size_type n) const; +``` + +[horizontal] +Requires:;; `n < bucket_count()` +Returns:;; The number of elements in bucket `n`. + +--- + +==== bucket +```c++ +size_type bucket(const key_type& k) const; +template size_type bucket(const K& k) const; +``` + +[horizontal] +Returns:;; The index of the bucket which would contain an element with key `k`. +Postconditions:;; The return value is less than `bucket_count()`. +Notes:;; The `template` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +--- + +==== begin + +```c++ +local_iterator begin(size_type n); +const_local_iterator begin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the first element in the bucket with index `n`. + +--- + +==== end +```c++ +local_iterator end(size_type n); +const_local_iterator end(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +==== cbegin +```c++ +const_local_iterator cbegin(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the first element in the bucket with index `n`. + +--- + +==== cend +```c++ +const_local_iterator cend(size_type n) const; +``` + +[horizontal] +Requires:;; `n` shall be in the range `[0, bucket_count())`. +Returns:;; A constant local iterator pointing the 'one past the end' element in the bucket with index `n`. + +--- + +=== Hash Policy + +==== load_factor +```c++ +float load_factor() const noexcept; +``` + +[horizontal] +Returns:;; The average number of elements per bucket. + +--- + +==== max_load_factor + +```c++ +float max_load_factor() const noexcept; +``` + +[horizontal] +Returns:;; Returns the current maximum load factor. + +--- + +==== Set max_load_factor +```c++ +void max_load_factor(float z); +``` + +[horizontal] +Effects:;; Changes the container's maximum load factor, using `z` as a hint. + +--- + +==== rehash +```c++ +void rehash(size_type n); +``` + +Changes the number of buckets so that there are at least `n` buckets, and so that the load factor is less than or equal to the maximum load factor. When applicable, this will either grow or shrink the `bucket_count()` associated with the container. + +When `size() == 0`, `rehash(0)` will deallocate the underlying buckets array. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + +--- + +==== reserve +```c++ +void reserve(size_type n); +``` + +Equivalent to `a.rehash(ceil(n / a.max_load_factor()))`, or `a.rehash(1)` if `n > 0` and `a.max_load_factor() == std::numeric_limits::infinity()`. + +Similar to `rehash`, this function can be used to grow or shrink the number of buckets in the container. + +Invalidates iterators, and changes the order of elements. Pointers and references to elements are not invalidated. + +[horizontal] +Throws:;; The function has no effect if an exception is thrown, unless it is thrown by the container's hash function or comparison function. + + +=== Deduction Guides +A deduction guide will not participate in overload resolution if any of the following are true: + + - It has an `InputIterator` template parameter and a type that does not qualify as an input iterator is deduced for that parameter. + - It has an `Allocator` template parameter and a type that does not qualify as an allocator is deduced for that parameter. + - It has a `Hash` template parameter and an integral type or a type that qualifies as an allocator is deduced for that parameter. + - It has a `Pred` template parameter and a type that qualifies as an allocator is deduced for that parameter. + +A `size_­type` parameter type in a deduction guide refers to the `size_­type` member type of the +container type deduced by the deduction guide. Its default value coincides with the default value +of the constructor selected. + +==== __iter-value-type__ +[listings,subs="+macros,+quotes"] +----- +template + using __iter-value-type__ = + typename std::iterator_traits::value_type; // exposition only +----- + +=== Equality Comparisons + +==== operator== +```c++ +template + bool operator==(const unordered_set& x, + const unordered_set& y); +``` + +Return `true` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +==== operator!= +```c++ +template + bool operator!=(const unordered_set& x, + const unordered_set& y); +``` + +Return `false` if `x.size() == y.size()` and for every element in `x`, there is an element in `y` with the same key, with an equal value (using `operator==` to compare the value types). + +[horizontal] +Notes:;; Behavior is undefined if the two containers don't have equivalent equality predicates. + +--- + +=== Swap +```c++ +template + void swap(unordered_set& x, + unordered_set& y) + noexcept(noexcept(x.swap(y))); +``` + +Swaps the contents of `x` and `y`. + +If `Allocator::propagate_on_container_swap` is declared and `Allocator::propagate_on_container_swap::value` is `true` then the containers' allocators are swapped. Otherwise, swapping with unequal allocators results in undefined behavior. + +[horizontal] +Effects:;; `x.swap(y)` +Throws:;; Doesn't throw an exception unless it is thrown by the copy constructor or copy assignment operator of `key_equal` or `hasher`. +Notes:;; The exception specifications aren't quite the same as the C++11 standard, as the equality predicate and hash function are swapped using their copy constructors. + +--- + +=== erase_if +```c++ +template + typename unordered_set::size_type + erase_if(unordered_set& c, Predicate pred); +``` + +Traverses the container `c` and removes all elements for which the supplied predicate returns `true`. + +[horizontal] +Returns:;; The number of erased elements. +Notes:;; Equivalent to: + ++ +```c++ +auto original_size = c.size(); +for (auto i = c.begin(), last = c.end(); i != last; ) { + if (pred(*i)) { + i = c.erase(i); + } else { + ++i; + } +} +return original_size - c.size(); +``` + +=== Serialization + +``unordered_set``s can be archived/retrieved by means of +link:../../../serialization/index.html[Boost.Serialization^] using the API provided +by this library. Both regular and XML archives are supported. + +==== Saving an unordered_set to an archive + +Saves all the elements of an `unordered_set` `x` to an archive (XML archive) `ar`. + +[horizontal] +Requires:;; `value_type` +is serializable (XML serializable), and it supports Boost.Serialization +`save_construct_data`/`load_construct_data` protocol (automatically suported by +https://en.cppreference.com/w/cpp/named_req/DefaultConstructible[DefaultConstructible^] +types). + +--- + +==== Loading an unordered_set from an archive + +Deletes all preexisting elements of an `unordered_set` `x` and inserts +from an archive (XML archive) `ar` restored copies of the elements of the +original `unordered_set` `other` saved to the storage read by `ar`. + +[horizontal] +Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/MoveInsertable[MoveInsertable^]. +`x.key_equal()` is functionally equivalent to `other.key_equal()`. +Note:;; If the archive was saved using a release of Boost prior to Boost 1.84, +the configuration macro `BOOST_UNORDERED_ENABLE_SERIALIZATION_COMPATIBILITY_V0` +has to be globally defined for this operation to succeed; otherwise, an exception is thrown. + +--- + +==== Saving an iterator/const_iterator to an archive + +Saves the positional information of an `iterator` (`const_iterator`) `it` +to an archive (XML archive) `ar`. `it` can be and `end()` iterator. + +[horizontal] +Requires:;; The `unordered_set` `x` pointed to by `it` has been previously saved to `ar`, +and no modifying operations have been issued on `x` between saving of `x` and +saving of `it`. + +--- + +==== Loading an iterator/const_iterator from an archive + +Makes an `iterator` (`const_iterator`) `it` point to the restored position of +the original `iterator` (`const_iterator`) saved to the storage read by +an archive (XML archive) `ar`. + +[horizontal] +Requires:;; If `x` is the `unordered_set` `it` points to, no modifying operations +have been issued on `x` between loading of `x` and loading of `it`. diff --git a/doc/modules/ROOT/pages/regular.adoc b/doc/modules/ROOT/pages/regular.adoc new file mode 100644 index 00000000..9ad36258 --- /dev/null +++ b/doc/modules/ROOT/pages/regular.adoc @@ -0,0 +1,203 @@ +[#regular] += Regular Containers + +:idprefix: regular_ + +Boost.Unordered closed-addressing containers (`boost::unordered_set`, `boost::unordered_map`, +`boost::unordered_multiset` and `boost::unordered_multimap`) are fully conformant with the +C++ specification for unordered associative containers, so for those who know how to use +`std::unordered_set`, `std::unordered_map`, etc., their homonyms in Boost.Unordered are +drop-in replacements. The interface of open-addressing containers (`boost::unordered_node_set`, +`boost::unordered_node_map`, `boost::unordered_flat_set` and `boost::unordered_flat_map`) +is very similar, but they present some minor differences listed in the dedicated +xref:#compliance_open_addressing_containers[standard compliance section]. + + +For readers without previous experience with hash containers but familiar +with normal associative containers (`std::set`, `std::map`, +`std::multiset` and `std::multimap`), Boost.Unordered containers are used in a similar manner: + +[source,cpp] +---- +typedef boost::unordered_map map; +map x; +x["one"] = 1; +x["two"] = 2; +x["three"] = 3; + +assert(x.at("one") == 1); +assert(x.find("missing") == x.end()); +---- + +But since the elements aren't ordered, the output of: + +[source,c++] +---- +for(const map::value_type& i: x) { + std::cout<> section. + +== Iterator Invalidation + +It is not specified how member functions other than `rehash` and `reserve` affect +the bucket count, although `insert` can only invalidate iterators +when the insertion causes the container's load to be greater than the maximum allowed. +For most implementations this means that `insert` will only +change the number of buckets when this happens. Iterators can be +invalidated by calls to `insert`, `rehash` and `reserve`. + +As for pointers and references, +they are never invalidated for node-based containers +(`boost::unordered_[multi]set`, `boost::unordered_[multi]map`, `boost::unordered_node_set`, `boost::unordered_node_map`), +but they will be when rehashing occurs for +`boost::unordered_flat_set` and `boost::unordered_flat_map`: this is because +these containers store elements directly into their holding buckets, so +when allocating a new bucket array the elements must be transferred by means of move construction. + +In a similar manner to using `reserve` for ``vector``s, it can be a good idea +to call `reserve` before inserting a large number of elements. This will get +the expensive rehashing out of the way and let you store iterators, safe in +the knowledge that they won't be invalidated. If you are inserting `n` +elements into container `x`, you could first call: + +``` +x.reserve(n); +``` + +Note:: `reserve(n)` reserves space for at least `n` elements, allocating enough buckets +so as to not exceed the maximum load factor. ++ +Because the maximum load factor is defined as the number of elements divided by the total +number of available buckets, this function is logically equivalent to: ++ +``` +x.rehash(std::ceil(n / x.max_load_factor())) +``` ++ +See the <> on the `rehash` function. + +[#comparison] + +:idprefix: comparison_ + +== Comparison with Associative Containers + +[caption=, title='Table {counter:table-counter} Interface differences'] +[cols="1,1", frame=all, grid=rows] +|=== +|Associative Containers |Unordered Associative Containers + +|Parameterized by an ordering relation `Compare` +|Parameterized by a function object `Hash` and an equivalence relation `Pred` + +|Keys can be compared using `key_compare` which is accessed by member function `key_comp()`, values can be compared using `value_compare` which is accessed by member function `value_comp()`. +|Keys can be hashed using `hasher` which is accessed by member function `hash_function()`, and checked for equality using `key_equal` which is accessed by member function `key_eq()`. There is no function object for compared or hashing values. + +|Constructors have optional extra parameters for the comparison object. +|Constructors have optional extra parameters for the initial minimum number of buckets, a hash function and an equality object. + +|Keys `k1`, `k2` are considered equivalent if `!Compare(k1, k2) && !Compare(k2, k1)`. +|Keys `k1`, `k2` are considered equivalent if `Pred(k1, k2)` + +|Member function `lower_bound(k)` and `upper_bound(k)` +|No equivalent. Since the elements aren't ordered `lower_bound` and `upper_bound` would be meaningless. + +|`equal_range(k)` returns an empty range at the position that `k` would be inserted if `k` isn't present in the container. +|`equal_range(k)` returns a range at the end of the container if `k` isn't present in the container. It can't return a positioned range as `k` could be inserted into multiple place. + +**Closed-addressing containers:** To find out the bucket that `k` would be inserted into use `bucket(k)`. But remember that an insert can cause the container to rehash - meaning that the element can be inserted into a different bucket. + +|`iterator`, `const_iterator` are of the bidirectional category. +|`iterator`, `const_iterator` are of at least the forward category. + +|Iterators, pointers and references to the container's elements are never invalidated. +|<>. + +**Node-based containers:** Pointers and references to the container's elements are never invalidated. + +**Flat containers:** Pointers and references to the container's elements are invalidated when rehashing occurs. + +|Iterators iterate through the container in the order defined by the comparison object. +|Iterators iterate through the container in an arbitrary order, that can change as elements are inserted, although equivalent elements are always adjacent. + +|No equivalent +|**Closed-addressing containers:** Local iterators can be used to iterate through individual buckets. (The order of local iterators and iterators aren't required to have any correspondence.) + +|Can be compared using the `==`, `!=`, `<`, `\<=`, `>`, `>=` operators. +|Can be compared using the `==` and `!=` operators. + +| +|When inserting with a hint, implementations are permitted to ignore the hint. + +|=== + +--- + +[caption=, title='Table {counter:table-counter} Complexity Guarantees'] +[cols="1,1,1", frame=all, grid=rows] +|=== +|Operation |Associative Containers |Unordered Associative Containers + +|Construction of empty container +|constant +|O(_n_) where _n_ is the minimum number of buckets. + +|Construction of container from a range of _N_ elements +|O(_N log N_), O(_N_) if the range is sorted with `value_comp()` +|Average case O(_N_), worst case O(_N^2^_) + +|Insert a single element +|logarithmic +|Average case constant, worst case linear + +|Insert a single element with a hint +|Amortized constant if `t` elements inserted right after hint, logarithmic otherwise +|Average case constant, worst case linear (ie. the same as a normal insert). + +|Inserting a range of _N_ elements +|_N_ log(`size()` + _N_) +|Average case O(_N_), worst case O(_N_ * `size()`) + +|Erase by key, `k` +|O(log(`size()`) + `count(k)`) +|Average case: O(`count(k)`), Worst case: O(`size()`) + +|Erase a single element by iterator +|Amortized constant +|Average case: O(1), Worst case: O(`size()`) + +|Erase a range of _N_ elements +|O(log(`size()`) + _N_) +|Average case: O(_N_), Worst case: O(`size()`) + +|Clearing the container +|O(`size()`) +|O(`size()`) + +|Find +|logarithmic +|Average case: O(1), Worst case: O(`size()`) + +|Count +|O(log(`size()`) + `count(k)`) +|Average case: O(1), Worst case: O(`size()`) + +|`equal_range(k)` +|logarithmic +|Average case: O(`count(k)`), Worst case: O(`size()`) + +|`lower_bound`,`upper_bound` +|logarithmic +|n/a + +|=== diff --git a/doc/modules/ROOT/pages/structures.adoc b/doc/modules/ROOT/pages/structures.adoc new file mode 100644 index 00000000..e9993da5 --- /dev/null +++ b/doc/modules/ROOT/pages/structures.adoc @@ -0,0 +1,180 @@ +[#structures] += Data Structures + +:idprefix: structures_ + +== Closed-addressing Containers + +++++ + +++++ + +Boost.Unordered sports one of the fastest implementations of closed addressing, also commonly known as https://en.wikipedia.org/wiki/Hash_table#Separate_chaining[separate chaining]. An example figure representing the data structure is below: + +[#img-bucket-groups,.text-center] +.A simple bucket group approach +image::bucket-groups.png[align=center] + +An array of "buckets" is allocated and each bucket in turn points to its own individual linked list. This makes meeting the standard requirements of bucket iteration straight-forward. Unfortunately, iteration of the entire container is often times slow using this layout as each bucket must be examined for occupancy, yielding a time complexity of `O(bucket_count() + size())` when the standard requires complexity to be `O(size())`. + +Canonical standard implementations will wind up looking like the diagram below: + +[.text-center] +.The canonical standard approach +image::singly-linked.png[align=center,link=_images/singly-linked.png,window=_blank] + +It's worth noting that this approach is only used by pass:[libc++] and pass:[libstdc++]; the MSVC Dinkumware implementation uses a different one. A more detailed analysis of the standard containers can be found http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html[here]. + +This unusually laid out data structure is chosen to make iteration of the entire container efficient by inter-connecting all of the nodes into a singly-linked list. One might also notice that buckets point to the node _before_ the start of the bucket's elements. This is done so that removing elements from the list can be done efficiently without introducing the need for a doubly-linked list. Unfortunately, this data structure introduces a guaranteed extra indirection. For example, to access the first element of a bucket, something like this must be done: + +```c++ +auto const idx = get_bucket_idx(hash_function(key)); +node* p = buckets[idx]; // first load +node* n = p->next; // second load +if (n && is_in_bucket(n, idx)) { + value_type const& v = *n; // third load + // ... +} +``` + +With a simple bucket group layout, this is all that must be done: +```c++ +auto const idx = get_bucket_idx(hash_function(key)); +node* n = buckets[idx]; // first load +if (n) { + value_type const& v = *n; // second load + // ... +} +``` + +In practice, the extra indirection can have a dramatic performance impact to common operations such as `insert`, `find` and `erase`. But to keep iteration of the container fast, Boost.Unordered introduces a novel data structure, a "bucket group". A bucket group is a fixed-width view of a subsection of the buckets array. It contains a bitmask (a `std::size_t`) which it uses to track occupancy of buckets and contains two pointers so that it can form a doubly-linked list with non-empty groups. An example diagram is below: + +[#img-fca-layout] +.The new layout used by Boost +image::fca.png[align=center] + +Thus container-wide iteration is turned into traversing the non-empty bucket groups (an operation with constant time complexity) which reduces the time complexity back to `O(size())`. In total, a bucket group is only 4 words in size and it views `sizeof(std::size_t) * CHAR_BIT` buckets meaning that for all common implementations, there's only 4 bits of space overhead per bucket introduced by the bucket groups. + +A more detailed description of Boost.Unordered's closed-addressing implementation is +given in an +https://bannalia.blogspot.com/2022/06/advancing-state-of-art-for.html[external article]. +For more information on implementation rationale, read the +xref:rationale.adoc#rationale_open_addresing_containers[corresponding section]. + +== Open-addressing Containers + +The diagram shows the basic internal layout of `boost::unordered_flat_set`/`unordered_node_set` and +`boost:unordered_flat_map`/`unordered_node_map`. + + +[#img-foa-layout] +.Open-addressing layout used by Boost.Unordered. +image::foa.png[align=center] + +As with all open-addressing containers, elements (or pointers to the element nodes in the case of +`boost::unordered_node_set` and `boost::unordered_node_map`) are stored directly in the bucket array. +This array is logically divided into 2^_n_^ _groups_ of 15 elements each. +In addition to the bucket array, there is an associated _metadata array_ with 2^_n_^ +16-byte words. + +[#img-foa-metadata] +.Breakdown of a metadata word. +image::foa-metadata.png[align=center] + +A metadata word is divided into 15 _h_~_i_~ bytes (one for each associated +bucket), and an _overflow byte_ (_ofw_ in the diagram). The value of _h_~_i_~ is: + + - 0 if the corresponding bucket is empty. + - 1 to encode a special empty bucket called a _sentinel_, which is used internally to + stop iteration when the container has been fully traversed. + - If the bucket is occupied, a _reduced hash value_ obtained from the hash value of + the element. + +When looking for an element with hash value _h_, SIMD technologies such as +https://en.wikipedia.org/wiki/SSE2[SSE2] and +https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(Neon)[Neon] allow us +to very quickly inspect the full metadata word and look for the reduced value of _h_ among all the +15 buckets with just a handful of CPU instructions: non-matching buckets can be +readily discarded, and those whose reduced hash value matches need be inspected via full +comparison with the corresponding element. If the looked-for element is not present, +the overflow byte is inspected: + +- If the bit in the position _h_ mod 8 is zero, lookup terminates (and the +element is not present). +- If the bit is set to 1 (the group has been _overflowed_), further groups are +checked using https://en.wikipedia.org/wiki/Quadratic_probing[_quadratic probing_], and +the process is repeated. + +Insertion is algorithmically similar: empty buckets are located using SIMD, +and when going past a full group its corresponding overflow bit is set to 1. + +In architectures without SIMD support, the logical layout stays the same, but the metadata +word is codified using a technique we call _bit interleaving_: this layout allows us +to emulate SIMD with reasonably good performance using only standard arithmetic and +logical operations. + +[#img-foa-metadata-interleaving] +.Bit-interleaved metadata word. +image::foa-metadata-interleaving.png[align=center] + +A more detailed description of Boost.Unordered's open-addressing implementation is +given in an +https://bannalia.blogspot.com/2022/11/inside-boostunorderedflatmap.html[external article]. +For more information on implementation rationale, read the +xref:#rationale_open_addresing_containers[corresponding section]. + +== Concurrent Containers + +`boost::concurrent_flat_set`/`boost::concurrent_node_set` and +`boost::concurrent_flat_map`/`boost::concurrent_node_map` use the basic +xref:#structures_open_addressing_containers[open-addressing layout] described above +augmented with synchronization mechanisms. + + +[#img-cfoa-layout] +.Concurrent open-addressing layout used by Boost.Unordered. +image::cfoa.png[align=center] + +Two levels of synchronization are used: + +* Container level: A read-write mutex is used to control access from any operation +to the container. Typically, such access is in read mode (that is, concurrent) even +for modifying operations, so for most practical purposes there is no thread +contention at this level. Access is only in write mode (blocking) when rehashing or +performing container-wide operations such as swapping or assignment. +* Group level: Each 15-slot group is equipped with an 8-byte word containing: + ** A read-write spinlock for synchronized access to any element in the group. + ** An atomic _insertion counter_ used for optimistic insertion as described + below. + +By using atomic operations to access the group metadata, lookup is (group-level) +lock-free up to the point where an actual comparison needs to be done with an element +that has been previously SIMD-matched: only then is the group's spinlock used. + +Insertion uses the following _optimistic algorithm_: + +* The value of the insertion counter for the initial group in the probe +sequence is locally recorded (let's call this value `c0`). +* Lookup is as described above. If lookup finds no equivalent element, +search for an available slot for insertion successively locks/unlocks +each group in the probing sequence. +* When an available slot is located, it is preemptively occupied (its +reduced hash value is set) and the insertion counter is atomically +incremented: if no other thread has incremented the counter during the +whole operation (which is checked by comparing with `c0`), then we're +good to go and complete the insertion, otherwise we roll back and start +over. + +This algorithm has very low contention both at the lookup and actual +insertion phases in exchange for the possibility that computations have +to be started over if some other thread interferes in the process by +performing a succesful insertion beginning at the same group. In +practice, the start-over frequency is extremely small, measured in the range +of parts per million for some of our benchmarks. + +For more information on implementation rationale, read the +xref:#rationale_concurrent_containers[corresponding section]. diff --git a/doc/package-lock.json b/doc/package-lock.json new file mode 100644 index 00000000..0b562207 --- /dev/null +++ b/doc/package-lock.json @@ -0,0 +1,1606 @@ +{ + "name": "doc", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "devDependencies": { + "antora": "3.1.10" + } + }, + "node_modules/@antora/asciidoc-loader": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/asciidoc-loader/-/asciidoc-loader-3.1.10.tgz", + "integrity": "sha512-np0JkOV37CK7V4eDZUZXf4fQuCKYW3Alxl8FlyzBevXi2Ujv29O82JLbHbv1cyTsvGkGNNB+gzJIx9XBsQ7+Nw==", + "dev": true, + "dependencies": { + "@antora/logger": "3.1.10", + "@antora/user-require-helper": "~3.0", + "@asciidoctor/core": "~2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/cli": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/cli/-/cli-3.1.10.tgz", + "integrity": "sha512-gp8u9aVM0w1DtWSsB5PwvEfFYKrooPENLhN58RAfdgTrcsTsWw+CDysFZPgEaHB0Y1ZbanR82ZH/f6JVKGcZfQ==", + "dev": true, + "dependencies": { + "@antora/logger": "3.1.10", + "@antora/playbook-builder": "3.1.10", + "@antora/user-require-helper": "~3.0", + "commander": "~11.1" + }, + "bin": { + "antora": "bin/antora" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/content-aggregator": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/content-aggregator/-/content-aggregator-3.1.10.tgz", + "integrity": "sha512-OT6ZcCA7LrtNfrAZUr3hFh+Z/1isKpsfnqFjCDC66NEMqIyzJO99jq0CM66rYlYhyX7mb5BwEua8lHcwpOXNow==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "@antora/logger": "3.1.10", + "@antora/user-require-helper": "~3.0", + "braces": "~3.0", + "cache-directory": "~2.0", + "fast-glob": "~3.3", + "hpagent": "~1.2", + "isomorphic-git": "~1.25", + "js-yaml": "~4.1", + "multi-progress": "~4.0", + "picomatch": "~4.0", + "progress": "~2.0", + "should-proxy": "~1.0", + "simple-get": "~4.0", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/content-classifier": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/content-classifier/-/content-classifier-3.1.10.tgz", + "integrity": "sha512-3JJl4IIiTX00v/MirK603NoqIcHjGYAaRWt3Q4U03tI1Fv2Aho/ypO3FE45069jFf0Dx2uDJfp5kapb9gaIjdQ==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.10", + "@antora/logger": "3.1.10", + "mime-types": "~2.1", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/document-converter": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/document-converter/-/document-converter-3.1.10.tgz", + "integrity": "sha512-qi9ctgcKal8tZtWflVo66w+4zCJoBmUKRV+eA9aRRR09KDdU9r514vu1adWNgniPppISr90zD13V5l2JUy/2CQ==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.10" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/expand-path-helper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@antora/expand-path-helper/-/expand-path-helper-3.0.0.tgz", + "integrity": "sha512-7PdEIhk97v85/CSm3HynCsX14TR6oIVz1s233nNLsiWubE8tTnpPt4sNRJR+hpmIZ6Bx9c6QDp3XIoiyu/WYYA==", + "dev": true, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/file-publisher": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/file-publisher/-/file-publisher-3.1.10.tgz", + "integrity": "sha512-DPR/0d1P+kr3qV4T0Gh81POEO/aCmNWIp/oLUYAhr0HHOcFzgpTUUoLStgcYynZPFRIB7EYKSab+oYSCK17DGA==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "@antora/user-require-helper": "~3.0", + "vinyl": "~3.0", + "yazl": "~2.5" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/logger": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/logger/-/logger-3.1.10.tgz", + "integrity": "sha512-WSuIxEP2tVrhWtTj/sIrwBDjpi4ldB/1Kpiu4PXmY4/qeWP8thW6u8nXdwdDcWss5zqkZWjourvWKwVq7y8Wjg==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "pino": "~9.2", + "pino-pretty": "~11.2", + "sonic-boom": "~4.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/navigation-builder": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/navigation-builder/-/navigation-builder-3.1.10.tgz", + "integrity": "sha512-aLMK49nYsSB3mEZbLkmUXDAUYmscv2AFWu+5c3eqVGkQ6Wgyd79WQ6Bz3/TN9YqkzGL+PqGs0G39F0VQzD23Hw==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.10" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/page-composer": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/page-composer/-/page-composer-3.1.10.tgz", + "integrity": "sha512-JoEg8J8HVsnPmAgUrYSGzf0C8rQefXyCi/18ucy0utyfUvlJNsZvUbGUPx62Het9p0JP0FkAz2MTLyDlNdArVg==", + "dev": true, + "dependencies": { + "@antora/logger": "3.1.10", + "handlebars": "~4.7", + "require-from-string": "~2.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/playbook-builder": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/playbook-builder/-/playbook-builder-3.1.10.tgz", + "integrity": "sha512-UB8UmRYfkKgActTUlotdVS4FKGjaZgTnSXE7Fns1xb3/3HRanWvI+Yze1OmCkGC33cTpoQFnSYp7ySEH8LaiBw==", + "dev": true, + "dependencies": { + "@iarna/toml": "~2.2", + "convict": "~6.2", + "js-yaml": "~4.1", + "json5": "~2.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/redirect-producer": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/redirect-producer/-/redirect-producer-3.1.10.tgz", + "integrity": "sha512-IbWJGh6LmsxJQ821h0B9JfooofFZBgFLZxsbp/IoTLkBFGLFAY5tDRvB6rvubfNLRoSjM8VjEUXGqVLlwZOb+g==", + "dev": true, + "dependencies": { + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-generator": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/site-generator/-/site-generator-3.1.10.tgz", + "integrity": "sha512-NCULYtwUjIyr5FGCymhfG/zDVUmZ6pfmCPorka8mAzo4/GDx1T7bgaRL9rEIyf2AMqcm7apQiAz03mpU4kucsw==", + "dev": true, + "dependencies": { + "@antora/asciidoc-loader": "3.1.10", + "@antora/content-aggregator": "3.1.10", + "@antora/content-classifier": "3.1.10", + "@antora/document-converter": "3.1.10", + "@antora/file-publisher": "3.1.10", + "@antora/logger": "3.1.10", + "@antora/navigation-builder": "3.1.10", + "@antora/page-composer": "3.1.10", + "@antora/playbook-builder": "3.1.10", + "@antora/redirect-producer": "3.1.10", + "@antora/site-mapper": "3.1.10", + "@antora/site-publisher": "3.1.10", + "@antora/ui-loader": "3.1.10", + "@antora/user-require-helper": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-mapper": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/site-mapper/-/site-mapper-3.1.10.tgz", + "integrity": "sha512-KY1j/y0uxC2Y7RAo4r4yKv9cgFm8aZoRylZXEODJnwj3tffbZ2ZdRzSWHp6fN0QX/Algrr9JNd9CWrjcj2f3Zw==", + "dev": true, + "dependencies": { + "@antora/content-classifier": "3.1.10", + "vinyl": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/site-publisher": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/site-publisher/-/site-publisher-3.1.10.tgz", + "integrity": "sha512-G4xcUWvgth8oeEQwiu9U1cE0miQtYHwKHOobUbDBt2Y6LlC5H31zQQmAyvMwTsGRlvYRgLVtG6j9d6JBwQ6w9Q==", + "dev": true, + "dependencies": { + "@antora/file-publisher": "3.1.10" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/ui-loader": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/@antora/ui-loader/-/ui-loader-3.1.10.tgz", + "integrity": "sha512-H1f5wI5a5HjLuE/Wexvc8NZy8w83Bhqjka7t1DbwOOqP+LyxFGLx/QbBVKdTtgFNDHVMtNBlplQq0ixeoTSh0A==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0", + "braces": "~3.0", + "cache-directory": "~2.0", + "fast-glob": "~3.3", + "hpagent": "~1.2", + "js-yaml": "~4.1", + "picomatch": "~4.0", + "should-proxy": "~1.0", + "simple-get": "~4.0", + "vinyl": "~3.0", + "yauzl": "~3.1" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@antora/user-require-helper": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@antora/user-require-helper/-/user-require-helper-3.0.0.tgz", + "integrity": "sha512-KIXb8WYhnrnwH7Jj21l1w+et9k5GvcgcqvLOwxqWLEd0uVZOiMFdqFjqbVm3M+zcrs1JXWMeh2LLvxBbQs3q/Q==", + "dev": true, + "dependencies": { + "@antora/expand-path-helper": "~3.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@asciidoctor/core": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@asciidoctor/core/-/core-2.2.8.tgz", + "integrity": "sha512-oozXk7ZO1RAd/KLFLkKOhqTcG4GO3CV44WwOFg2gMcCsqCUTarvMT7xERIoWW2WurKbB0/ce+98r01p8xPOlBw==", + "dev": true, + "dependencies": { + "asciidoctor-opal-runtime": "0.3.3", + "unxhr": "1.0.1" + }, + "engines": { + "node": ">=8.11", + "npm": ">=5.0.0", + "yarn": ">=1.1.0" + } + }, + "node_modules/@iarna/toml": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/@iarna/toml/-/toml-2.2.5.tgz", + "integrity": "sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==", + "dev": true + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "dev": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, + "node_modules/antora": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/antora/-/antora-3.1.10.tgz", + "integrity": "sha512-FcXPfqxi5xrGF2fTrFiiau45q8w0bzRcnfk97nxvpvztPDHX/lUOrBF/GpaGl1JT5K085VkI3/dbxTlvWK1jjw==", + "dev": true, + "dependencies": { + "@antora/cli": "3.1.10", + "@antora/site-generator": "3.1.10" + }, + "bin": { + "antora": "bin/antora" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/asciidoctor-opal-runtime": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/asciidoctor-opal-runtime/-/asciidoctor-opal-runtime-0.3.3.tgz", + "integrity": "sha512-/CEVNiOia8E5BMO9FLooo+Kv18K4+4JBFRJp8vUy/N5dMRAg+fRNV4HA+o6aoSC79jVU/aT5XvUpxSxSsTS8FQ==", + "dev": true, + "dependencies": { + "glob": "7.1.3", + "unxhr": "1.0.1" + }, + "engines": { + "node": ">=8.11" + } + }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==", + "dev": true + }, + "node_modules/atomic-sleep": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/atomic-sleep/-/atomic-sleep-1.0.0.tgz", + "integrity": "sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/b4a": { + "version": "1.6.7", + "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.7.tgz", + "integrity": "sha512-OnAYlL5b7LEkALw87fUVafQw5rVR9RjwGd4KUwNQ6DrrNmaVaUCgLipfVlzrPQ4tWOR9P0IXGNOx50jYCCdSJg==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bare-events": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.5.0.tgz", + "integrity": "sha512-/E8dDe9dsbLyh2qrZ64PEPadOQ0F4gbl1sUJOrmph7xOiIxfY8vwab/4bFLh4Y88/Hk/ujKcrQKc+ps0mv873A==", + "dev": true, + "optional": true + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/cache-directory": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/cache-directory/-/cache-directory-2.0.0.tgz", + "integrity": "sha512-7YKEapH+2Uikde8hySyfobXBqPKULDyHNl/lhKm7cKf/GJFdG/tU/WpLrOg2y9aUrQrWUilYqawFIiGJPS6gDA==", + "dev": true, + "dependencies": { + "xdg-basedir": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==", + "dev": true + }, + "node_modules/clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==", + "dev": true + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", + "dev": true + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "dev": true, + "engines": { + "node": ">=16" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/convict": { + "version": "6.2.4", + "resolved": "https://registry.npmjs.org/convict/-/convict-6.2.4.tgz", + "integrity": "sha512-qN60BAwdMVdofckX7AlohVJ2x9UvjTNoKVXCL2LxFk1l7757EJqf1nySdMkPQer0bt8kQ5lQiyZ9/2NvrFBuwQ==", + "dev": true, + "dependencies": { + "lodash.clonedeep": "^4.5.0", + "yargs-parser": "^20.2.7" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "dev": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/dateformat": { + "version": "4.6.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-4.6.3.tgz", + "integrity": "sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==", + "dev": true + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/fast-copy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-copy/-/fast-copy-3.0.2.tgz", + "integrity": "sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==", + "dev": true + }, + "node_modules/fast-fifo": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", + "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-redact": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/fast-redact/-/fast-redact-3.5.0.tgz", + "integrity": "sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-safe-stringify": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz", + "integrity": "sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.18.0.tgz", + "integrity": "sha512-QKHXPW0hD8g4UET03SdOdunzSouc9N4AuHdsX8XNcTsuz+yYFILVNIX4l9yHABMhiEI9Db0JTTIpu0wB+Y1QQw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "deprecated": "Glob versions prior to v9 are no longer supported", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/handlebars": { + "version": "4.7.8", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", + "integrity": "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5", + "neo-async": "^2.6.2", + "source-map": "^0.6.1", + "wordwrap": "^1.0.0" + }, + "bin": { + "handlebars": "bin/handlebars" + }, + "engines": { + "node": ">=0.4.7" + }, + "optionalDependencies": { + "uglify-js": "^3.1.4" + } + }, + "node_modules/help-me": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/help-me/-/help-me-5.0.0.tgz", + "integrity": "sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==", + "dev": true + }, + "node_modules/hpagent": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/hpagent/-/hpagent-1.2.0.tgz", + "integrity": "sha512-A91dYTeIB6NoXG+PxTQpCCDDnfHsW9kc06Lvpu1TEe9gnd6ZFeiBoRO9JvzEv6xK7EX97/dUE8g/vBMTqTS3CA==", + "dev": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/isomorphic-git": { + "version": "1.25.10", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.25.10.tgz", + "integrity": "sha512-IxGiaKBwAdcgBXwIcxJU6rHLk+NrzYaaPKXXQffcA0GW3IUrQXdUPDXDo+hkGVcYruuz/7JlGBiuaeTCgIgivQ==", + "dev": true, + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha512-H5ZhCF25riFd9uB5UCkVKo61m3S/xZk1x4wA6yp/L3RFP6Z/eHH1ymQcGLo7J3GMPfm0V/7m1tryHuGVxpqEBQ==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "dev": true, + "dependencies": { + "minimist": "^1.2.5" + } + }, + "node_modules/multi-progress": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multi-progress/-/multi-progress-4.0.0.tgz", + "integrity": "sha512-9zcjyOou3FFCKPXsmkbC3ethv51SFPoA4dJD6TscIp2pUmy26kBDZW6h9XofPELrzseSkuD7r0V+emGEeo39Pg==", + "dev": true, + "peerDependencies": { + "progress": "^2.0.0" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==", + "dev": true + }, + "node_modules/on-exit-leak-free": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/on-exit-leak-free/-/on-exit-leak-free-2.1.2.tgz", + "integrity": "sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==", + "dev": true, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true + }, + "node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pino": { + "version": "9.2.0", + "resolved": "https://registry.npmjs.org/pino/-/pino-9.2.0.tgz", + "integrity": "sha512-g3/hpwfujK5a4oVbaefoJxezLzsDgLcNJeITvC6yrfwYeT9la+edCK42j5QpEQSQCZgTKapXvnQIdgZwvRaZug==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0", + "fast-redact": "^3.1.1", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.2.0", + "pino-std-serializers": "^7.0.0", + "process-warning": "^3.0.0", + "quick-format-unescaped": "^4.0.3", + "real-require": "^0.2.0", + "safe-stable-stringify": "^2.3.1", + "sonic-boom": "^4.0.1", + "thread-stream": "^3.0.0" + }, + "bin": { + "pino": "bin.js" + } + }, + "node_modules/pino-abstract-transport": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pino-abstract-transport/-/pino-abstract-transport-1.2.0.tgz", + "integrity": "sha512-Guhh8EZfPCfH+PMXAb6rKOjGQEoy0xlAIn+irODG5kgfYV+BQ0rGYYWTIel3P5mmyXqkYkPmdIkywsn6QKUR1Q==", + "dev": true, + "dependencies": { + "readable-stream": "^4.0.0", + "split2": "^4.0.0" + } + }, + "node_modules/pino-abstract-transport/node_modules/readable-stream": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", + "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-pretty": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/pino-pretty/-/pino-pretty-11.2.2.tgz", + "integrity": "sha512-2FnyGir8nAJAqD3srROdrF1J5BIcMT4nwj7hHSc60El6Uxlym00UbCCd8pYIterstVBFlMyF1yFV8XdGIPbj4A==", + "dev": true, + "dependencies": { + "colorette": "^2.0.7", + "dateformat": "^4.6.3", + "fast-copy": "^3.0.2", + "fast-safe-stringify": "^2.1.1", + "help-me": "^5.0.0", + "joycon": "^3.1.1", + "minimist": "^1.2.6", + "on-exit-leak-free": "^2.1.0", + "pino-abstract-transport": "^1.0.0", + "pump": "^3.0.0", + "readable-stream": "^4.0.0", + "secure-json-parse": "^2.4.0", + "sonic-boom": "^4.0.1", + "strip-json-comments": "^3.1.1" + }, + "bin": { + "pino-pretty": "bin.js" + } + }, + "node_modules/pino-pretty/node_modules/readable-stream": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.6.0.tgz", + "integrity": "sha512-cbAdYt0VcnpN2Bekq7PU+k363ZRsPwJoEEJOEtSJQlJXzwaxt3FIo/uL+KeDSGIjJqtkwyge4KQgD2S2kd+CQw==", + "dev": true, + "dependencies": { + "abort-controller": "^3.0.0", + "buffer": "^6.0.3", + "events": "^3.3.0", + "process": "^0.11.10", + "string_decoder": "^1.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/pino-std-serializers": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pino-std-serializers/-/pino-std-serializers-7.0.0.tgz", + "integrity": "sha512-e906FRY0+tV27iq4juKzSYPbUj2do2X2JX4EzSca1631EB2QJQUqGbDuERal7LCtOpxl6x3+nvo9NPZcmjkiFA==", + "dev": true + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-warning": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/process-warning/-/process-warning-3.0.0.tgz", + "integrity": "sha512-mqn0kFRl0EoqhnL0GQ0veqFHyIN1yig9RHh/InzORTUiZHFRAur+aMtRkELNwGs9aNwKS6tg/An4NYBPGwvtzQ==", + "dev": true + }, + "node_modules/progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/queue-tick": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz", + "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==", + "dev": true + }, + "node_modules/quick-format-unescaped": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/quick-format-unescaped/-/quick-format-unescaped-4.0.4.tgz", + "integrity": "sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==", + "dev": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/real-require": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/real-require/-/real-require-0.2.0.tgz", + "integrity": "sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==", + "dev": true, + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==", + "dev": true + }, + "node_modules/replace-ext": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz", + "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-stable-stringify": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", + "integrity": "sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/secure-json-parse": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/secure-json-parse/-/secure-json-parse-2.7.0.tgz", + "integrity": "sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==", + "dev": true + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/should-proxy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/should-proxy/-/should-proxy-1.0.4.tgz", + "integrity": "sha512-RPQhIndEIVUCjkfkQ6rs6sOR6pkxJWCNdxtfG5pP0RVgUYbK5911kLTF0TNcCC0G3YCGd492rMollFT2aTd9iQ==", + "dev": true + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/sonic-boom": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/sonic-boom/-/sonic-boom-4.0.1.tgz", + "integrity": "sha512-hTSD/6JMLyT4r9zeof6UtuBDpjJ9sO08/nmS5djaA9eozT9oOlNdpXSnzcgj4FTqpk3nkLrs61l4gip9r1HCrQ==", + "dev": true, + "dependencies": { + "atomic-sleep": "^1.0.0" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "dev": true, + "engines": { + "node": ">= 10.x" + } + }, + "node_modules/streamx": { + "version": "2.21.1", + "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.21.1.tgz", + "integrity": "sha512-PhP9wUnFLa+91CPy3N6tiQsK+gnYyUNuk15S3YG/zjYE7RuPeCjJngqnzpC31ow0lzBHQ+QGO4cNJnd0djYUsw==", + "dev": true, + "dependencies": { + "fast-fifo": "^1.3.2", + "queue-tick": "^1.0.1", + "text-decoder": "^1.1.0" + }, + "optionalDependencies": { + "bare-events": "^2.2.0" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/teex": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz", + "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==", + "dev": true, + "dependencies": { + "streamx": "^2.12.5" + } + }, + "node_modules/text-decoder": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.3.tgz", + "integrity": "sha512-3/o9z3X0X0fTupwsYvR03pJ/DjWuqqrfwBgTQzdWDiQSm9KitAyz/9WqsT2JQW7KV2m+bC2ol/zqpW37NHxLaA==", + "dev": true, + "dependencies": { + "b4a": "^1.6.4" + } + }, + "node_modules/thread-stream": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/thread-stream/-/thread-stream-3.1.0.tgz", + "integrity": "sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==", + "dev": true, + "dependencies": { + "real-require": "^0.2.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/uglify-js": { + "version": "3.19.3", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.19.3.tgz", + "integrity": "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ==", + "dev": true, + "optional": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unxhr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unxhr/-/unxhr-1.0.1.tgz", + "integrity": "sha512-MAhukhVHyaLGDjyDYhy8gVjWJyhTECCdNsLwlMoGFoNJ3o79fpQhtQuzmAE4IxCMDwraF4cW8ZjpAV0m9CRQbg==", + "dev": true, + "engines": { + "node": ">=8.11" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/vinyl": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz", + "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==", + "dev": true, + "dependencies": { + "clone": "^2.1.2", + "clone-stats": "^1.0.0", + "remove-trailing-separator": "^1.1.0", + "replace-ext": "^2.0.0", + "teex": "^1.0.1" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/xdg-basedir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-3.0.0.tgz", + "integrity": "sha512-1Dly4xqlulvPD3fZUQJLY+FUIeqN3N2MM3uqe4rCJftAvOjFa3jFGfctOgluGx4ahPbUCsZkmJILiP0Vi4T6lQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.1.3.tgz", + "integrity": "sha512-JCCdmlJJWv7L0q/KylOekyRaUrdEoUxWkWVcgorosTROCFWiS9p2NNPE9Yb91ak7b1N5SxAZEliWpspbZccivw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "dependencies": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/doc/package.json b/doc/package.json new file mode 100644 index 00000000..4dbe787a --- /dev/null +++ b/doc/package.json @@ -0,0 +1,5 @@ +{ + "devDependencies": { + "antora": "3.1.10" + } +}