diff --git a/doc/diagrams/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..c71ce263 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-arm64/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..d0da34f6 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-arm64/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..1391cd2e Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-arm64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..bfadd879 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-arm64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..bccf8d52 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x64/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..6399e6da Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x64/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..c99cea4e Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..11680c41 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..6836cfbe Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x86/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..5f5b4ba9 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x86/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..67e9f266 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x86/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..0e8d77f2 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/clang-x86/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..a02a4cf2 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x64/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..806f2b21 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x64/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..4677a61b Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..e279bebb Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..8690ca94 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x86/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..7216a415 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x86/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..898d9557 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x86/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..53d4db83 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/gcc-x86/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..3fb9474b Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x64/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..2227cd65 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x64/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..fe841c71 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x64/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..cfabae47 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x64/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png new file mode 100644 index 00000000..7920aaa6 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x86/Running erasure.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png new file mode 100644 index 00000000..83f19d9c Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x86/Running insertion.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png new file mode 100644 index 00000000..c3f60c76 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x86/Scattered successful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png b/doc/diagrams/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png new file mode 100644 index 00000000..ed7ac1f2 Binary files /dev/null and b/doc/diagrams/benchmarks-flat_map/vs-x86/Scattered unsuccessful looukp.xlsx.plot.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..1be1ec6f Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png new file mode 100644 index 00000000..d329c243 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png new file mode 100644 index 00000000..90cc446a Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png new file mode 100644 index 00000000..74805b84 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png new file mode 100644 index 00000000..554e6fe2 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice norehash.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png new file mode 100644 index 00000000..51be605b Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/running insertion.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..d2ce2a56 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png new file mode 100644 index 00000000..5b7ac632 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png new file mode 100644 index 00000000..667ab64b Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered erasure.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..265dec75 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..7eb717db Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png new file mode 100644 index 00000000..dfb5080c Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered successful looukp.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..75faa5c7 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..39efd03e Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png b/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png new file mode 100644 index 00000000..85ca2d49 Binary files /dev/null and b/doc/diagrams/benchmarks-set/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..2de06c82 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png new file mode 100644 index 00000000..af0ef4d7 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png new file mode 100644 index 00000000..d6383d34 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png new file mode 100644 index 00000000..b68953a7 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png new file mode 100644 index 00000000..036b3ca1 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice norehash.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice.png b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice.png new file mode 100644 index 00000000..089a6d6b Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/running insertion.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..d323233c Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png new file mode 100644 index 00000000..31b556bb Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice.png b/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice.png new file mode 100644 index 00000000..c105a88e Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered erasure.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..41e95e76 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..9f8c7184 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png b/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png new file mode 100644 index 00000000..b1de68aa Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered successful looukp.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..2ff40da4 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..1a62b27e Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png b/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png new file mode 100644 index 00000000..cdbe14d2 Binary files /dev/null and b/doc/diagrams/benchmarks-set/gcc/scattered unsuccessful looukp.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..4d69f0ac Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png new file mode 100644 index 00000000..668511a1 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png new file mode 100644 index 00000000..2b36767a Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png new file mode 100644 index 00000000..87b0fb39 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash.png b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash.png new file mode 100644 index 00000000..9c3235f4 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice norehash.png differ diff --git a/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice.png b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice.png new file mode 100644 index 00000000..66d3bc4d Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/running insertion.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..42cbe985 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png new file mode 100644 index 00000000..9ba0e9a9 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice.png b/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice.png new file mode 100644 index 00000000..42f6a1ba Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered erasure.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..5a5fbd46 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..e9f05076 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png b/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png new file mode 100644 index 00000000..1c533310 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered successful looukp.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png new file mode 100644 index 00000000..d8963dc0 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png new file mode 100644 index 00000000..9b9679c2 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png differ diff --git a/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png b/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png new file mode 100644 index 00000000..bd5a05c0 Binary files /dev/null and b/doc/diagrams/benchmarks-set/vs/scattered unsuccessful looukp.xlsx.practice.png differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice non-unique 5.png deleted file mode 100644 index f9f200e2..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice non-unique.png deleted file mode 100644 index c3c2ab8f..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png b/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png deleted file mode 100644 index 2e7539ed..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png b/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png deleted file mode 100644 index eec0fcc1..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash.png b/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash.png deleted file mode 100644 index e5e4b916..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice norehash.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice.png b/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice.png deleted file mode 100644 index 24807e2b..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/running insertion.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png deleted file mode 100644 index a2fe95c6..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice non-unique.png deleted file mode 100644 index eb53f3c8..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice.png b/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice.png deleted file mode 100644 index dad07371..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered erasure.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png deleted file mode 100644 index 83c39c4c..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png deleted file mode 100644 index d25ef7dd..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice.png b/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice.png deleted file mode 100644 index d4bc4fe4..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered successful looukp.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png deleted file mode 100644 index 7c43b2ad..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png deleted file mode 100644 index 41251196..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png b/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png deleted file mode 100644 index daa41516..00000000 Binary files a/doc/diagrams/benchmarks/clang_libcpp/scattered unsuccessful looukp.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice non-unique 5.png deleted file mode 100644 index 8d012b1c..00000000 Binary files a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice non-unique.png deleted file mode 100644 index 3d6ae325..00000000 Binary files a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash non-unique 5.png b/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash non-unique 5.png deleted file mode 100644 index 5c65139b..00000000 Binary files a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash non-unique.png b/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash non-unique.png deleted file mode 100644 index b33427f5..00000000 Binary files a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash.png b/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash.png deleted file mode 100644 index b0e6b5ab..00000000 Binary files a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice norehash.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice.png b/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice.png deleted file mode 100644 index a34bd7f4..00000000 Binary files a/doc/diagrams/benchmarks/gcc/running insertion.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice non-unique 5.png deleted file mode 100644 index 56cadad1..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice non-unique.png deleted file mode 100644 index bdd3aa7f..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice.png b/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice.png deleted file mode 100644 index 3d2324b0..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered erasure.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice non-unique 5.png deleted file mode 100644 index 92c60c90..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice non-unique.png deleted file mode 100644 index 98a2f15b..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice.png b/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice.png deleted file mode 100644 index d9f96588..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered successful looukp.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png deleted file mode 100644 index 497d84b5..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png deleted file mode 100644 index 312b3c76..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice.png b/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice.png deleted file mode 100644 index afaf4bf8..00000000 Binary files a/doc/diagrams/benchmarks/gcc/scattered unsuccessful looukp.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice non-unique 5.png deleted file mode 100644 index dc22eb13..00000000 Binary files a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice non-unique.png deleted file mode 100644 index efd12331..00000000 Binary files a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash non-unique 5.png b/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash non-unique 5.png deleted file mode 100644 index 311c2141..00000000 Binary files a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash non-unique.png b/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash non-unique.png deleted file mode 100644 index dbc60834..00000000 Binary files a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash.png b/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash.png deleted file mode 100644 index eab1aa2b..00000000 Binary files a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice norehash.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice.png b/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice.png deleted file mode 100644 index d71c2836..00000000 Binary files a/doc/diagrams/benchmarks/vs/running insertion.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice non-unique 5.png deleted file mode 100644 index b223b0a4..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice non-unique.png deleted file mode 100644 index 2d7a5fb4..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice.png b/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice.png deleted file mode 100644 index 50a14d84..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered erasure.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice non-unique 5.png deleted file mode 100644 index b8d48386..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice non-unique.png deleted file mode 100644 index 36555095..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice.png b/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice.png deleted file mode 100644 index 054b4537..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered successful looukp.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png b/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png deleted file mode 100644 index 810f5ecd..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice non-unique 5.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png b/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png deleted file mode 100644 index 5847127e..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice non-unique.png and /dev/null differ diff --git a/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice.png b/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice.png deleted file mode 100644 index 0f697161..00000000 Binary files a/doc/diagrams/benchmarks/vs/scattered unsuccessful looukp.xlsx.practice.png and /dev/null differ diff --git a/doc/diagrams/buckets-oa.png b/doc/diagrams/buckets-oa.png new file mode 100644 index 00000000..25fc6045 Binary files /dev/null and b/doc/diagrams/buckets-oa.png differ diff --git a/doc/unordered.adoc b/doc/unordered.adoc index deeff98e..07e09dbb 100644 --- a/doc/unordered.adoc +++ b/doc/unordered.adoc @@ -12,10 +12,10 @@ include::unordered/intro.adoc[] include::unordered/buckets.adoc[] -include::unordered/benchmarks.adoc[] include::unordered/hash_equality.adoc[] include::unordered/comparison.adoc[] include::unordered/compliance.adoc[] +include::unordered/benchmarks.adoc[] include::unordered/rationale.adoc[] include::unordered/ref.adoc[] include::unordered/changes.adoc[] diff --git a/doc/unordered/benchmarks.adoc b/doc/unordered/benchmarks.adoc index 23f2bc1d..bae45f8c 100644 --- a/doc/unordered/benchmarks.adoc +++ b/doc/unordered/benchmarks.adoc @@ -4,27 +4,29 @@ = Benchmarks -All benchmarks were created using `unordered_set` (non-duplicate) and `unordered_multiset` (duplicate). The source code can be https://github.com/joaquintides/boost_unordered_benchmark[found here]. +== 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. -The successful lookup benchmarks are done by looking up all `n` values, in the their original insertion order. +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 11 + libstdc++-v3 +=== GCC 11 + libstdc++-v3, x64 -=== Insertion +==== Insertion [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/gcc/running insertion.xlsx.practice.png[width=250,link=../diagrams/benchmarks/gcc/running insertion.xlsx.practice.png,window=_blank] -|image::benchmarks/gcc/running%20insertion.xlsx.practice non-unique.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice non-unique.png,window=_blank] -|image::benchmarks/gcc/running%20insertion.xlsx.practice non-unique 5.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice non-unique 5.png,window=_blank] +|image::benchmarks-set/gcc/running insertion.xlsx.practice.png[width=250,link=../diagrams/benchmarks-set/gcc/running insertion.xlsx.practice.png,window=_blank] +|image::benchmarks-set/gcc/running%20insertion.xlsx.practice non-unique.png[width=250,link=../diagrams/benchmarks-set/gcc/running%20insertion.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/gcc/running%20insertion.xlsx.practice non-unique 5.png[width=250,link=../diagrams/benchmarks-set/gcc/running%20insertion.xlsx.practice non-unique 5.png,window=_blank] h|non-duplicate elements h|duplicate elements @@ -36,9 +38,9 @@ max load factor 5 [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/gcc/running%20insertion.xlsx.practice norehash.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice norehash.png,window=_blank] -|image::benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique.png,window=_blank] -|image::benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,link=../diagrams/benchmarks/gcc/running%20insertion.xlsx.practice norehash non-unique 5.png,window=_blank] +|image::benchmarks-set/gcc/running%20insertion.xlsx.practice norehash.png[width=250,link=../diagrams/benchmarks-set/gcc/running%20insertion.xlsx.practice norehash.png,window=_blank] +|image::benchmarks-set/gcc/running%20insertion.xlsx.practice norehash non-unique.png[width=250,link=../diagrams/benchmarks-set/gcc/running%20insertion.xlsx.practice norehash non-unique.png,window=_blank] +|image::benchmarks-set/gcc/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,link=../diagrams/benchmarks-set/gcc/running%20insertion.xlsx.practice norehash non-unique 5.png,window=_blank] h|non-duplicate elements, + prior `reserve` @@ -50,15 +52,15 @@ prior `reserve` |=== -=== Erasure +==== Erasure [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/gcc/scattered%20erasure.xlsx.practice.png[width=250,link=../diagrams/benchmarks/gcc/scattered%20erasure.xlsx.practice.png,window=_blank] -|image::benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique.png[width=250,link=../diagrams/benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique.png,window=_blank] -|image::benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,link=../diagrams/benchmarks/gcc/scattered%20erasure.xlsx.practice non-unique 5.png,window=_blank] +|image::benchmarks-set/gcc/scattered%20erasure.xlsx.practice.png[width=250,link=../diagrams/benchmarks-set/gcc/scattered%20erasure.xlsx.practice.png,window=_blank] +|image::benchmarks-set/gcc/scattered%20erasure.xlsx.practice non-unique.png[width=250,link=../diagrams/benchmarks-set/gcc/scattered%20erasure.xlsx.practice non-unique.png,window=_blank] +|image::benchmarks-set/gcc/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,link=../diagrams/benchmarks-set/gcc/scattered%20erasure.xlsx.practice non-unique 5.png,window=_blank] h|non-duplicate elements h|duplicate elements @@ -66,15 +68,15 @@ h|duplicate elements + max load factor 5 |=== -=== Successful Lookup +==== Successful Lookup [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice.png] -|image::benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique.png] -|image::benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20successful%20looukp.xlsx.practice non-unique 5.png] +|image::benchmarks-set/gcc/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/gcc/scattered%20successful%20looukp.xlsx.practice.png] +|image::benchmarks-set/gcc/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/gcc/scattered%20successful%20looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/gcc/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/gcc/scattered%20successful%20looukp.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -83,15 +85,15 @@ max load factor 5 |=== -=== Unsuccessful lookup +==== Unsuccessful lookup [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice.png] -|image::benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png] -|image::benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png] +|image::benchmarks-set/gcc/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/gcc/scattered%20unsuccessful%20looukp.xlsx.practice.png] +|image::benchmarks-set/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/gcc/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -100,17 +102,17 @@ max load factor 5 |=== -== Clang 12 + libc++ +=== Clang 12 + libc++, x64 -=== Insertion +==== Insertion [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice.png[width=250, window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice.png] -|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique.png[width=250, window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique.png] -|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique 5.png[width=250, window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice non-unique 5.png] +|image::benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice.png[width=250, window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice non-unique.png[width=250, window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice non-unique 5.png[width=250, window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -123,9 +125,9 @@ max load factor 5 [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash.png] -|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique.png] -|image::benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique 5.png] +|image::benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice norehash.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice norehash.png] +|image::benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique.png] +|image::benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/running%20insertion.xlsx.practice norehash non-unique 5.png] h|non-duplicate elements, + prior `reserve` @@ -137,15 +139,15 @@ prior `reserve` |=== -=== Erasure +==== Erasure [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice.png] -|image::benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique.png] -|image::benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20erasure.xlsx.practice non-unique 5.png] +|image::benchmarks-set/clang_libcpp/scattered%20erasure.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20erasure.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/scattered%20erasure.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20erasure.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20erasure.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -154,15 +156,15 @@ max load factor 5 |=== -=== Successful lookup +==== Successful lookup [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice.png] -|image::benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique.png] -|image::benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique 5.png] +|image::benchmarks-set/clang_libcpp/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20successful%20looukp.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20successful%20looukp.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -171,15 +173,15 @@ max load factor 5 |=== -=== Unsuccessful lookup +==== Unsuccessful lookup [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice.png] -|image::benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png] -|image::benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png] +|image::benchmarks-set/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice.png] +|image::benchmarks-set/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/clang_libcpp/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -188,17 +190,17 @@ max load factor 5 |=== -== Visual Studio 2019 + Dinkumware +=== Visual Studio 2019 + Dinkumware, x64 -=== Insertion +==== Insertion [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/vs/running%20insertion.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice.png] -|image::benchmarks/vs/running%20insertion.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice non-unique.png] -|image::benchmarks/vs/running%20insertion.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice non-unique 5.png] +|image::benchmarks-set/vs/running%20insertion.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/running%20insertion.xlsx.practice.png] +|image::benchmarks-set/vs/running%20insertion.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/running%20insertion.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/running%20insertion.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/running%20insertion.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -211,9 +213,9 @@ max load factor 5 [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/vs/running%20insertion.xlsx.practice norehash.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice norehash.png] -|image::benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique.png] -|image::benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/running%20insertion.xlsx.practice norehash non-unique 5.png] +|image::benchmarks-set/vs/running%20insertion.xlsx.practice norehash.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/running%20insertion.xlsx.practice norehash.png] +|image::benchmarks-set/vs/running%20insertion.xlsx.practice norehash non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/running%20insertion.xlsx.practice norehash non-unique.png] +|image::benchmarks-set/vs/running%20insertion.xlsx.practice norehash non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/running%20insertion.xlsx.practice norehash non-unique 5.png] h|non-duplicate elements, + prior `reserve` @@ -225,15 +227,15 @@ prior `reserve` |=== -=== Erasure +==== Erasure [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/vs/scattered%20erasure.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20erasure.xlsx.practice.png] -|image::benchmarks/vs/scattered%20erasure.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20erasure.xlsx.practice non-unique.png] -|image::benchmarks/vs/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20erasure.xlsx.practice non-unique 5.png] +|image::benchmarks-set/vs/scattered%20erasure.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20erasure.xlsx.practice.png] +|image::benchmarks-set/vs/scattered%20erasure.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20erasure.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/scattered%20erasure.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20erasure.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -242,15 +244,15 @@ max load factor 5 |=== -=== Successful lookup +==== Successful lookup [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/vs/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20successful%20looukp.xlsx.practice.png] -|image::benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique.png] -|image::benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20successful%20looukp.xlsx.practice non-unique 5.png] +|image::benchmarks-set/vs/scattered%20successful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20successful%20looukp.xlsx.practice.png] +|image::benchmarks-set/vs/scattered%20successful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20successful%20looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/scattered%20successful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20successful%20looukp.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -259,15 +261,15 @@ max load factor 5 |=== -=== Unsuccessful lookup +==== Unsuccessful lookup [caption=] [cols="3*^.^a", frame=all, grid=all] |=== -|image::benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice.png] -|image::benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png] -|image::benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png] +|image::benchmarks-set/vs/scattered%20unsuccessful%20looukp.xlsx.practice.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20unsuccessful%20looukp.xlsx.practice.png] +|image::benchmarks-set/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique.png] +|image::benchmarks-set/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png[width=250,window=_blank,link=../diagrams/benchmarks-set/vs/scattered%20unsuccessful%20looukp.xlsx.practice non-unique 5.png] h|non-duplicate elements h|duplicate elements @@ -275,3 +277,156 @@ h|duplicate elements, + max load factor 5 |=== + +== boost::unordered_flat_map + +All benchmarks were created using: + +* `https://abseil.io/docs/cpp/guides/container[absl::flat_hash_map^]` +* `boost::unordered_flat_map` +* `boost::unordered_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 11, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/gcc-x64/Running%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x64/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x64/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x64/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x64/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x64/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x64/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x64/Scattered%20unsuccessful%20looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Clang 12, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/clang-x64/Running%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x64/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x64/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x64/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x64/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x64/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x64/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x64/Scattered%20unsuccessful%20looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Visual Studio 2019, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/vs-x64/Running%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x64/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x64/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x64/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x64/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x64/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x64/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x64/Scattered%20unsuccessful%20looukp.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%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-arm64/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/clang-arm64/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-arm64/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/clang-arm64/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-arm64/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/clang-arm64/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-arm64/Scattered%20unsuccessful%20looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== GCC 11, x86 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/gcc-x86/Running%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x86/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x86/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x86/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x86/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x86/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/gcc-x86/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/gcc-x86/Scattered%20unsuccessful%20looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Clang 12, x64 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/clang-x86/Running%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x86/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x86/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x86/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x86/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x86/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/clang-x86/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/clang-x86/Scattered%20unsuccessful%20looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + +=== Visual Studio 2019, x86 + + +[caption=] +[cols="4*^.^a", frame=all, grid=all] +|=== + +|image::benchmarks-flat_map/vs-x86/Running%20insertion.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x86/Running%20insertion.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x86/Running%20erasure.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x86/Running%20erasure.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x86/Scattered%20successful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x86/Scattered%20successful%20looukp.xlsx.plot.png] +|image::benchmarks-flat_map/vs-x86/Scattered%20unsuccessful%20looukp.xlsx.plot.png[width=250,window=_blank,link=../diagrams/benchmarks-flat_map/vs-x86/Scattered%20unsuccessful%20looukp.xlsx.plot.png] + +h|running insertion +h|running erasure +h|successful lookup +h|unsuccessful lookup + +|=== + diff --git a/doc/unordered/bibliography.adoc b/doc/unordered/bibliography.adoc index 5a2e3f11..020d3c04 100644 --- a/doc/unordered/bibliography.adoc +++ b/doc/unordered/bibliography.adoc @@ -5,6 +5,8 @@ = Bibliography * _C/C++ Users Journal_. February, 2006. Pete Becker. http://www.ddj.com/cpp/184402066[STL and TR1: Part III - Unordered containers^]. + -An introducation to the standard 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/unordered/buckets.adoc b/doc/unordered/buckets.adoc index 4c338065..42ec9189 100644 --- a/doc/unordered/buckets.adoc +++ b/doc/unordered/buckets.adoc @@ -5,7 +5,7 @@ = The Data Structure 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 an <> with 7 buckets containing 5 elements, `A`, +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). @@ -31,20 +31,34 @@ equality predicates in the next section>>. 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 +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] |=== -|Method |Description +2+^h| *All containers* +h|*Method* h|*Description* |`size_type bucket_count() const` |The number of buckets. +2+^h| *Closed-addressing containers only* + +`boost::unordered_[multi]set`, `boost::unordered_[multi]map` +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`. @@ -69,14 +83,14 @@ keep collisions to a minimum. == Controlling the number of buckets As more elements are added to an unordered associative container, the number -of elements in the buckets will increase causing performance to degrade. +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 average number of elements per bucket. +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. @@ -97,7 +111,8 @@ 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] |=== -|Method |Description +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). @@ -112,22 +127,44 @@ or close to the hint - unless your hint is unreasonably small or large. |Returns the current maximum load factor. |`float max_load_factor(float z)` -|Changes the container's maximum load factor, using `z` as a hint. +|Changes the container's maximum load factor, using `z` as a hint. + +**Open-addressing 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 containers only* + +`boost::unordered_flat_set`, `boost::unordered_flat_map` +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 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. + == Iterator Invalidation It is not specified how member functions other than `rehash` and `reserve` affect -the bucket count, although `insert` is only allowed to invalidate iterators -when the insertion causes the load factor to be greater than or equal to the -maximum load factor. For most implementations this means that `insert` will only -change the number of buckets when this happens. While iterators can be -invalidated by calls to `insert`, `rehash` and `reserve`, pointers and references to the -container's elements are never invalidated. +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 closed-addressing containers (`boost::unordered_[multi]set`, `boost::unordered_[multi]map`), +but they will when rehashing occurs for open-addressing +`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 diff --git a/doc/unordered/changes.adoc b/doc/unordered/changes.adoc index e17fe5c1..e308c988 100644 --- a/doc/unordered/changes.adoc +++ b/doc/unordered/changes.adoc @@ -6,6 +6,11 @@ :github-pr-url: https://github.com/boostorg/unordered/pull :cpp: C++ +== Release 1.81.0 - Major update + +* Added fast containers `boost::unordered_flat_map` and `boost::unordered_flat_set` + based on open addressing. + == Release 1.80.0 - Major update * Refactor internal implementation to be dramatically faster diff --git a/doc/unordered/comparison.adoc b/doc/unordered/comparison.adoc index 73ff38f9..8d8564e5 100644 --- a/doc/unordered/comparison.adoc +++ b/doc/unordered/comparison.adoc @@ -25,19 +25,22 @@ |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. 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. +|`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. -|<>. Pointers and references to the container's elements are never invalidated. +|<>. + +**Closed-addressing containers:** Pointers and references to the container's elements are never invalidated. + +**Open-addressing 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 -|Local iterators can be used to iterate through individual buckets. (The order of local iterators and iterators aren't required to have any correspondence.) +|**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. @@ -45,9 +48,6 @@ | |When inserting with a hint, implementations are permitted to ignore the hint. -|`erase` never throws an exception -|The containers' hash or predicate function can throw exceptions from `erase`. - |=== --- diff --git a/doc/unordered/compliance.adoc b/doc/unordered/compliance.adoc index 411a1ecf..16e869db 100644 --- a/doc/unordered/compliance.adoc +++ b/doc/unordered/compliance.adoc @@ -5,13 +5,15 @@ :cpp: C++ -The intent of Boost.Unordered is to implement a close (but imperfect) -implementation of the {cpp}17 standard, that will work with {cpp}98 upwards. -The wide compatibility does mean some comprimises have to be made. +== Closed-addressing containers: unordered_[multi]set, unordered_[multi]map + +The intent of Boost.Unordered is to provide a conformant +implementation of the {cpp}20 standard that will work with {cpp}98 upwards. +This wide compatibility does mean some compromises have to be made. With a compiler and library that fully support {cpp}11, the differences should be minor. -== Move emulation +=== Move emulation Support for move semantics is implemented using Boost.Move. If rvalue references are available it will use them, but if not it uses a close, @@ -23,7 +25,7 @@ but imperfect emulation. On such compilers: * The containers themselves are not movable. * Argument forwarding is not perfect. -== Use of allocators +=== Use of allocators {cpp}11 introduced a new allocator system. It's backwards compatible due to the lax requirements for allocators in the old standard, but might need @@ -56,7 +58,7 @@ Due to imperfect move emulation, some assignments might check `propagate_on_container_copy_assignment` on some compilers and `propagate_on_container_move_assignment` on others. -== Construction/Destruction using allocators +=== Construction/Destruction using allocators The following support is required for full use of {cpp}11 style construction/destruction: @@ -76,7 +78,7 @@ constructing a `std::pair` using `boost::tuple` (see <>) When support is not available `allocator_traits::construct` and `allocator_traits::destroy` are never called. -== Pointer Traits +=== Pointer Traits `pointer_traits` aren't used. Instead, pointer types are obtained from rebound allocators, this can cause problems if the allocator can't be @@ -84,7 +86,7 @@ used with incomplete types. If `const_pointer` is not defined in the allocator, `boost::pointer_to_other::type` is used to obtain a const pointer. -== Pairs +=== Pairs Since the containers use `std::pair` they're limited to the version from the current standard library. But since {cpp}11 ``std::pair``'s @@ -105,7 +107,7 @@ Older drafts of the standard also supported variadic constructors for `std::pair`, where the first argument would be used for the first part of the pair, and the remaining for the second part. -== Miscellaneous +=== Miscellaneous When swapping, `Pred` and `Hash` are not currently swapped by calling `swap`, their copy constructors are used. As a consequence when swapping @@ -114,3 +116,28 @@ an exception may be thrown from their copy constructor. Variadic constructor arguments for `emplace` are only used when both rvalue references and variadic template parameters are available. Otherwise `emplace` can only take up to 10 constructors arguments. + +== Open-addressing containers: unordered_flat_set, unordered_flat_map + +The C++ standard does not currently provide any open-addressing container +specification to adhere to, so `boost::unordered_flat_set` and +`boost::unordered_flat_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, node based). + +`unordered_flat_set` and `unordered_flat_map` 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. +`unordered_flat_set` and `unordered_flat_map` are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]. + +The main differences with C++ unordered associative containers are: + +* `value_type` must be move-constructible. +* Pointer stability is not kept under rehashing. +* `begin()` is not constant-time. +* `erase(iterator)` returns `void` instead of an iterator to the following element. +* 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. The maximum load, +exposed through the public function `max_load`, may decrease on erasure under high-load conditions. + diff --git a/doc/unordered/copyright.adoc b/doc/unordered/copyright.adoc index 57851e12..0138aa29 100644 --- a/doc/unordered/copyright.adoc +++ b/doc/unordered/copyright.adoc @@ -11,4 +11,8 @@ Copyright (C) 2005-2008 Daniel James Copyright (C) 2022 Christian Mazakas +Copyright (C) 2022 Joaquín M López Muñoz + +Copyright (C) 2022 Peter Dimov + 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/unordered/hash_traits.adoc b/doc/unordered/hash_traits.adoc new file mode 100644 index 00000000..b5e0c11c --- /dev/null +++ b/doc/unordered/hash_traits.adoc @@ -0,0 +1,46 @@ +[#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 `true` if `Hash::is_avalanching` is a valid type, +and `false` otherwise. +Users can then declare a hash function `Hash` as avalanching either by embedding an `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`. + +xref:unordered_flat_set[`boost::unordered_flat_set`] and xref:unordered_flat_map[`boost::unordered_flat_map`] +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/unordered/intro.adoc b/doc/unordered/intro.adoc index c82021fe..f015d586 100644 --- a/doc/unordered/intro.adoc +++ b/doc/unordered/intro.adoc @@ -18,12 +18,12 @@ or isn't practical. In contrast, a hash table only needs an equality function and a hash function for the key. With this in mind, unordered associative containers were added to the {cpp} -standard. This is an implementation of the containers described in {cpp}11, +standard. Boost.Unordered provides an implementation of the containers described in {cpp}11, with some <> in order to work with non-{cpp}11 compilers and libraries. `unordered_set` and `unordered_multiset` are defined in the header -`` +`` [source,c++] ---- namespace boost { @@ -44,7 +44,7 @@ namespace boost { ---- `unordered_map` and `unordered_multimap` are defined in the header -`` +`` [source,c++] ---- @@ -65,10 +65,51 @@ namespace boost { } ---- -When using Boost.TR1, these classes are included from `` and -``, with the classes added to the `std::tr1` namespace. +These containers, and all other implementations of standard unordered associative +containers, use an approach to its internal data structure design called +*closed addressing*. Starting in Boost 1.81, Boost.Unordered also provides containers +`boost::unordered_flat_set` and `boost::unordered_flat_map`, which use a +different data structure strategy commonly known as *open addressing* and depart in +a small number of ways from the standard so as to offer much better performance +in exchange (more than 2 times faster in typical scenarios): -The containers are used in a similar manner to the normal associative + +[source,c++] +---- +// #include +// +// Note: no multiset version + +namespace boost { + template < + class Key, + class Hash = boost::hash, + class Pred = std::equal_to, + class Alloc = std::allocator > + class unordered_flat_set; +} +---- + +[source,c++] +---- +// #include +// +// Note: no multimap version + +namespace boost { + template < + class Key, class Mapped, + class Hash = boost::hash, + class Pred = std::equal_to, + class Alloc = std::allocator > > + class unordered_flat_map; +} +---- + +`boost::unordered_flat_set` and `boost::unordered_flat_map` require a +reasonably compliant C++11 compiler. + +Boost.Unordered containers are used in a similar manner to the normal associative containers: [source,cpp] @@ -87,7 +128,7 @@ But since the elements aren't ordered, the output of: [source,c++] ---- -BOOST_FOREACH(map::value_type i, x) { +for(const map::value_type& i: x) { std::cout<>trait. +`boost::hash` specializations for string types are marked as avalanching. + +=== Platform interoperability + +The observable behavior of `boost::unordered_flat_set` and `boost::unordered_flat_map` is deterministically +identical across different compilers as long as their ``std::size_type``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. diff --git a/doc/unordered/ref.adoc b/doc/unordered/ref.adoc index 66924f81..f118ac05 100644 --- a/doc/unordered/ref.adoc +++ b/doc/unordered/ref.adoc @@ -5,3 +5,6 @@ include::unordered_map.adoc[] include::unordered_multimap.adoc[] include::unordered_set.adoc[] include::unordered_multiset.adoc[] +include::hash_traits.adoc[] +include::unordered_flat_map.adoc[] +include::unordered_flat_set.adoc[] diff --git a/doc/unordered/unordered_flat_map.adoc b/doc/unordered/unordered_flat_map.adoc new file mode 100644 index 00000000..777bd347 --- /dev/null +++ b/doc/unordered/unordered_flat_map.adoc @@ -0,0 +1,1311 @@ +[#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_flat_map`/`std::unordered_flat_map`: + + - `value_type` must be move-constructible. + - Pointer stability is not kept under rehashing. + - `begin()` is not constant-time. + - `erase(iterator)` returns `void`. + - 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_; + + // 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_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::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); + 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 + 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 + 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 + 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); + + void xref:#unordered_flat_map_erase_by_position[erase](iterator position); + void xref:#unordered_flat_map_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_flat_map_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_flat_map_transparent_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::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); + 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); + 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; + + // 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); + }; +} + +// 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))); + +template + typename unordered_flat_map::size_type + xref:#unordered_flat_map_erase_if[erase_if](unordered_flat_map& c, Predicate pred); +----- + +--- + +=== 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. +`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 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. + +--- + +=== 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`. + +--- + +==== 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`. + +--- + +==== 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::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); +``` +The move assignment operator. Destroys previously existing elements, move-assigns 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`. + +--- + +==== 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. + + +--- + +==== 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); +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/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. + +--- + +==== try_emplace +```c++ +template + std::pair try_emplace(const key_type& k, Args&&... args); +template + std::pair try_emplace(key_type&& k, Args&&... args); +``` + +Inserts a new node 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++ +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::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. + +-- + +--- + +==== 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); +``` + +Inserts a new node 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++ +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::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. + +-- + +--- + +==== 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); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `boost::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::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. + + +--- + +==== 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); +``` + +Inserts a new element into the container or updates an existing one by assigning to the contained value. + +If there is an element with key `k`, then it is updated by assigning `boost::forward(obj)`. + +If there is no such element, it is added to the container as: +```c++ +value_type(std::piecewise_construct, + std::forward_as_tuple(boost::forward(k)), + std::forward_as_tuple(boost::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. + +--- + + +==== Erase by Position + +```c++ +void erase(iterator position); +void erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Nothing. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + +--- + +==== Transparent Erase by Key +```c++ +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + +--- + +==== 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::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:;; 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); +``` + +[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. + +--- + +==== at +```c++ +mapped_type& at(const key_type& k); +const mapped_type& at(const key_type& 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. + +--- + +=== 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. + +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. + +=== 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(); +``` + +--- diff --git a/doc/unordered/unordered_flat_set.adoc b/doc/unordered/unordered_flat_set.adoc new file mode 100644 index 00000000..0079246e --- /dev/null +++ b/doc/unordered/unordered_flat_set.adoc @@ -0,0 +1,1110 @@ +[#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. + - `erase(iterator)` returns `void`. + - 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_; + + // 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_with_allocator[unordered_flat_set](unordered_flat_set&& other, const Allocator& a); + 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::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); + 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); + 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 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); + + void xref:#unordered_flat_set_erase_by_position[erase](iterator position); + void xref:#unordered_flat_set_erase_by_position[erase](const_iterator position); + size_type xref:#unordered_flat_set_erase_by_key[erase](const key_type& k); + template size_type xref:#unordered_flat_set_transparent_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::is_nothrow_swappable_v && + boost::is_nothrow_swappable_v); + 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); + }; +} + +// 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))); + +template + typename unordered_flat_set::size_type + xref:#unordered_flat_set_erase_if[erase_if](unordered_flat_set& c, Predicate pred); +----- + +--- + +=== 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. +`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 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. + +--- + +=== 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`. + +--- + +==== 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`. + +--- + +==== 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::is_nothrow_move_assignable_v && + boost::is_nothrow_move_assignable_v); +``` +The move assignment operator. Destroys previously existing elements, move-assigns 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`. + +--- + +==== 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. + +--- + +==== 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. + +--- + +==== 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/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. + +--- + +==== Erase by Position + +```c++ +void erase(iterator position); +void erase(const_iterator position); +``` + +Erase the element pointed to by `position`. + +[horizontal] +Throws:;; Nothing. + +--- + +==== Erase by Key +```c++ +size_type erase(const key_type& k); +``` + +Erase all elements with key equivalent to `k`. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + +--- + +==== Transparent Erase by Key +```c++ +template size_type erase(K&& k); +``` + +Erase all elements with key equivalent to `k`. + +This overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type. + +[horizontal] +Returns:;; The number of elements erased. +Throws:;; Only throws an exception if it is thrown by `hasher` or `key_equal`. + +--- + +==== 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::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:;; 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. + +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. + +=== 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(); +``` + +--- diff --git a/doc/unordered/unordered_map.adoc b/doc/unordered/unordered_map.adoc index a174a580..bcd7a86f 100644 --- a/doc/unordered/unordered_map.adoc +++ b/doc/unordered/unordered_map.adoc @@ -9,7 +9,7 @@ [listing,subs="+macros,+quotes"] ----- -// #include +// #include namespace boost { 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); @@ -69,6 +71,7 @@ namespace boost { 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); @@ -450,6 +453,19 @@ So, for example, you can't return the container from a function. --- +==== 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); @@ -553,6 +569,19 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/ --- +==== 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++ diff --git a/doc/unordered/unordered_multimap.adoc b/doc/unordered/unordered_multimap.adoc index f14f6a61..b66b0edd 100644 --- a/doc/unordered/unordered_multimap.adoc +++ b/doc/unordered/unordered_multimap.adoc @@ -9,7 +9,7 @@ [listing,subs="+macros,+quotes"] ----- -// #include +// #include namespace boost { 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); @@ -68,7 +70,9 @@ namespace boost { 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_bucket_count_and_allocator[unordered_multimap](std::initializer_list il, size_type n, 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](); @@ -416,6 +420,19 @@ So, for example, you can't return the container from a function. --- +==== 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); @@ -518,6 +535,19 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/ --- +==== 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++ diff --git a/doc/unordered/unordered_multiset.adoc b/doc/unordered/unordered_multiset.adoc index 69f94bbe..de4f39d7 100644 --- a/doc/unordered/unordered_multiset.adoc +++ b/doc/unordered/unordered_multiset.adoc @@ -9,7 +9,7 @@ [listing,subs="+macros,+quotes"] ----- -// #include +// #include namespace boost { 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); @@ -66,7 +68,9 @@ namespace boost { 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_bucket_count_and_allocator[unordered_multiset](std::initializer_list il, size_type n, 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()]; @@ -276,7 +280,7 @@ Is identical to the difference type of `iterator` and `const_iterator`. typedef _implementation-defined_ iterator; ---- -An iterator whose value type is `value_type`. +A constant iterator whose value type is `value_type`. The iterator category is at least a forward iterator. @@ -409,6 +413,19 @@ So, for example, you can't return the container from a function. --- +==== 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); @@ -512,6 +529,19 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/ --- +==== 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++ diff --git a/doc/unordered/unordered_set.adoc b/doc/unordered/unordered_set.adoc index e9bb9312..99b7442a 100644 --- a/doc/unordered/unordered_set.adoc +++ b/doc/unordered/unordered_set.adoc @@ -9,7 +9,7 @@ [listing,subs="+macros,+quotes"] ----- -// #include +// #include namespace boost { 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); @@ -67,6 +69,7 @@ namespace boost { 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); @@ -278,7 +281,7 @@ Is identical to the difference type of `iterator` and `const_iterator`. typedef _implementation-defined_ iterator; ---- -An iterator whose value type is `value_type`. +A constant iterator whose value type is `value_type`. The iterator category is at least a forward iterator. @@ -420,6 +423,19 @@ So, for example, you can't return the container from a function. --- +==== 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); @@ -523,6 +539,19 @@ Requires:;; `key_equal` needs to be https://en.cppreference.com/w/cpp/named_req/ --- +==== 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++