Compare commits

..

430 Commits

Author SHA1 Message Date
joaquintides 8149197fa8 replaced our spinlock with tbb's 2023-06-12 19:27:39 +02:00
joaquintides c2484f05f0 avoided old GCC/Clang hiccup with {} for aggregate copy construction 2023-06-09 21:31:30 +02:00
joaquintides f7e2132bdb Merge branch 'feature/cfoa' of https://github.com/boostorg/unordered into feature/cfoa 2023-06-09 21:20:36 +02:00
joaquintides 07a8b2b14d stylistic 2023-06-09 08:55:25 -07:00
joaquintides 2eac49f0ed added copy ctor for cache_aligned_size_control 2023-06-09 08:55:25 -07:00
joaquintides 6a8d7857e2 fixed unqualified swap call 2023-06-09 08:55:25 -07:00
joaquintides ef34ec5e87 added missing #include 2023-06-09 08:55:25 -07:00
joaquintides 518a5d2e1e refactored padding into a clean design 2023-06-09 08:55:25 -07:00
joaquintides 3ea8a768ca added padding between and around ml and size_ 2023-06-09 08:55:25 -07:00
joaquintides 4b877d363a updated concurrent_flat_map benchmarks 2023-06-09 08:55:25 -07:00
Christian Mazakas 2395db7bb9 Cleanup docs 2023-06-09 08:55:25 -07:00
joaquintides 7327053eea updated concurrent_flat_map benchmarks 2023-06-08 09:34:05 +02:00
Christian Mazakas af19d99b70 Clean up CI to pre-debugging state 2023-06-07 10:05:19 -07:00
joaquintides 64f9370fff implemented cacheline alignment without extended alignas 2023-06-07 11:30:52 +02:00
joaquintides ca193de243 added missing #include 2023-06-07 11:28:00 +02:00
Christian Mazakas 2914925b4d Explicitly disable ccache in GHA runner file 2023-06-06 09:14:00 -07:00
Christian Mazakas bc37851725 Remove usage of ccache from problematic gcc-12 sanitizer actions 2023-06-06 08:51:59 -07:00
Christian Mazakas f89a31849c Fix workaround for cfoa_fwd_tests 2023-06-06 08:27:55 -07:00
Christian Mazakas ec945810eb Remove problematic test from clang-3.7 runner 2023-06-05 15:56:06 -07:00
Christian Mazakas 68ddaba57a Update cfoa's fwd header to be in line with the others 2023-06-05 15:47:41 -07:00
Christian Mazakas c48c2afc56 Add gcc-13 and Ubuntu 23.04 to Drone CI 2023-06-05 14:24:38 -07:00
Christian Mazakas 01a5dd0dd1 Add concurrent_flat_map to link tests for foa 2023-06-05 14:19:18 -07:00
Christian Mazakas 300a8e61bd Add ubsan + asan jobs to gcc-12 2023-06-05 11:16:34 -07:00
joaquintides 1d2be664a0 added boost::concurrent_flat_map benchmarks 2023-06-05 20:08:32 +02:00
Christian Mazakas e6b1ef9e1e Add ubsan gcc-12 runners to drone 2023-06-05 09:32:11 -07:00
Christian Mazakas 4efb55146a Update gcc used for code coverage collection 2023-06-02 15:08:29 -07:00
Christian Mazakas 8877d21237 Replace dependency on SmartPtr with primitives in Core 2023-06-02 14:14:18 -07:00
Christian Mazakas 44c50cd2ea Resolve potential ambiguities during insertion by introducing a member function template 2023-06-01 14:19:14 -07:00
Christian Mazakas e7c1e1a56e Clean up raii count checkers to avoid extraneous assertions 2023-06-01 14:18:54 -07:00
Christian Mazakas 9a22f8fbee Add missing dependency on SmartPtr 2023-05-31 09:14:44 -07:00
Christian Mazakas 51520de04b Add allocator using fancy pointers to insert_tests 2023-05-31 07:30:37 -07:00
Christian Mazakas 6e0f76f4c2 Add missing FindThreads to CML 2023-05-30 14:52:45 -07:00
Christian Mazakas 06aa4b5c19 Cleanup test CML 2023-05-30 13:24:21 -07:00
Christian Mazakas 332540c857 Attempt to fix CMake tests 2023-05-30 12:05:10 -07:00
Christian Mazakas fdedb6c957 Add merge exceptions tests for cfoa 2023-05-30 09:19:50 -07:00
joaquintides 7aaa2e9452 polished BOOST_UNORDERED_PREFETCH[_ELEMENTS] 2023-05-28 19:09:14 +02:00
Christian Mazakas 950e640fcf Update concurrent_table to use macro-based prefetching 2023-05-26 21:06:01 -07:00
Christian Mazakas 7874625c08 Replace prefetch_elements() with macro so builtins aren't optimized away by DSE 2023-05-26 20:56:52 -07:00
Christian Mazakas 2ab4225473 Add workaround for gcc-12 and above where the prefetch call is ignored 2023-05-26 08:16:02 -07:00
Christian Mazakas c5df4ec069 Remove unused test 2023-05-25 08:41:26 -07:00
Christian Mazakas 55d79204be Add exceptions tests for cfoa assign ops 2023-05-24 15:23:09 -07:00
Christian Mazakas f5d5299b88 Flesh out constructor exception tests 2023-05-24 11:06:45 -07:00
joaquintides 253a9bccf6 fixed leak in throwing allocator-extended move ctor 2023-05-24 09:19:31 +02:00
Christian Mazakas 61f11a58ee Push up failing test case for code review purposes 2023-05-23 15:28:14 -07:00
Christian Mazakas e78dc311e3 Clean up erase tests 2023-05-23 08:43:10 -07:00
Christian Mazakas a5748c2e8b Add initial container population to insert iterator range tests 2023-05-22 15:24:36 -07:00
Christian Mazakas 146c5cb6be Clean up exception tests 2023-05-22 14:19:21 -07:00
Christian Mazakas c63a88032d Loosen restrictions on erase exceptions tests to accomodate runs where there are no successful erasures 2023-05-22 12:10:10 -07:00
Christian Mazakas 3ad164267a Update duration of erase operations to trigger successful erasures when only 2 threads are available 2023-05-22 11:37:07 -07:00
Christian Mazakas a9203ed93c Clean up erase_tests 2023-05-22 10:17:36 -07:00
Christian Mazakas 16550ded0c Add exceptional erase tests 2023-05-22 10:17:36 -07:00
joaquintides b4c75abca9 typo 2023-05-22 09:49:00 +02:00
joaquintides a696bdecf6 editorial 2023-05-21 13:10:46 +02:00
joaquintides 8865a940fc editorial 2023-05-21 12:55:23 +02:00
joaquintides 2a28698c8c editorial 2023-05-21 12:43:45 +02:00
joaquintides 96f5983f88 fixed initializer_list insert requirements 2023-05-21 12:39:02 +02:00
joaquintides ddb1148a31 reformulated static member initialization to appease VS2015 2023-05-20 12:16:30 +02:00
Christian Mazakas ffcae204ee Add insert_exception_tests 2023-05-19 12:33:23 -07:00
joaquintides f28527c4d8 removed double separating line 2023-05-19 11:28:08 +02:00
joaquintides 528f7d4b12 title cased some sections 2023-05-19 11:17:56 +02:00
joaquintides a140de4254 typos/editorial 2023-05-19 10:51:00 +02:00
Christian Mazakas f1bc948be8 Update table formatting in intro to use monospaced font 2023-05-18 13:14:58 -07:00
joaquintides 3d640ac032 refactored to modernize and improve flow 2023-05-18 20:18:58 +02:00
Christian Mazakas ff10b287e2 Remove unreliable check from swap_tests 2023-05-17 13:36:56 -07:00
Christian Mazakas 4a416501c8 Fix misuse of ctad macro 2023-05-17 10:14:45 -07:00
Christian Mazakas bf06fa97e3 Add deduction guides 2023-05-17 09:38:29 -07:00
Christian Mazakas fcf6fee0f6 Make usage of forceinline consistent with the underlying concurrent_table 2023-05-16 15:42:47 -07:00
Christian Mazakas 8ddfc8ec7a Update execution policies to accept by forwarding reference 2023-05-16 14:33:41 -07:00
Christian Mazakas 5f249bc681 Add fwd header 2023-05-16 13:31:35 -07:00
Christian Mazakas dbd1a929e6 Remove unnenecessary spinning 2023-05-16 12:34:50 -07:00
Christian Mazakas 32ff2f145e Add initial draft of equality tests 2023-05-16 11:55:56 -07:00
Christian Mazakas 63026fd320 Clean up tests to avoid needless yields and extraneous spurious wakeups 2023-05-16 09:19:43 -07:00
Christian Mazakas 6295c7f0d4 Add free function erase_if() 2023-05-15 13:40:33 -07:00
Christian Mazakas c3879e238d Add free function swap() 2023-05-15 07:54:19 -07:00
joaquintides 9260bff8f8 editorial 2023-05-15 10:20:45 +02:00
joaquintides f48fc70f4b typos/editorial 2023-05-14 11:13:48 +02:00
joaquintides 48f703132e added implementation description for cfoa 2023-05-13 19:29:41 +02:00
joaquintides 69ee0039e0 added implementation rationale for concurrent hashmap 2023-05-13 19:29:08 +02:00
joaquintides add01e2dfd added compliance section for concurrent hashmap 2023-05-13 19:28:43 +02:00
joaquintides 4b4db3dfb3 fixed links 2023-05-13 10:00:35 +02:00
joaquintides 81480feeb4 fixed regression at unprotected_emplace 2023-05-12 12:45:31 +02:00
joaquintides d615a08f76 made operator [==|!=] templated again to accommodate fwd declarations 2023-05-12 12:33:27 +02:00
joaquintides dacc1c8234 made operator[==|!=] non-templated 2023-05-12 11:41:50 +02:00
joaquintides 511e2b3272 refactored to provide equality comparison from table_core 2023-05-12 11:24:20 +02:00
Christian Mazakas bcf5d0cf13 Attempt to disable extraneous runs on CI 2023-05-11 08:39:29 -07:00
Christian Mazakas 80a1904d92 Fix call_count check in rehash_tests 2023-05-11 08:39:16 -07:00
Christian Mazakas 21afc69894 Add initial tests for rehash(), reserve() 2023-05-10 13:22:02 -07:00
Christian Mazakas c90b72a643 Squelch gcc self-move warning for version 13 2023-05-09 14:00:14 -07:00
Christian Mazakas c2c34f96a3 Improve robustness of merge_tests to schedule merges without spurious wakeups and in a wider stride of insertions 2023-05-09 14:00:14 -07:00
joaquintides 69ba1c7c00 editorial 2023-05-09 19:53:56 +02:00
joaquintides ba25041fc8 added tutorial on boost::concurrent_flat_map 2023-05-08 18:37:36 +02:00
joaquintides 02197674f4 prevented VS C4800 warning 2023-05-06 12:44:07 +02:00
Christian Mazakas f0fe62d6ab Add count(), contains() 2023-05-05 15:41:23 -07:00
Christian Mazakas 53328766b9 Return size_type instead of size_t 2023-05-05 15:41:08 -07:00
Christian Mazakas 5b775345ba Clean up concurrent_table's merge impl 2023-05-05 11:47:20 -07:00
Christian Mazakas 99b0868283 Add initial impl of merge() 2023-05-05 10:20:52 -07:00
joaquintides 1c98a4a8f1 changed all titles to Title Casing 2023-05-05 18:56:33 +02:00
joaquintides bf73366117 typo 2023-05-05 17:55:53 +02:00
joaquintides 719394c522 Split important info int separate paragraphs 2023-05-05 17:55:02 +02:00
joaquintides 03fccc1947 refined concurrency requirements and guarantees 2023-05-05 17:37:20 +02:00
joaquintides 814264082f fixed BNF syntax 2023-05-04 19:19:37 +02:00
joaquintides 70e3dc4628 Changed the return type of iterator/initializer_list insert[_or_[c]visit] and merge to size_type 2023-05-04 19:16:39 +02:00
joaquintides b72dbef1a9 added equality comparison to reference 2023-05-04 18:51:03 +02:00
joaquintides 26924c73b9 fixed space reservation in concurrent_table::operator=(std::initializer_list) 2023-05-04 18:09:28 +02:00
Christian Mazakas 23e720a968 Split up Drone jobs even further due to extended runtimes 2023-05-03 15:32:06 -07:00
Christian Mazakas 4fb7751b55 Add missing #include 2023-05-03 11:37:32 -07:00
Christian Mazakas 3c0fb0fa1b Attempt to fix flaky CI 2023-05-03 11:37:32 -07:00
Christian Mazakas 3fe0807ae9 Add test that intermixes insertion and visitation
Attempt to test the happens-before and synchronizes-with relationship, looking for potential bugs on weakly-ordered models
2023-05-03 11:37:32 -07:00
joaquintides dfb4f2a28a added reference for boost::concurrent_flat_map 2023-05-03 17:53:13 +02:00
Christian Mazakas cc4cfc7ef2 Fix bug in swap_test iteration logic that caused early termination of the swap loop 2023-05-02 15:57:16 -07:00
Christian Mazakas a9bf367d6e Test if being the kind of program that calls yield() pays dividends for flaky CI failures 2023-05-02 15:44:21 -07:00
Christian Mazakas 2ea0dbf30e Add impl of member function swap() 2023-05-02 13:44:27 -07:00
Christian Mazakas 40c4d456f3 Clean up for CI 2023-05-01 15:21:25 -07:00
Christian Mazakas 011b7a5969 Add initial impl of clear 2023-05-01 11:58:58 -07:00
Christian Mazakas c52ad849ea Add policy check that excludes unsequenced policies
It's technically UB for the callable in an unsequenced policy to acquire a lock so we add static_assert()s to catch potential user error.
2023-05-01 11:58:58 -07:00
joaquintides 615ce1e9b6 refactored unprotected_rehash_if_full out 2023-04-29 11:35:11 +02:00
Christian Mazakas bee9a3cb1a Split Drone jobs to help with CI timeouts and load 2023-04-28 14:10:58 -07:00
Christian Mazakas 081932221f Attempt to fix flaky assign_tests 2023-04-28 13:42:28 -07:00
Christian Mazakas 135c9586af Add fuzzy test mixing copy-assignment with insertion 2023-04-27 15:23:21 -07:00
Christian Mazakas 187fd3e71e Implement initializer_list assignment 2023-04-27 12:00:42 -07:00
Christian Mazakas 0959df1896 Flesh out move assignment tests 2023-04-27 09:30:49 -07:00
Christian Mazakas 7833a8359d Use Core's allocator access to handle allocator_traits not having uniform support in early C++11 compilers 2023-04-26 13:58:20 -07:00
Christian Mazakas 212c6a1e4d Add prototype of move assignment 2023-04-26 12:54:04 -07:00
Christian Mazakas d7acb7e8b8 Fix capturing in latch_tests 2023-04-26 12:54:04 -07:00
joaquintides 0bc4f2c4b9 refactored foa::concurrent_table::merge internals 2023-04-26 13:39:38 +02:00
Christian Mazakas 2b612ed120 Flesh out assign_tests 2023-04-25 13:14:08 -07:00
Christian Mazakas a7c15e86fc Update num_threads to use the concurrent hint from the stdlib 2023-04-25 12:18:15 -07:00
joaquintides 4c117ab20a made merge blocking 2023-04-25 15:53:18 +02:00
Christian Mazakas e9c6a0fef5 Add polyfill implementation of std::latch 2023-04-24 13:29:35 -07:00
Christian Mazakas ac216a93c8 Add tests back in 2023-04-24 13:29:07 -07:00
joaquintides e49fef5f9a commented out all tests except those for cfoa 2023-04-23 17:27:50 +02:00
Christian Mazakas 26ab9ff584 Add prototype copy assignment operator 2023-04-21 15:56:22 -07:00
Christian Mazakas 1e92d9f545 Refactor stateful_allocator to test helpers 2023-04-21 13:33:18 -07:00
Christian Mazakas 2cf72093b1 Update test to spin until the container is non-empty 2023-04-21 10:44:06 -07:00
Christian Mazakas 88d4d64edf Add last remaining constructors 2023-04-21 10:33:21 -07:00
joaquintides 7f7e577e77 polished description 2023-04-21 09:13:28 +02:00
Christian Mazakas 80d7203d78 Add more iterator constructor overloads 2023-04-20 15:35:04 -07:00
Christian Mazakas 5dfed4deec Update thread_runner to block on hand-rolled barrier, add yield points to hash, key_equal 2023-04-20 14:34:01 -07:00
Christian Mazakas e08f9f11a1 Add more constructors 2023-04-20 12:58:29 -07:00
Christian Mazakas c304284773 Update tests to use condition variables for work synchronization instead of sleeps 2023-04-20 12:58:29 -07:00
joaquintides 0e8affcc07 [skip ci] editorial 2023-04-20 20:40:10 +02:00
joaquintides ba00dbd65a Merge branch 'feature/cfoa' of https://github.com/boostorg/unordered into feature/cfoa 2023-04-20 18:50:29 +02:00
joaquintides c214fb44a3 completed internal code documentation 2023-04-20 18:49:42 +02:00
Christian Mazakas c704788718 Fix flaky test by starting insertion thread earlier 2023-04-20 09:25:33 -07:00
joaquintides a91efeb237 refactored size_/ml swap 2023-04-20 17:29:21 +02:00
Christian Mazakas 7812b26d3a Add allocator aware move constructors 2023-04-19 15:18:53 -07:00
Christian Mazakas 8bd07e17c3 Add forced inlining to keep msvc benchmarks on par with raw concurrent_table 2023-04-19 10:52:41 -07:00
Christian Mazakas b3c0368ab5 Clean up typedef names to avoid conflicts 2023-04-19 09:35:47 -07:00
Christian Mazakas 37edc392a5 Add allocator-aware copy constructor 2023-04-19 09:35:38 -07:00
Christian Mazakas fb403bc233 Add explicit allocator constructor 2023-04-18 15:36:12 -07:00
Christian Mazakas 910b8de697 Add iterator range + allocator constructor, continue to clean up constructor_tests 2023-04-18 15:11:53 -07:00
Christian Mazakas 3aff995ae0 Clean up constructor_tests 2023-04-18 13:38:24 -07:00
Christian Mazakas 68c018fda6 Clean up usage of decltype to help msvc-14.3 2023-04-18 12:30:34 -07:00
Christian Mazakas a9ad06139e Add move constructor 2023-04-18 12:00:08 -07:00
joaquintides 9a0e5e9ea8 dispensed with std::array 2023-04-15 12:13:40 +02:00
joaquintides b1a52d0236 explicitly declared guards' copy ctors as it prevents VS from doing spurious copies (!) 2023-04-15 09:51:01 +02:00
joaquintides 1723358298 refactored to deICE Clang<=3.8 and for clarity 2023-04-14 10:48:26 +02:00
Christian Mazakas 6bf0e93a41 Remove size check as the insertion thread may not have started by the time the check happens 2023-04-13 13:30:56 -07:00
joaquintides 0e5ef25a69 added workaround for GCC<=5 having problems with return {...} syntax 2023-04-13 19:31:20 +02:00
joaquintides ab84a922cf added workaround for lack of std::is_trivially_copy_assignable in GCC<5.0 2023-04-13 13:00:29 +02:00
Christian Mazakas d8bc38f154 Clean up tag dispatch for group_type copy assignment 2023-04-12 14:41:36 -07:00
Christian Mazakas ecd4a82ed5 Add test for select_on_container_copy_construction Allocator requirement 2023-04-12 13:58:01 -07:00
Christian Mazakas 0898219edc Test empty visitation 2023-04-12 12:23:16 -07:00
Christian Mazakas d9b62d24dc Begin work on constructors 2023-04-12 12:22:59 -07:00
Christian Mazakas b771278813 Fix copy assignment warning in gcc 2023-04-12 12:22:38 -07:00
joaquintides 2226a7238d adjusted arg constness in erase and erase_if 2023-04-11 16:32:47 +02:00
joaquintides 00c6a93a56 restored invocability static asserts 2023-04-10 11:03:11 +02:00
joaquintides 8ea1cbbd64 s/BOOST_ASSERT/BOOST_TEST to avoid unused var warnings 2023-04-10 10:17:05 +02:00
joaquintides 81a47ca88d updated more tests affected by change in position of f 2023-04-10 09:05:19 +02:00
joaquintides c54151769f updated insert_or_assign impls to f-last interface 2023-04-09 21:56:12 +02:00
joaquintides e73d5ecdd1 updated tests affected by change in position of f 2023-04-09 20:41:15 +02:00
joaquintides 8a4e987030 made f the last argument in all *_or_[c]visit functions 2023-04-09 20:20:55 +02:00
Christian Mazakas 8544d9f3c8 Clean up test/Jamfile 2023-04-07 12:40:06 -07:00
Christian Mazakas ed80cb14e2 Add visit_all() 2023-04-07 12:39:39 -07:00
Christian Mazakas 91eb2ddbd1 Fix sign comparison warning 2023-04-07 12:39:13 -07:00
Christian Mazakas 3bd28dc3d7 Implement basic version of single element visitation 2023-04-06 13:42:57 -07:00
Christian Mazakas e4d2da40f2 Add missing static_assert()s 2023-04-06 09:36:08 -07:00
Christian Mazakas a004e71dd0 Implement emplace, emplace_or_[c]visit 2023-04-05 13:21:18 -07:00
Christian Mazakas ddcab1c171 Add impl of try_emplace, try_emplace_or_[c]visit 2023-04-04 15:16:52 -07:00
Christian Mazakas e3cbf03f47 Commit missing changes to erase_if() 2023-04-03 14:11:51 -07:00
Christian Mazakas f8fbbc3b76 Add ExecutionPolicy overload of erase_if 2023-04-03 13:15:15 -07:00
Christian Mazakas 52bf2bf7a2 Add insert_or_cvisit() overloads 2023-04-03 08:14:21 -07:00
Christian Mazakas cf39fc4c38 Implement transparent erase_if, unary erase_if 2023-04-03 08:14:21 -07:00
Christian Mazakas 1309361a02 Remove erroneous move() calls 2023-04-03 08:14:21 -07:00
joaquintides 946491489e added workaround for lack of std::is_trivially_constructible in GCC<5.0 2023-04-01 12:06:39 +02:00
joaquintides 19202d2a8d avoided memset-related GCC warning 2023-04-01 09:09:22 +02:00
joaquintides 3be466966d avoided copy elision for the initialization of an atomic 2023-03-31 19:46:59 +02:00
joaquintides d22787c218 use memset for group array initialization only when permissible 2023-03-31 19:36:31 +02:00
joaquintides b86dee9a18 removed BOOST_UNORDERED_EMBEDDED_GROUP_ACCESS support 2023-03-31 18:52:00 +02:00
joaquintides 863984a7c8 fixed erase_if(x,f) return value calculation 2023-03-31 17:28:21 +02:00
joaquintides e9b3ad4a5f reverted 2023-03-31 13:07:02 +02:00
joaquintides e00d700457 experiment with unaligned embedded group 2023-03-31 11:32:29 +02:00
Christian Mazakas 53e20a2a1b Add transparent impl of erase() 2023-03-30 12:41:31 -07:00
Christian Mazakas af4cdf8fab Shorten "transparent" to "transp" 2023-03-30 12:41:18 -07:00
Christian Mazakas 7003e91d44 Harden erase() tests 2023-03-30 11:43:12 -07:00
joaquintides e86bb5cce2 stylistic 2023-03-30 14:50:19 +02:00
joaquintides 6a4728add0 removed implementation of scoped_bilock copy ctor 2023-03-30 12:39:10 +02:00
joaquintides f02afbc815 simplified scoped_bilock impl 2023-03-30 12:13:58 +02:00
joaquintides 6399dfd1e4 made erase_if returned count exact 2023-03-30 10:08:38 +02:00
Christian Mazakas f468fb77e0 Hopefully fix sign-conversion warnings 2023-03-29 15:55:22 -07:00
Christian Mazakas 5e316ebc88 Add initial draft of erase() 2023-03-29 15:00:54 -07:00
Christian Mazakas 0c90585511 Refactor myriad test helpers into separate file 2023-03-29 15:00:32 -07:00
Christian Mazakas 13b4fd7133 Fix sign-compare warnings 2023-03-29 12:16:09 -07:00
joaquintides 27b4c62bd2 fixed initialization of concurrent_table::thread:counter 2023-03-29 20:35:48 +02:00
joaquintides 846de7ca82 added cvisit overloads to concurrent_table 2023-03-29 19:17:57 +02:00
joaquintides 62cf58d1ca sprinkled some inlines 2023-03-29 18:29:15 +02:00
joaquintides 4482031329 made concurrent_table::thread_counter static 2023-03-29 16:45:15 +02:00
Christian Mazakas 7b1af37b9c Update RAII counters to use unsigned integers instead of signed 2023-03-28 14:37:52 -07:00
Christian Mazakas 1c48f665ea Add alias target for foa container tests 2023-03-28 14:30:29 -07:00
Christian Mazakas e4072747bb Implement insert_or_visit() 2023-03-28 14:28:42 -07:00
Christian Mazakas ce674c8007 Add transparent insert_or_assign 2023-03-27 15:06:28 -07:00
joaquintides 45ebc1e555 fixed call ambiguities in insert_or_visit 2023-03-27 13:39:14 +02:00
joaquintides 02c3bd4072 stylistic 2023-03-27 11:32:07 +02:00
joaquintides 5f4172c13f refactored visitation an const-protection of args to visitation functions 2023-03-27 10:17:25 +02:00
joaquintides 40c5c6907a fixed const-casting in erase_if(foa::table&,...) 2023-03-25 18:50:25 +01:00
joaquintides 8dbe380d6c changed predicate arg to an lvalue ref to avoid ADL ambiguities 2023-03-25 17:37:02 +01:00
joaquintides 37ff9de0db fixed remaining errors in erase_if(foa::table&,...) 2023-03-25 17:35:37 +01:00
joaquintides ae9f35073b avoided sign conversion warning 2023-03-25 17:17:00 +01:00
joaquintides a85df27d4c fixed previous commit 2023-03-25 12:47:19 +01:00
joaquintides 88c70b885d fixed previous commit 2023-03-25 12:37:10 +01:00
joaquintides 240f5f94b1 moved erase_if_impl from foa::table_core into foa::table 2023-03-25 12:31:49 +01:00
joaquintides 7415721f7d completed shared/exclusive visitation 2023-03-25 12:28:44 +01:00
Christian Mazakas 8b5539756b Partially implement insert_or_assign() 2023-03-24 14:35:01 -07:00
joaquintides 49ac1035bb (partially) implemented shared/exclusive visitation 2023-03-24 19:49:59 +01:00
joaquintides d085c40541 relaxed all ops of atomic_integral 2023-03-24 18:37:53 +01:00
Christian Mazakas 99d5b9b1bb Avoid unsupported typedef on earlier compilers 2023-03-24 08:57:51 -07:00
Christian Mazakas ad86f9211b Flesh out tests for insertion 2023-03-23 10:59:50 -07:00
Christian Mazakas d9515fdc2f Add insert(initializer_list) 2023-03-23 10:59:50 -07:00
Christian Mazakas eedbc6bcf7 Add missing stdlib= to drone.sh 2023-03-23 10:59:50 -07:00
joaquintides 297fb2e8c4 abode by TSan on Neon 2023-03-23 09:41:36 +01:00
Christian Mazakas 99eab2dfb1 Fix missing quotes in jsonnet file 2023-03-22 15:14:16 -07:00
Christian Mazakas 1070c9b69e Attempt to add tsan to Drone CI 2023-03-22 15:11:55 -07:00
Christian Mazakas 9e6b5a7e43 Add tsan OSX job 2023-03-22 15:07:36 -07:00
Christian Mazakas e1f11e840c update clang tsan job to use libc++ 2023-03-22 13:55:42 -07:00
Christian Mazakas f2d4f1968b Explicitly add B2_TARGETS to script invocation 2023-03-22 12:49:05 -07:00
joaquintides 4a7116b996 partially restored prior commit to nail down problem with Clang x86 2023-03-22 20:16:09 +01:00
joaquintides 41584e73d9 partially reverted prior commit to nail down problem with Clang x86 2023-03-22 20:09:53 +01:00
joaquintides 52453cb5a4 Merge branch 'feature/cfoa' of https://github.com/boostorg/unordered into feature/cfoa 2023-03-22 19:25:10 +01:00
joaquintides 44b918896d tried relaxing atomic operations 2023-03-22 19:24:46 +01:00
Christian Mazakas ff356ac083 Fix typo in GHA ci.yml 2023-03-22 11:20:03 -07:00
Christian Mazakas 3064801a89 Attempt to add tsan to GHA 2023-03-22 11:19:13 -07:00
Christian Mazakas e9d9f19e76 Flesh out insert_tests 2023-03-22 10:47:01 -07:00
Christian Mazakas 9b85c38e37 Add rehash, add missing move in insert() 2023-03-22 10:46:19 -07:00
joaquintides 0b2829c793 hardened TSan detection 2023-03-21 20:03:35 +01:00
joaquintides a9c2d1daa5 abode by TSan on SSE2 2023-03-21 19:41:55 +01:00
joaquintides d29815b3a8 group-synchronized earlier in unprotected_norehash_emplace_or_visit 2023-03-21 14:47:43 +01:00
joaquintides 7ed7878278 fixed 3df435d4d3 fix 2023-03-21 11:50:21 +01:00
Christian Mazakas 4c927cd2f2 Implement myriad insert() overloads, get first threaded test working 2023-03-20 16:00:54 -07:00
joaquintides 2fae05ed31 made concurrent_table use table_core's automatic capacity growth formula 2023-03-20 12:43:57 -07:00
joaquintides 41abb96d83 avoided sign conversion warning 2023-03-20 12:43:57 -07:00
joaquintides 63f51e7c41 fixed concurrent_table_arrays::delete_ 2023-03-20 12:43:57 -07:00
joaquintides ba4f321934 removed unused typedef 2023-03-20 12:43:57 -07:00
joaquintides 68563fab72 removed unused typedef 2023-03-20 12:43:57 -07:00
joaquintides d8e9503869 made table_arrays non-aggregate for the benefit of older compilers 2023-03-20 12:43:57 -07:00
joaquintides 86e998cbc7 fixed UB in dummy_group_accesses 2023-03-20 12:43:57 -07:00
joaquintides ce722e4d56 avoided shadowing 2023-03-20 12:43:57 -07:00
joaquintides 77eaab4803 provided concurrent_table_arrays ctor to satisfy older compilers 2023-03-20 12:43:57 -07:00
joaquintides 96562f4c3b hardened non-embedded group_access 2023-03-20 12:43:57 -07:00
joaquintides d66ceaf7fe avoided std::atomic_* aliases 2023-03-20 12:43:57 -07:00
joaquintides 2e44769247 added preliminary version of non-embedded group_access 2023-03-20 12:43:57 -07:00
joaquintides e64fd45760 removed inefficient group15::match_really_occupied 2023-03-20 12:43:57 -07:00
joaquintides 454fc7501e extended shutting down VS C4324 warning 2023-03-20 12:43:57 -07:00
joaquintides a89c62728a removed unnecessary mutable 2023-03-20 12:43:57 -07:00
joaquintides 1d8c0f91f8 avoided name hiding 2023-03-20 12:43:57 -07:00
joaquintides 25ba8e4dfc shut down VS C4324 warning 2023-03-20 12:43:57 -07:00
joaquintides fb4437219f fixed memory ordering in atomic_integral 2023-03-20 12:43:57 -07:00
joaquintides 0d1fdae84c implemented safe concurrent_table::load_factor 2023-03-20 12:43:57 -07:00
joaquintides c5debf11cf added explicit disabling/enabling of parallel algorithms 2023-03-20 12:43:57 -07:00
Christian Mazakas 9e4f89aa43 Continue fleshing out insert_tests 2023-03-20 12:43:57 -07:00
Christian Mazakas 12935eb695 Add minimal prototype of concurrent_flat_map 2023-03-20 12:43:57 -07:00
Christian Mazakas 2386188d69 Relocate macros needed by test suite into detail/fwd.hpp 2023-03-20 12:43:57 -07:00
Christian Mazakas e4b32f7f5e Update rw_spinlock impl to mirror github.com/pdimov's impl 2023-03-20 12:43:57 -07:00
Christian Mazakas 3df435d4d3 Temporarily suppress warning about memset'ing non-trivial types by using a constructor loop 2023-03-20 12:43:57 -07:00
Christian Mazakas ed076facc4 Stabilize ABI of cacheline_protected by hardcoding its alignment to 64 2023-03-20 12:43:57 -07:00
Christian Mazakas b09c5bdcf0 Add missing <execution> header 2023-03-20 12:43:57 -07:00
Christian Mazakas 6abb94bb68 Silence unused variable warnings in for_all_elements_exec 2023-03-20 12:43:57 -07:00
Christian Mazakas d2b1f095c8 Update atomic_uint nsdmi to eschew potentially deleted copy constructor 2023-03-20 12:43:57 -07:00
joaquintides 3d34571654 tried yest another variation for for_all_elements_while 2023-03-20 12:43:57 -07:00
joaquintides d683b3ac3e disabled use of match_really_occupied in for_all_elements_while 2023-03-20 12:43:57 -07:00
joaquintides e16a8737f4 shut down GCC Winterference-size 2023-03-20 12:43:57 -07:00
joaquintides 8f348aea26 temporarily disabled parallel algorithms 2023-03-20 12:43:57 -07:00
joaquintides 9a8ba2bdff re-enabled match_really_occupied in for_all_elements_while 2023-03-20 12:43:57 -07:00
joaquintides 3aaefdcc78 completed concurrent_table's API 2023-03-20 12:43:57 -07:00
joaquintides ca59ed8c50 avoided usage of match_really_occupied on for_all_elements_while (used by rehash) 2023-03-20 12:43:57 -07:00
joaquintides ff78ef25c0 removed unnecessary forwards and captures 2023-03-20 12:43:57 -07:00
joaquintides ec487b5c6c stylistic 2023-03-20 12:43:57 -07:00
joaquintides 0a03ed8170 weakened atomic_integral ops, fixed some trivial bugs 2023-03-20 12:43:57 -07:00
joaquintides 5881dcc2b2 done reverse unlock in multimutex 2023-03-20 12:43:57 -07:00
joaquintides 2070cbe2cc fixed regression in table_core(table_core&&) 2023-03-20 12:43:57 -07:00
joaquintides 8198b9c57c dropped erroneous call to user-provided f 2023-03-20 12:43:57 -07:00
joaquintides c35e9fc631 made slot setting on insertion exception safe 2023-03-20 12:43:57 -07:00
joaquintides f244ba55de switched from available to size_ 2023-03-20 12:43:57 -07:00
joaquintides 5e225fe46c micro-optimized reserve_available 2023-03-20 12:43:57 -07:00
joaquintides 06535e518e uploaded first draft of foa::concurrent_table 2023-03-20 12:43:57 -07:00
joaquintides 81584c22cf swapped member order in alloc_cted_insert_type to suppress padding warnings 2023-03-20 12:43:57 -07:00
joaquintides 83040211e8 recovered warninng supression pragmas 2023-03-20 12:43:56 -07:00
joaquintides 4ed301df97 refactored insert_type creation in emplace 2023-03-20 12:43:56 -07:00
joaquintides 8010f506a6 added SizeImpl and fixed some size arithmetic bugs 2023-03-20 12:43:56 -07:00
joaquintides 840ea1ce5c refactored some more for future concurrent_table 2023-03-20 12:43:56 -07:00
joaquintides 447306bfb9 stylistic 2023-03-20 12:43:56 -07:00
joaquintides 4569c1bec0 changed type of N to std::size_t 2023-03-20 12:43:56 -07:00
joaquintides 37ad547e18 more fixed sign issues in Neon ops 2023-03-20 12:43:56 -07:00
joaquintides e037ee8d82 fixed syntax error 2023-03-20 12:43:56 -07:00
joaquintides 9bbadfdb34 fixed sign issues in Neon ops 2023-03-20 12:43:56 -07:00
joaquintides c1b63f68c8 added missing op to plain_integral 2023-03-20 12:43:56 -07:00
joaquintides 0590e3bf8c typo 2023-03-20 12:43:56 -07:00
joaquintides 8f17f5f548 fixed static_assert 2023-03-20 12:43:56 -07:00
joaquintides 3a8bea9e1d parameterized group15 and core 2023-03-20 12:43:56 -07:00
joaquintides b33b354818 extended caae8eb9ac9a47dd224b81f22efe8ea34b084d54 to rest of "using typename"s 2023-03-20 12:43:56 -07:00
joaquintides b08837b93e added missing template keyword 2023-03-20 12:43:56 -07:00
joaquintides b3b840df30 extended Wshadow supression to foa::table 2023-03-20 12:43:56 -07:00
joaquintides 2ef47f0813 reformulated using to workaround VS problem 2023-03-20 12:43:56 -07:00
joaquintides 27f5513911 published max_load_factor 2023-03-20 12:43:56 -07:00
joaquintides a5100a9d35 fixed incomplete porting of PR187 2023-03-20 12:43:56 -07:00
joaquintides ccbc639677 made table_core protected interface public 2023-03-20 12:43:56 -07:00
joaquintides 18725a682d fixed previous fix 2023-03-20 12:43:56 -07:00
joaquintides dac1135199 fixed usage syntax for destroy_on_exit 2023-03-20 12:43:56 -07:00
joaquintides ead55a8938 s/noexcept(...)/noexcept(noexcept(...)) 2023-03-20 12:43:56 -07:00
joaquintides 8f39001ff0 fixed trivial syntax error 2023-03-20 12:43:56 -07:00
joaquintides 8b056b902e split foa::table in table and core in preparation for foa::concurrent_table 2023-03-20 12:43:56 -07:00
Christian Mazakas 5724adbbe9 Merge pull request #187 from boostorg/feature/foa_fast_iteration
Feature/foa fast iteration
2023-03-20 12:43:29 -07:00
joaquintides 1c5640cfbe s/BOOST_UNORDERED_ASSUME/BOOST_ASSERT 2023-03-08 19:12:46 +01:00
joaquintides 4d982e133e added is-not-end assumption on table_iterator::increment 2023-03-08 18:29:55 +01:00
joaquintides 1bf193b8fc updated release notes 2023-03-06 21:46:42 +01:00
joaquintides 7faec20f26 Merge branch 'feature/foa_fast_iteration' of https://github.com/boostorg/unordered into feature/foa_fast_iteration 2023-03-06 21:44:55 +01:00
joaquintides ced8b45add fixed UB with begin when using fast iteration 2023-03-06 12:44:10 -08:00
joaquintides 15c9bc40f7 added fast table_iterator::increment variant for regular-layout groups 2023-03-06 12:44:10 -08:00
joaquintides 9aedb95296 Merge pull request #185 from boostorg/fix/uses-allocator 2023-03-06 21:38:13 +01:00
Christian Mazakas e56cb4418c Remove extraneous information from TypePolicy's construct, destroy docs 2023-03-06 09:48:26 -08:00
Christian Mazakas 1ae21c6d1a Remove extraneous typedef from destroy_on_exit 2023-03-06 09:47:33 -08:00
Peter Dimov 82acad3794 Increase GHA timeout to 180 minutes 2023-03-06 17:04:06 +02:00
joaquintides c50461528c fixed UB with begin when using fast iteration 2023-03-06 13:50:25 +01:00
joaquintides bd08e49255 added fast table_iterator::increment variant for regular-layout groups 2023-03-06 11:56:49 +01:00
Peter Dimov dbba3cec7b Add C++03 deprecation notice 2023-03-06 09:43:45 +02:00
Christian Mazakas 6c5b5b3186 Update comments on type policy to include changes to construct, destroy and move 2023-03-03 11:33:32 -08:00
Christian Mazakas 47dd02a4b3 Add bugfix notes to release notes 2023-03-03 11:18:41 -08:00
Christian Mazakas 8429d1a6aa Refactor node_handle to directly store element_type by modularizing and extending it 2023-03-03 11:17:38 -08:00
Christian Mazakas 86d3f9f632 Refactor move(init_type&) to handle defects in C++20 versions of libstdc++ for gcc versions <=12 2023-03-03 11:17:38 -08:00
Christian Mazakas 48e92afd92 Refactor drop_guard into destroy_on_exit 2023-03-03 11:17:38 -08:00
Christian Mazakas 5a5c31de35 Rename storage to uninitialized_storage 2023-03-03 11:17:38 -08:00
Christian Mazakas 088941dc7b Clean up usage of Allocators for flat containers 2023-03-03 11:17:38 -08:00
Christian Mazakas 5f6f1691e5 Format node_map 2023-03-03 11:17:38 -08:00
Christian Mazakas 45d6c07be6 Update emplace() to no longer needlessly rebind its allocator 2023-03-03 11:17:38 -08:00
Christian Mazakas 5c63cd2bdb Update drone to run using the same branches as listed in GHA's ci.yml 2023-03-03 11:17:38 -08:00
Christian Mazakas 86318c1e88 Update foa to construct stack-locals with the user's Allocator during emplace() 2023-03-03 11:17:38 -08:00
Christian Mazakas 0ff1fa0f6e Add test that ensures proper uses-allocator construction is followed 2023-03-03 11:17:38 -08:00
Christian Mazakas d90bf0c438 Merge pull request #186 from boostorg/cxx03-deprecation
Update changelog to reflect planned C++03 deprecation
2023-03-01 09:53:24 -08:00
Christian Mazakas dc63438e22 Add missing end-of-list marker to compliance section 2023-03-01 09:37:49 -08:00
Christian Mazakas 0a3ac26f00 Update changelog to reflect planned C++03 deprecation 2023-02-28 15:44:44 -08:00
joaquintides c64ed1caa3 Feature/SIMD config (#184)
* added BOOST_UNORDERED_[ENABLE|DISABLE]_[SSE2|LITTLE_ENDIAN_NEON]
* renamed and refactored
* removed #undefs of SIMD usage macros
2023-02-26 16:39:50 +01:00
joaquintides efc33b18be Merge pull request #182 from boostorg/feature/unordered_node_map_docs
Feature/unordered node map docs
2023-02-25 10:20:05 +01:00
joaquintides c189d8d5e8 updated boost::unordered_(flat|node)_map benchmarks 2023-02-25 10:03:10 +01:00
joaquintides 886227db3b updated link to P2363 2023-02-24 09:58:51 +01:00
joaquintides 719eb90d03 fixed copy&paste error 2023-02-24 08:59:45 +01:00
joaquintides fadb686bc5 added boost::unordered_node_map to benchmarks 2023-02-23 20:17:01 +01:00
Christian Mazakas aebefaef0d Merge pull request #183 from boostorg/unordered_node_map_rc
Node Map Release Candidate
2023-02-22 08:39:59 -08:00
Christian Mazakas 63a564e8ff Update foa comments for changes in TypePolicy 2023-02-21 11:12:33 -08:00
Christian Mazakas 16c1593368 Remove extraneous copy constructor from flat set's type policy 2023-02-21 07:53:09 -08:00
Christian Mazakas 53580a3070 Fix bug in hint-based overload for node_type insertion where elements were erroneously reallocated 2023-02-19 21:26:06 -08:00
Christian Mazakas d26aeed68f Update node_handle tests to cover address stability for inserted nodes when using the hint-based overloads 2023-02-19 21:26:06 -08:00
Christian Mazakas 73eefd2b5d Rename Node{X}Types to TypePolicy in node-based foa containers 2023-02-19 21:26:06 -08:00
Christian Mazakas 3df600d069 Remove extraneous construct() overloads from the flat foa-based containers 2023-02-19 21:26:06 -08:00
Christian Mazakas a1adacdfe2 Refactor erase_on_exit to use a const_iterator so callsites can avoid a const cast 2023-02-19 21:26:06 -08:00
Christian Mazakas f405fa9118 Rename foa's emplace_dispatch to emplace_value 2023-02-19 21:26:06 -08:00
Christian Mazakas 7b5d6e7c29 Fix typos in code comments in foa 2023-02-19 21:26:06 -08:00
Christian Mazakas 7d0ba7178e Clean up naming in delete_ impl to use storage_traits for foa 2023-02-19 21:26:06 -08:00
Christian Mazakas df5e2c3aca Remove extraneous commented out code from foa 2023-02-19 21:26:06 -08:00
Christian Mazakas 343e344582 Reify implementation of node_handle's swap 2023-02-19 21:26:06 -08:00
Christian Mazakas 34ed463bea Reify implementation of node_handle's move assignment operator 2023-02-19 21:26:06 -08:00
Christian Mazakas 5986f75d16 Refactor node_handle's clear() member function to reset() 2023-02-19 21:26:06 -08:00
Christian Mazakas b08810c0c4 Add missing copyright notice to foa.hpp 2023-02-19 21:26:06 -08:00
Christian Mazakas 7c608ae7bc Include missing extract tests in transparent_tests 2023-02-19 21:25:25 -08:00
joaquintides d51cee35d5 updated open-addressing benchmark info 2023-02-18 12:31:26 +01:00
joaquintides d0289b4c7b editorial 2023-02-18 12:13:14 +01:00
Christian Mazakas bc7ba9cb3b Implement internal foa updates + node_handle for node-based containers 2023-02-14 10:55:35 -08:00
Christian Mazakas 6b10c8a4d3 Update unordered_flat_map for new type traits 2023-02-14 10:55:35 -08:00
Christian Mazakas b9805c7309 Update unordered_flat_set for new type traits 2023-02-14 10:55:35 -08:00
Christian Mazakas 844460fd22 Add unordered_node_map 2023-02-14 10:55:35 -08:00
Christian Mazakas a600278d27 Add unordered_node_set 2023-02-14 10:55:35 -08:00
Christian Mazakas 4398ffe8c9 Add foa-based node containers to node_handle_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas eed1eeedeb Add foa-based node containers to extract_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 8c0c230f78 Add foa-based node containers to the exception tests 2023-02-14 10:55:35 -08:00
Christian Mazakas e96ec1e79a Add foa-based node containers to transparent_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas be7dd51fab Add foa-based node containers to swap_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 4dec95840b Add foa-based node containers to simple_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas d44fb36581 Add foa-based node containers to scoped_allocator tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 9d3bbe27db Add foa-based node containers to scary_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 13ed4afc95 Add foa-based node containers to reserve_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas b3f54e74a7 Add foa-based node containers to rehash_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas d6374e2718 Add foa-based node containers to post_move_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 74156b6b06 Add foa-based node containers to noexcept_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 965048d3e6 Add foa-based node containers to move_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 36dfe6b98b Add foa-based node containers to merge_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas e4e89bdbde Add foa-based node containers to max_load_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 85a9d8d81d Add foa-based node containers to load_factor_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas b21ad13bbb Add foa-based node containers to link tests 2023-02-14 10:55:35 -08:00
Christian Mazakas f0d10308e3 Add foa-based node containers to insert_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas f240e587cb Add foa-based node containers to insert_hint_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 2a7dc9e40e Add foa-based node containers to init_type_insert_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 99b8d0063b Add foa-based node containers to incomplete_test 2023-02-14 10:55:35 -08:00
Christian Mazakas c6aff9278a Add foa-based node containers to fwd_set_test 2023-02-14 10:55:35 -08:00
Christian Mazakas 129497133e Add foa-based node containers to fwd_map_test 2023-02-14 10:55:35 -08:00
Christian Mazakas eaa9ff0cec Add foa-based node containers to find_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas fa735864a3 Add foa-based node containers to erase_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 0ce180e19b Add foa-based node containers to erase_if tests 2023-02-14 10:55:35 -08:00
Christian Mazakas e578b7eee3 Add foa-based node containers to equivalent_keys_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 1844695b0c Add foa-based node containers to equality_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 54b9adbdbc Add foa-based node containers to emplace_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 8b71656cd7 Add foa-based node containers to copy_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas a858ef5688 Add foa-based node containers to contains_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 18395c8d21 Add foa-based node containers to constructor_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas e68ec5c9a9 Add foa-based node containers to compile_set tests 2023-02-14 10:55:35 -08:00
Christian Mazakas d3b264345d Add foa-based node containers to compile_map tests 2023-02-14 10:55:35 -08:00
Christian Mazakas f1e1733c06 Add foa-based node containers to at_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas 66ffbdb881 Add foa-based node containers to assign_tests 2023-02-14 10:55:35 -08:00
Christian Mazakas f7f5466ed2 Add necessary #include's and typedefs for test suite to use foa-based node containers 2023-02-14 10:55:35 -08:00
Christian Mazakas 83410fcabe Add -Wunused-template to tests run with the clang-14 toolset 2023-02-14 10:55:35 -08:00
Christian Mazakas 1ee91d494d Fix bug in impl of test::exception::less::operator() 2023-02-14 10:55:35 -08:00
Christian Mazakas e8fe550d6c Add less_tests to track bug in test::exception::less::operator() impl 2023-02-14 10:55:35 -08:00
Christian Mazakas 5b0fe7f655 Update test::compare_range to use BOOST_TEST_ALL_WITH 2023-02-14 10:55:35 -08:00
Christian Mazakas ba439437bf Add osx 12 to gha ci matrix 2023-02-14 10:55:35 -08:00
joaquintides aa6eef135e editorial 2023-02-13 18:40:36 +01:00
joaquintides 1dd085daaa added unordered_node_[map|set] containers to the tutorial 2023-02-13 13:29:52 +01:00
joaquintides 2a8f50bcb7 added reference for unordered_node_set 2023-02-12 18:32:26 +01:00
joaquintides 866c58a879 typo 2023-02-12 17:35:02 +01:00
joaquintides c9a75a56c2 added reference for unordered_node_map 2023-02-11 13:23:34 +01:00
joaquintides e1861aa3d9 updated copyright notes 2023-02-11 13:23:12 +01:00
joaquintides 242c7cb93a updated release notes 2023-02-11 13:22:55 +01:00
joaquintides 0597463902 Merge pull request #181 from boostorg/feature/mulx_docs
Documented the new mulx-based mixing algorithm
2023-02-09 09:06:51 +01:00
joaquintides 14d80725eb documented the new mulx-based mixing algorithm 2023-02-08 20:07:23 +01:00
161 changed files with 17550 additions and 1655 deletions
+149 -22
View File
@@ -6,11 +6,12 @@ local library = "unordered";
local triggers =
{
branch: [ "master", "develop", "feature/*", "bugfix/*" ]
branch: [ "master", "develop", "bugfix/*", "fix/*", "pr/*" ]
};
local ubsan = { UBSAN: '1', UBSAN_OPTIONS: 'print_stacktrace=1' };
local asan = { ASAN: '1' };
local tsan = { TSAN: '1' };
local linux_pipeline(name, image, environment, packages = "", sources = [], arch = "amd64") =
{
@@ -157,16 +158,29 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 18.04 GCC 8 32/64",
"Linux 18.04 GCC 8 32/64 (03,11)",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11,14,17', ADDRMD: '32,64' },
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '03,11', ADDRMD: '32,64' },
"g++-8-multilib",
),
linux_pipeline(
"Linux 20.04 GCC 9* 32/64",
"Linux 18.04 GCC 8 32/64 (14,17)",
"cppalliance/droneubuntu1804:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-8', CXXSTD: '14,17', ADDRMD: '32,64' },
"g++-8-multilib",
),
linux_pipeline(
"Linux 20.04 GCC 9* 32/64 (03,11,14)",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 20.04 GCC 9* 32/64 (17,2a)",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
@@ -177,36 +191,77 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 20.04 GCC 9* S390x",
"Linux 20.04 GCC 9* S390x (03,11,14)",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a' },
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14' },
arch="s390x",
),
linux_pipeline(
"Linux 20.04 GCC 10 32/64",
"Linux 20.04 GCC 9* S390x (17,2a)",
"cppalliance/droneubuntu2004:multiarch",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a' },
arch="s390x",
),
linux_pipeline(
"Linux 20.04 GCC 10 32/64 (03,11,14)",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14,17,20', ADDRMD: '32,64' },
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '03,11,14', ADDRMD: '32,64' },
"g++-10-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 11* 32/64",
"Linux 20.04 GCC 10 32/64 (17,20)",
"cppalliance/droneubuntu2004:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-10', CXXSTD: '17,20', ADDRMD: '32,64' },
"g++-10-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 11* 32/64 (03,11,14)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14,17,2a', ADDRMD: '32,64' },
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '03,11,14', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 22.04 GCC 11* 32/64 (17,2a)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++', CXXSTD: '17,2a', ADDRMD: '32,64' },
),
linux_pipeline(
"Linux 22.04 GCC 12 32 ASAN (03,11,14)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11,14', ADDRMD: '32' } + asan,
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '03,11', ADDRMD: '32' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 32 ASAN (17,20,2b)",
"Linux 22.04 GCC 12 32 ASAN (14)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20,2b', ADDRMD: '32' } + asan,
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '14', ADDRMD: '32' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 32 ASAN (17)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17', ADDRMD: '32' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 32 ASAN (20)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '20', ADDRMD: '32' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 32 ASAN (2b)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '32' } + asan,
"g++-12-multilib",
),
@@ -218,12 +273,47 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 22.04 GCC 12 64 ASAN (17,20,2b)",
"Linux 22.04 GCC 12 64 ASAN (17)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17,20,2b', ADDRMD: '64' } + asan,
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '17', ADDRMD: '64' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 64 ASAN (20)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '20', ADDRMD: '64' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 64 ASAN (2b)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '2b', ADDRMD: '64' } + asan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 22.04 GCC 12 64 TSAN (11,14,17,20,2b)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-12', CXXSTD: '11,14,17,20,2b', ADDRMD: '64', TARGET: 'libs/unordered/test//cfoa_tests' } + tsan,
"g++-12-multilib",
),
linux_pipeline(
"Linux 23.04 GCC 13 32/64 (03,11,14)",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '03,11,14', ADDRMD: '32,64' },
"g++-13 g++-13-multilib",
),
linux_pipeline(
"Linux 23.04 GCC 13 32/64 (17,20,2b)",
"cppalliance/droneubuntu2304:1",
{ TOOLSET: 'gcc', COMPILER: 'g++-13', CXXSTD: '17,20,2b', ADDRMD: '32,64' },
"g++-13 g++-13-multilib",
),
linux_pipeline(
"Linux 16.04 Clang 3.5",
"cppalliance/droneubuntu1604:1",
@@ -330,19 +420,40 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
linux_pipeline(
"Linux 22.04 Clang 14 UBSAN",
"Linux 22.04 Clang 14 UBSAN (03,11,14)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + ubsan,
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14' } + ubsan,
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 14 ASAN",
"Linux 22.04 Clang 14 UBSAN (17,20)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14,17,20' } + asan,
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '17,20' } + ubsan,
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 14 ASAN (03,11,14)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '03,11,14' } + asan,
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 14 ASAN (17,20)",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', CXXSTD: '17,20' } + asan,
"clang-14",
),
linux_pipeline(
"Linux 22.04 Clang 14 libc++ 64 TSAN",
"cppalliance/droneubuntu2204:1",
{ TOOLSET: 'clang', COMPILER: 'clang++-14', ADDRMD: '64', TARGET: 'libs/unordered/test//cfoa_tests', CXXSTD: '11,14,17,20', STDLIB: 'libc++' } + tsan,
"clang-14 libc++-14-dev libc++abi-14-dev",
),
linux_pipeline(
"Linux 22.04 Clang 15",
"cppalliance/droneubuntu2204:1",
@@ -352,8 +463,18 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11,14,1z' } + ubsan,
"MacOS 10.15 Xcode 12.2 UBSAN (03,11)",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '03,11' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN (14)",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '14' } + ubsan,
),
macos_pipeline(
"MacOS 10.15 Xcode 12.2 UBSAN (1z)",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '1z' } + ubsan,
),
macos_pipeline(
@@ -362,6 +483,12 @@ local windows_pipeline(name, image, environment, arch = "amd64") =
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
macos_pipeline(
"MacOS 12.4 Xcode 13.4.1 TSAN",
{ TOOLSET: 'clang', COMPILER: 'clang++', CXXSTD: '11,14,1z', TARGET: 'libs/unordered/test//cfoa_tests' } + tsan,
xcode_version = "13.4.1", osx_version = "monterey", arch = "arm64",
),
windows_pipeline(
"Windows VS2015 msvc-14.0",
"cppalliance/dronevs2015",
+3 -1
View File
@@ -7,6 +7,8 @@
set -ex
export PATH=~/.local/bin:/usr/local/bin:$PATH
: ${TARGET:="libs/$LIBRARY/test"}
DRONE_BUILD_DIR=$(pwd)
BOOST_BRANCH=develop
@@ -22,4 +24,4 @@ python tools/boostdep/depinst/depinst.py $LIBRARY
./b2 -d0 headers
echo "using $TOOLSET : : $COMPILER ;" > ~/user-config.jam
./b2 -j3 libs/$LIBRARY/test toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
./b2 -j3 $TARGET toolset=$TOOLSET cxxstd=$CXXSTD variant=debug,release ${ADDRMD:+address-model=$ADDRMD} ${STDLIB:+stdlib=$STDLIB} ${UBSAN:+undefined-sanitizer=norecover debug-symbols=on} ${ASAN:+address-sanitizer=norecover debug-symbols=on} ${TSAN:+thread-sanitizer=norecover debug-symbols=on} ${LINKFLAGS:+linkflags=$LINKFLAGS}
+14 -4
View File
@@ -15,7 +15,6 @@ on:
- master
- develop
- bugfix/**
- feature/**
- fix/**
- pr/**
@@ -52,7 +51,10 @@ jobs:
- { name: "gcc-12 w/ sanitizers (17,20,2b)", sanitize: yes,
compiler: gcc-12, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
- { name: Collect coverage, coverage: yes,
compiler: gcc-8, cxxstd: '03,11', os: ubuntu-20.04, install: 'g++-8-multilib', address-model: '32,64', ccache_key: "cov" }
compiler: gcc-12, cxxstd: '03,20', os: ubuntu-22.04, install: 'g++-12-multilib', address-model: '32,64', ccache_key: "cov" }
- { name: "cfoa tsan (gcc)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: gcc-12,
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes }
# Linux, clang, libc++
- { compiler: clang-7, cxxstd: '03,11,14,17', os: ubuntu-20.04, stdlib: libc++, install: 'clang-7 libc++-7-dev libc++abi-7-dev' }
@@ -65,17 +67,23 @@ jobs:
compiler: clang-12, cxxstd: '17,20,2b', os: ubuntu-20.04, stdlib: libc++, install: 'clang-12 libc++-12-dev libc++abi-12-dev', ccache_key: "san2" }
- { compiler: clang-13, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-13 libc++-13-dev libc++abi-13-dev' }
- { compiler: clang-14, cxxstd: '03,11,14,17,20,2b', os: ubuntu-22.04, stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
# not using libc++ because of https://github.com/llvm/llvm-project/issues/52771
- { name: "clang-14 w/ sanitizers (03,11,14)", sanitize: yes,
compiler: clang-14, cxxstd: '03,11,14', os: ubuntu-22.04, ccache_key: "san1" }
- { name: "clang-14 w/ sanitizers (17,20,2b)", sanitize: yes,
compiler: clang-14, cxxstd: '17,20,2b', os: ubuntu-22.04, ccache_key: "san2" }
- { name: "cfoa tsan (clang)", cxxstd: '11,14,17,20,2b', os: ubuntu-22.04, compiler: clang-14,
targets: 'libs/unordered/test//cfoa_tests', thread-sanitize: yes,
stdlib: libc++, install: 'clang-14 libc++-14-dev libc++abi-14-dev' }
# OSX, clang
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-11, }
- { compiler: clang, cxxstd: '03,11,14,17,2a', os: macos-12, sanitize: yes }
- { compiler: clang, cxxstd: '11,14,17,2a', os: macos-12, thread-sanitize: yes, targets: 'libs/unordered/test//cfoa_tests' }
timeout-minutes: 120
timeout-minutes: 180
runs-on: ${{matrix.os}}
container: ${{matrix.container}}
env: {B2_USE_CCACHE: 1}
@@ -184,6 +192,8 @@ jobs:
B2_COMPILER: ${{matrix.compiler}}
B2_CXXSTD: ${{matrix.cxxstd}}
B2_SANITIZE: ${{matrix.sanitize}}
B2_TSAN: ${{matrix.thread-sanitize}}
B2_TARGETS: ${{matrix.targets}}
B2_STDLIB: ${{matrix.stdlib}}
# More entries can be added in the same way, see the B2_ARGS assignment in ci/enforce.sh for the possible keys.
# B2_DEFINES: ${{matrix.defines}}
@@ -197,7 +207,7 @@ jobs:
- name: Run tests
if: '!matrix.coverity'
run: ci/build.sh
run: B2_TARGETS=${{matrix.targets}} ci/build.sh
- name: Upload coverage
if: matrix.coverage
+1
View File
@@ -22,6 +22,7 @@ target_link_libraries(boost_unordered
Boost::mp11
Boost::predef
Boost::preprocessor
Boost::static_assert
Boost::throw_exception
Boost::tuple
Boost::type_traits
+10
View File
@@ -1,4 +1,5 @@
// Copyright 2021 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
@@ -272,6 +274,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -345,6 +350,9 @@ std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_map_fnv1a =
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map_fnv1a =
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map_fnv1a =
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
@@ -373,6 +381,7 @@ int main()
test<std_unordered_map>( "std::unordered_map" );
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
@@ -390,6 +399,7 @@ int main()
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
+10
View File
@@ -1,4 +1,5 @@
// Copyright 2021 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/core/detail/splitmix64.hpp>
#include <boost/config.hpp>
@@ -273,6 +275,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -346,6 +351,9 @@ std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_map_fnv1a =
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map_fnv1a =
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map_fnv1a =
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
@@ -374,6 +382,7 @@ int main()
test<std_unordered_map>( "std::unordered_map" );
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
@@ -391,6 +400,7 @@ int main()
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
+6
View File
@@ -1,4 +1,5 @@
// Copyright 2021 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/core/detail/splitmix64.hpp>
@@ -289,6 +291,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -315,6 +320,7 @@ int main()
test<std_unordered_map>( "std::unordered_map" );
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
+6
View File
@@ -1,4 +1,5 @@
// Copyright 2021 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/core/detail/splitmix64.hpp>
@@ -289,6 +291,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -325,6 +330,7 @@ int main()
#endif
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
+6
View File
@@ -1,4 +1,5 @@
// Copyright 2021, 2022 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/endian/conversion.hpp>
#include <boost/core/detail/splitmix64.hpp>
@@ -340,6 +342,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -366,6 +371,7 @@ int main()
test<std_unordered_map>( "std::unordered_map" );
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
+10
View File
@@ -1,4 +1,5 @@
// Copyright 2021, 2022 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/regex.hpp>
#ifdef HAVE_ABSEIL
@@ -227,6 +229,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -300,6 +305,9 @@ std::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_map_fnv1a =
boost::unordered_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map_fnv1a =
boost::unordered_node_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map_fnv1a =
boost::unordered_flat_map<K, V, fnv1a_hash, std::equal_to<K>, allocator_for<K, V>>;
@@ -328,6 +336,7 @@ int main()
test<std_unordered_map>( "std::unordered_map" );
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
@@ -345,6 +354,7 @@ int main()
test<std_unordered_map_fnv1a>( "std::unordered_map, FNV-1a" );
test<boost_unordered_map_fnv1a>( "boost::unordered_map, FNV-1a" );
test<boost_unordered_node_map_fnv1a>( "boost::unordered_node_map, FNV-1a" );
test<boost_unordered_flat_map_fnv1a>( "boost::unordered_flat_map, FNV-1a" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
+6
View File
@@ -1,4 +1,5 @@
// Copyright 2021, 2022 Peter Dimov.
// Copyright 2023 Joaquin M Lopez Munoz.
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt
@@ -6,6 +7,7 @@
#define _SILENCE_CXX20_CISO646_REMOVED_WARNING
#include <boost/unordered_map.hpp>
#include <boost/unordered/unordered_node_map.hpp>
#include <boost/unordered/unordered_flat_map.hpp>
#include <boost/regex.hpp>
#ifdef HAVE_ABSEIL
@@ -181,6 +183,9 @@ template<class K, class V> using std_unordered_map =
template<class K, class V> using boost_unordered_map =
boost::unordered_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_node_map =
boost::unordered_node_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
template<class K, class V> using boost_unordered_flat_map =
boost::unordered_flat_map<K, V, boost::hash<K>, std::equal_to<K>, allocator_for<K, V>>;
@@ -207,6 +212,7 @@ int main()
test<std_unordered_map>( "std::unordered_map" );
test<boost_unordered_map>( "boost::unordered_map" );
test<boost_unordered_node_map>( "boost::unordered_node_map" );
test<boost_unordered_flat_map>( "boost::unordered_flat_map" );
#ifdef HAVE_ANKERL_UNORDERED_DENSE
Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 62 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 45 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 47 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 51 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

+3 -1
View File
@@ -13,8 +13,10 @@
include::unordered/intro.adoc[]
include::unordered/buckets.adoc[]
include::unordered/hash_equality.adoc[]
include::unordered/comparison.adoc[]
include::unordered/regular.adoc[]
include::unordered/concurrent.adoc[]
include::unordered/compliance.adoc[]
include::unordered/structures.adoc[]
include::unordered/benchmarks.adoc[]
include::unordered/rationale.adoc[]
include::unordered/ref.adoc[]
+263 -2
View File
@@ -278,13 +278,14 @@ max load factor 5
|===
== boost::unordered_flat_map
== boost::unordered_(flat|node)_map
All benchmarks were created using:
* `https://abseil.io/docs/cpp/guides/container[absl::flat_hash_map^]<uint64_t, uint64_t>`
* `boost::unordered_flat_map<uint64_t, uint64_t>`
* `boost::unordered_map<uint64_t, uint64_t>`
* `boost::unordered_flat_map<uint64_t, uint64_t>`
* `boost::unordered_node_map<uint64_t, uint64_t>`
The source code can be https://github.com/boostorg/boost_unordered_benchmarks/tree/boost_unordered_flat_map[found here^].
@@ -430,3 +431,263 @@ h|unsuccessful lookup
|===
== boost::concurrent_flat_map
All benchmarks were created using:
* `https://spec.oneapi.io/versions/latest/elements/oneTBB/source/containers/concurrent_hash_map_cls.html[oneapi::tbb::concurrent_hash_map^]<int, int>`
* `https://github.com/greg7mdp/gtl/blob/main/docs/phmap.md[gtl::parallel_flat_hash_map^]<int, int>` with 64 submaps
* `boost::concurrent_flat_map<int, int>`
The source code can be https://github.com/boostorg/boost_unordered_benchmarks/tree/boost_concurrent_flat_map[found here^].
The benchmarks exercise a number of threads _T_ (between 1 and 16) concurrently performing operations
randomly chosen among **update**, **successful lookup** and **unsuccessful lookup**. The keys used in the
operations follow a https://en.wikipedia.org/wiki/Zipf%27s_law#Formal_definition[Zipf distribution^]
with different _skew_ parameters: the higher the skew, the more concentrated are the keys in the lower values
of the covered range.
=== GCC 12, x64
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x64/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
=== Clang 15, x64
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x64/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
=== Visual Studio 2022, x64
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x64/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
=== Clang 12, ARM64
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-arm64/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
=== GCC 12, x86
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/gcc-x86/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
=== Clang 15, x86
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/clang-x86/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
=== Visual Studio 2022, x86
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.500k%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.500k%2C%200.01.png]
|image::benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.500k%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.500k%2C%200.5.png]
|image::benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.500k%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.500k%2C%200.99.png]
h|500k updates, 4.5M lookups +
skew=0.01
h|500k updates, 4.5M lookups +
skew=0.5
h|500k updates, 4.5M lookups +
skew=0.99
|===
[caption=]
[cols="3*^.^a", frame=all, grid=all]
|===
|image::benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.5M%2C%200.01.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.5M%2C%200.01.png]
|image::benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.5M%2C%200.5.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.5M%2C%200.5.png]
|image::benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.5M%2C%200.99.png[width=250,window=_blank,link=../diagrams/benchmarks-concurrent_map/vs-x86/Parallel%20workload.xlsx.5M%2C%200.99.png]
h|5M updates, 45M lookups +
skew=0.01
h|5M updates, 45M lookups +
skew=0.5
h|5M updates, 45M lookups +
skew=0.99
|===
+9 -171
View File
@@ -2,9 +2,9 @@
:idprefix: buckets_
:imagesdir: ../diagrams
= The Data Structure
= Basics of Hash Tables
The containers are made up of a number of 'buckets', each of which can contain
The containers are made up of a number of _buckets_, each of which can contain
any number of elements. For example, the following diagram shows a <<unordered_set,`boost::unordered_set`>> with 7 buckets containing 5 elements, `A`,
`B`, `C`, `D` and `E` (this is just for illustration, containers will typically
have more buckets).
@@ -12,8 +12,7 @@ have more buckets).
image::buckets.png[]
In order to decide which bucket to place an element in, the container applies
the hash function, `Hash`, to the element's key (for `unordered_set` and
`unordered_multiset` the key is the whole element, but is referred to as the key
the hash function, `Hash`, to the element's key (for sets the key is the whole element, but is referred to as the key
so that the same terminology can be used for sets and maps). This returns a
value of type `std::size_t`. `std::size_t` has a much greater range of values
then the number of buckets, so the container applies another transformation to
@@ -53,8 +52,7 @@ 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`
2+^h| *Closed-addressing containers only*
h|*Method* h|*Description*
|`size_type max_bucket_count() const`
@@ -80,7 +78,7 @@ h|*Method* h|*Description*
|===
== Controlling the number of buckets
== Controlling the Number of Buckets
As more elements are added to an unordered associative container, the number
of collisions will increase causing performance to degrade.
@@ -90,8 +88,8 @@ calling `rehash`.
The standard leaves a lot of freedom to the implementer to decide how the
number of buckets is chosen, but it does make some requirements based on the
container's 'load factor', the number of elements divided by the number of buckets.
Containers also have a 'maximum load factor' which they should try to keep the
container's _load factor_, the number of elements divided by the number of buckets.
Containers also have a _maximum load factor_ which they should try to keep the
load factor below.
You can't control the bucket count directly but there are two ways to
@@ -133,8 +131,7 @@ h|*Method* h|*Description*
|`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`
2+^h| *Open-addressing and concurrent containers only*
h|*Method* h|*Description*
|`size_type max_load() const`
@@ -142,7 +139,7 @@ h|*Method* h|*Description*
|===
A note on `max_load` for open-addressing containers: the maximum load will be
A note on `max_load` for open-addressing and concurrent containers: the maximum load will be
(`max_load_factor() * bucket_count()`) right after `rehash` or on container creation, but may
slightly decrease when erasing elements in high-load situations. For instance, if we
have a <<unordered_flat_map,`boost::unordered_flat_map`>> with `size()` almost
@@ -150,163 +147,4 @@ at `max_load()` level and then erase 1,000 elements, `max_load()` may decrease b
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` 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
the expensive rehashing out of the way and let you store iterators, safe in
the knowledge that they won't be invalidated. If you are inserting `n`
elements into container `x`, you could first call:
```
x.reserve(n);
```
Note:: `reserve(n)` reserves space for at least `n` elements, allocating enough buckets
so as to not exceed the maximum load factor.
+
Because the maximum load factor is defined as the number of elements divided by the total
number of available buckets, this function is logically equivalent to:
+
```
x.rehash(std::ceil(n / x.max_load_factor()))
```
+
See the <<unordered_map_rehash,reference for more details>> on the `rehash` function.
== Fast Closed Addressing Implementation
++++
<style>
.imageblock > .title {
text-align: inherit;
}
</style>
++++
Boost.Unordered sports one of the fastest implementations of closed addressing, also commonly known as https://en.wikipedia.org/wiki/Hash_table#Separate_chaining[separate chaining]. An example figure representing the data structure is below:
[#img-bucket-groups,.text-center]
.A simple bucket group approach
image::bucket-groups.png[align=center]
An array of "buckets" is allocated and each bucket in turn points to its own individual linked list. This makes meeting the standard requirements of bucket iteration straight-forward. Unfortunately, iteration of the entire container is often times slow using this layout as each bucket must be examined for occupancy, yielding a time complexity of `O(bucket_count() + size())` when the standard requires complexity to be `O(size())`.
Canonical standard implementations will wind up looking like the diagram below:
[.text-center]
.The canonical standard approach
image::singly-linked.png[align=center,link=../diagrams/singly-linked.png,window=_blank]
It's worth noting that this approach is only used by pass:[libc++] and pass:[libstdc++]; the MSVC Dinkumware implementation uses a different one. A more detailed analysis of the standard containers can be found http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html[here].
This unusually laid out data structure is chosen to make iteration of the entire container efficient by inter-connecting all of the nodes into a singly-linked list. One might also notice that buckets point to the node _before_ the start of the bucket's elements. This is done so that removing elements from the list can be done efficiently without introducing the need for a doubly-linked list. Unfortunately, this data structure introduces a guaranteed extra indirection. For example, to access the first element of a bucket, something like this must be done:
```c++
auto const idx = get_bucket_idx(hash_function(key));
node* p = buckets[idx]; // first load
node* n = p->next; // second load
if (n && is_in_bucket(n, idx)) {
value_type const& v = *n; // third load
// ...
}
```
With a simple bucket group layout, this is all that must be done:
```c++
auto const idx = get_bucket_idx(hash_function(key));
node* n = buckets[idx]; // first load
if (n) {
value_type const& v = *n; // second load
// ...
}
```
In practice, the extra indirection can have a dramatic performance impact to common operations such as `insert`, `find` and `erase`. But to keep iteration of the container fast, Boost.Unordered introduces a novel data structure, a "bucket group". A bucket group is a fixed-width view of a subsection of the buckets array. It contains a bitmask (a `std::size_t`) which it uses to track occupancy of buckets and contains two pointers so that it can form a doubly-linked list with non-empty groups. An example diagram is below:
[#img-fca-layout]
.The new layout used by Boost
image::fca.png[align=center]
Thus container-wide iteration is turned into traversing the non-empty bucket groups (an operation with constant time complexity) which reduces the time complexity back to `O(size())`. In total, a bucket group is only 4 words in size and it views `sizeof(std::size_t) * CHAR_BIT` buckets meaning that for all common implementations, there's only 4 bits of space overhead per bucket introduced by the bucket groups.
A more detailed description of Boost.Unordered's closed-addressing implementation is
given in an
https://bannalia.blogspot.com/2022/06/advancing-state-of-art-for.html[external article].
For more information on implementation rationale, read the
xref:#rationale_boostunordered_multiset_and_boostunordered_multimap[corresponding section].
== Open Addressing Implementation
The diagram shows the basic internal layout of `boost::unordered_flat_map` and
`boost:unordered_flat_set`.
[#img-foa-layout]
.Open-addressing layout used by Boost.Unordered.
image::foa.png[align=center]
As with all open-addressing containers, elements are stored directly in the bucket array.
This array is logically divided into 2^_n_^ _groups_ of 15 elements each.
In addition to the bucket array, there is an associated _metadata array_ with 2^_n_^
16-byte words.
[#img-foa-metadata]
.Breakdown of a metadata word.
image::foa-metadata.png[align=center]
A metadata word is divided into 15 _h_~_i_~ bytes (one for each associated
bucket), and an _overflow byte_ (_ofw_ in the diagram). The value of _h_~_i_~ is:
- 0 if the corresponding bucket is empty.
- 1 to encode a special empty bucket called a _sentinel_, which is used internally to
stop iteration when the container has been fully traversed.
- If the bucket is occupied, a _reduced hash value_ obtained from the hash value of
the element.
When looking for an element with hash value _h_, SIMD technologies such as
https://en.wikipedia.org/wiki/SSE2[SSE2] and
https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(Neon)[Neon] allow us
to very quickly inspect the full metadata word and look for the reduced value of _h_ among all the
15 buckets with just a handful of CPU instructions: non-matching buckets can be
readily discarded, and those whose reduced hash value matches need be inspected via full
comparison with the corresponding element. If the looked-for element is not present,
the overflow byte is inspected:
- If the bit in the position _h_ mod 8 is zero, lookup terminates (and the
element is not present).
- If the bit is set to 1 (the group has been _overflowed_), further groups are
checked using https://en.wikipedia.org/wiki/Quadratic_probing[_quadratic probing_], and
the process is repeated.
Insertion is algorithmically similar: empty buckets are located using SIMD,
and when going past a full group its corresponding overflow bit is set to 1.
In architectures without SIMD support, the logical layout stays the same, but the metadata
word is codified using a technique we call _bit interleaving_: this layout allows us
to emulate SIMD with reasonably good performance using only standard arithmetic and
logical operations.
[#img-foa-metadata-interleaving]
.Bit-interleaved metadata word.
image::foa-metadata-interleaving.png[align=center]
A more detailed description of Boost.Unordered's open-addressing implementation is
given in an
https://bannalia.blogspot.com/2022/11/inside-boostunorderedflatmap.html[external article].
For more information on implementation rationale, read the
xref:#rationale_boostunordered_flat_set_and_boostunordered_flat_map[corresponding section].
+16 -2
View File
@@ -6,10 +6,24 @@
:github-pr-url: https://github.com/boostorg/unordered/pull
:cpp: C++
== Release 1.82.0
== Release 1.83.0 - Major update
* Added `boost::concurrent_flat_map`, a fast, thread-safe hashmap based on open addressing.
* Sped up iteration of open-addressing containers.
== Release 1.82.0 - Major update
* {cpp}03 support is planned for deprecation. Boost 1.84.0 will no longer support
{cpp}03 mode and {cpp}11 will become the new minimum for using the library.
* Added node-based, open-addressing containers
`boost::unordered_node_map` and `boost::unordered_node_set`.
* Extended heterogeneous lookup to more member functions as specified in
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p2363r3.html[P2363].
https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2363r5.html[P2363].
* Replaced the previous post-mixing process for open-addressing containers with
a new algorithm based on extended multiplication by a constant.
* Fixed bug in internal emplace() impl where stack-local types were not properly
constructed using the Allocator of the container which breaks uses-allocator
construction.
== Release 1.81.0 - Major update
+79 -18
View File
@@ -5,15 +5,15 @@
:cpp: C++
== Closed-addressing containers: unordered_[multi]set, unordered_[multi]map
== Closed-addressing Containers
The intent of Boost.Unordered is to provide a conformant
`unordered_[multi]set` and `unordered_[multi]map` are intended to provide a conformant
implementation of the {cpp}20 standard that will work with {cpp}98 upwards.
This wide compatibility does mean some compromises have to be made.
With a compiler and library that fully support {cpp}11, the differences should
be minor.
=== 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,
@@ -25,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
@@ -58,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:
@@ -117,27 +117,88 @@ 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
== Open-addressing Containers
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
specification to adhere to, so `boost::unordered_flat_set`/`unordered_node_set` and
`boost::unordered_flat_map`/`unordered_node_map` take inspiration from `std::unordered_set` and
`std::unordered_map`, respectively, and depart from their interface where
convenient or as dictated by their internal data structure, which is
radically different from that imposed by the standard (closed addressing, node based).
radically different from that imposed by the standard (closed addressing).
`unordered_flat_set` and `unordered_flat_map` only work with reasonably
Open-addressing containers provided by Boost.Unordered only work with reasonably
compliant C++11 (or later) compilers. Language-level features such as move semantics
and variadic template parameters are then not emulated.
`unordered_flat_set` and `unordered_flat_map` are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^].
The containers are fully https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^].
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.
* In general:
** `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`).
** The maximum load factor of the container is managed internally and can't be set by the user. The maximum load,
exposed through the public function `max_load`, may decrease on erasure under high-load conditions.
* Flat containers (`boost::unordered_flat_set` and `boost::unordered_flat_map`):
** `value_type` must be move-constructible.
** Pointer stability is not kept under rehashing.
** There is no API for node extraction/insertion.
== Concurrent Containers
There is currently no specification in the C++ standard for this or any other concurrent
data structure. `boost::concurrent_flat_map` takes the same template parameters as `std::unordered_map`
and all the maps provided by Boost.Unordered, and its API is modelled after that of
`boost::unordered_flat_map` with the crucial difference that iterators are not provided
due to their inherent problems in concurrent scenarios (high contention, prone to deadlocking):
so, `boost::concurrent_flat_map` is technically not a
https://en.cppreference.com/w/cpp/named_req/Container[Container^], although
it meets all the requirements of https://en.cppreference.com/w/cpp/named_req/AllocatorAwareContainer[AllocatorAware^]
containers except those implying iterators.
In a non-concurrent unordered container, iterators serve two main purposes:
* Access to an element previously located via lookup.
* Container traversal.
In place of iterators, `boost::concurrent_flat_map` uses _internal visitation_
facilities as a thread-safe substitute. Classical operations returning an iterator to an
element already existing in the container, like for instance:
[source,c++]
----
iterator find(const key_type& k);
std::pair<iterator, bool> insert(const value_type& obj);
----
are transformed to accept a _visitation function_ that is passed such element:
[source,c++]
----
template<class F> size_t visit(const key_type& k, F f);
template<class F> bool insert_or_visit(const value_type& obj, F f);
----
(In the second case `f` is only invoked if there's an equivalent element
to `obj` in the table, not if insertion is successful). Container traversal
is served by:
[source,c++]
----
template<class F> size_t visit_all(F f);
----
of which there are parallelized versions in C++17 compilers with parallel
algorithm support. In general, the interface of `boost::concurrent_flat_map`
is derived from that of `boost::unordered_flat_map` by a fairly straightforward
process of replacing iterators with visitation where applicable. If
`iterator` and `const_iterator` provide mutable and const access to elements,
respectively, here visitation is granted mutable or const access depending on
the constness of the member function used (there are also `*cvisit` overloads for
explicit const visitation).
The one notable operation not provided is `operator[]`/`at`, which can be
replaced, if in a more convoluted manner, by
xref:#concurrent_flat_map_try_emplace_or_cvisit[`try_emplace_or_visit`].
//-
+182
View File
@@ -0,0 +1,182 @@
[#concurrent]
= Concurrent Containers
:idprefix: concurrent_
Boost.Unordered currently provides just one concurrent container named `boost::concurrent_flat_map`.
`boost::concurrent_flat_map` is a hash table that allows concurrent write/read access from
different threads without having to implement any synchronzation mechanism on the user's side.
[source,c++]
----
std::vector<int> input;
boost::concurrent_flat_map<int,int> m;
...
// process input in parallel
const int num_threads = 8;
std::vector<std::jthread> threads;
std::size_t chunk = input.size() / num_threads; // how many elements per thread
for (int i = 0; i < num_threads; ++i) {
threads.emplace_back([&,i] {
// calculate the portion of input this thread takes care of
std::size_t start = i * chunk;
std::size_t end = (i == num_threads - 1)? input.size(): (i + 1) * chunk;
for (std::size_t n = start; n < end; ++n) {
m.emplace(input[n], calculation(input[n]));
}
});
}
----
In the example above, threads access `m` without synchronization, just as we'd do in a
single-threaded scenario. In an ideal setting, if a given workload is distributed among
_N_ threads, execution is _N_ times faster than with one thread —this limit is
never attained in practice due to synchronization overheads and _contention_ (one thread
waiting for another to leave a locked portion of the map), but `boost::concurrent_flat_map`
is designed to perform with very little overhead and typically achieves _linear scaling_
(that is, performance is proportional to the number of threads up to the number of
logical cores in the CPU).
== Visitation-based API
The first thing a new user of `boost::concurrent_flat_map` will notice is that this
class _does not provide iterators_ (which makes it technically
not a https://en.cppreference.com/w/cpp/named_req/Container[Container^]
in the C++ standard sense). The reason for this is that iterators are inherently
thread-unsafe. Consider this hypothetical code:
[source,c++]
----
auto it = m.find(k); // A: get an iterator pointing to the element with key k
if (it != m.end() ) {
some_function(*it); // B: use the value of the element
}
----
In a multithreaded scenario, the iterator `it` may be invalid at point B if some other
thread issues an `m.erase(k)` operation between A and B. There are designs that
can remedy this by making iterators lock the element they point to, but this
approach lends itself to high contention and can easily produce deadlocks in a program.
`operator[]` has similar concurrency issues, and is not provided by
`boost::concurrent_flat_map` either. Instead, element access is done through
so-called _visitation functions_:
[source,c++]
----
m.visit(k, [](const auto& x) { // x is the element with key k (if it exists)
some_function(x); // use it
});
----
The visitation function passed by the user (in this case, a lambda function)
is executed internally by `boost::concurrent_flat_map` in
a thread-safe manner, so it can access the element without worrying about other
threads interfering in the process.
On the other hand, a visitation function can _not_ access the container itself:
[source,c++]
----
m.visit(k, [&](const auto& x) {
some_function(x, m.size()); // forbidden: m can't be accessed inside visitation
});
----
Access to a different container is allowed, though:
[source,c++]
----
m.visit(k, [&](const auto& x) {
if (some_function(x)) {
m2.insert(x); // OK, m2 is a different boost::concurrent_flat_map
}
});
----
But, in general, visitation functions should be as lightweight as possible to
reduce contention and increase parallelization. In some cases, moving heavy work
outside of visitation may be beneficial:
[source,c++]
----
std::optional<value_type> o;
bool found = m.visit(k, [&](const auto& x) {
o = x;
});
if (found) {
some_heavy_duty_function(*o);
}
----
Visitation is prominent in the API provided by `boost::concurrent_flat_map`, and
many classical operations have visitation-enabled variations:
[source,c++]
----
m.insert_or_visit(x, [](auto& y) {
// if insertion failed because of an equivalent element y,
// do something with it, for instance:
++y.second; // increment the mapped part of the element
});
----
Note that in this last example the visitation function could actually _modify_
the element: as a general rule, operations on a `boost::concurrent_flat_map` `m`
will grant visitation functions const/non-const access to the element depending on whether
`m` is const/non-const. Const access can be always be explicitly requested
by using `cvisit` overloads (for instance, `insert_or_cvisit`) and may result
in higher parallelization. Consult the xref:#concurrent_flat_map[reference]
for a complete list of available operations.
== Whole-Table Visitation
In the absence of iterators, `boost::concurrent_flat_map` provides `visit_all`
as an alternative way to process all the elements in the map:
[source,c++]
----
m.visit_all([](auto& x) {
x.second = 0; // reset the mapped part of the element
});
----
In C++17 compilers implementing standard parallel algorithms, whole-table
visitation can be parallelized:
[source,c++]
----
m.visit_all(std::execution::par, [](auto& x) { // run in parallel
x.second = 0; // reset the mapped part of the element
});
----
There is another whole-table visitation operation, `erase_if`:
[source,c++]
----
m.erase_if([](auto& x) {
return x.second == 0; // erase the elements whose mapped value is zero
});
----
`erase_if` can also be parallelized. Note that, in order to increase efficiency,
these operations do not block the table during execution: this implies that elements
may be inserted, modified or erased by other threads during visitation. It is
advisable not to assume too much about the exact global state of a `boost::concurrent_flat_map`
at any point in your program.
== Blocking Operations
``boost::concurrent_flat_map``s can be copied, assigned, cleared and merged just like any
Boost.Unordered container. Unlike most other operations, these are _blocking_,
that is, all other threads are prevented from accesing the tables involved while a copy, assignment,
clear or merge operation is in progress. Blocking is taken care of automatically by the library
and the user need not take any special precaution, but overall performance may be affected.
Another blocking operation is _rehashing_, which happens explicitly via `rehash`/`reserve`
or during insertion when the table's load hits `max_load()`. As with non-concurrent containers,
reserving space in advance of bulk insertions will generally speed up the process.
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -9,10 +9,10 @@ Copyright (C) 2003, 2004 Jeremy B. Maitin-Shepard
Copyright (C) 2005-2008 Daniel James
Copyright (C) 2022 Christian Mazakas
Copyright (C) 2022-2023 Christian Mazakas
Copyright (C) 2022 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz
Copyright (C) 2022-2023 Joaqu&iacute;n M L&oacute;pez Mu&ntilde;oz
Copyright (C) 2022 Peter Dimov
Copyright (C) 2022-2023 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)
+3 -3
View File
@@ -20,14 +20,14 @@ class unordered_map;
The hash function comes first as you might want to change the hash function
but not the equality predicate. For example, if you wanted to use the
http://www.isthe.com/chongo/tech/comp/fnv/[FNV-1 hash^] you could write:
https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash[FNV-1a hash^] you could write:
```
boost::unordered_map<std::string, int, hash::fnv_1>
boost::unordered_map<std::string, int, hash::fnv_1a>
dictionary;
```
There is an link:../../examples/fnv1.hpp[implementation of FNV-1^] in the examples directory.
There is an link:../../examples/fnv1.hpp[implementation of FNV-1a^] in the examples directory.
If you wish to use a different equality function, you will also need to use a matching hash function. For example, to implement a case insensitive dictionary you need to define a case insensitive equality predicate and hash function:
+61 -121
View File
@@ -4,26 +4,65 @@
:idprefix: intro_
:cpp: C++
For accessing data based on key lookup, the {cpp} standard library offers `std::set`,
`std::map`, `std::multiset` and `std::multimap`. These are generally
implemented using balanced binary trees so that lookup time has
logarithmic complexity. That is generally okay, but in many cases a
link:https://en.wikipedia.org/wiki/Hash_table[hash table^] can perform better, as accessing data has constant complexity,
on average. The worst case complexity is linear, but that occurs rarely and
with some care, can be avoided.
link:https://en.wikipedia.org/wiki/Hash_table[Hash tables^] are extremely popular
computer data structures and can be found under one form or another in virtually any programming
language. Whereas other associative structures such as rb-trees (used in {cpp} by `std::set` and `std::map`)
have logarithmic-time complexity for insertion and lookup, hash tables, if configured properly,
perform these operations in constant time on average, and are generally much faster.
Also, the existing containers require a 'less than' comparison object
to order their elements. For some data types this is impossible to implement
or isn't practical. In contrast, a hash table only needs an equality function
and a hash function for the key.
{cpp} introduced __unordered associative containers__ `std::unordered_set`, `std::unordered_map`,
`std::unordered_multiset` and `std::unordered_multimap` in {cpp}11, but research on hash tables
hasn't stopped since: advances in CPU architectures such as
more powerful caches, link:https://en.wikipedia.org/wiki/Single_instruction,_multiple_data[SIMD] operations
and increasingly available link:https://en.wikipedia.org/wiki/Multi-core_processor[multicore processors]
open up possibilities for improved hash-based data structures and new use cases that
are simply beyond reach of unordered associative containers as specified in 2011.
With this in mind, unordered associative containers were added to the {cpp}
standard. Boost.Unordered provides an implementation of the containers described in {cpp}11,
with some <<compliance,deviations from the standard>> in
order to work with non-{cpp}11 compilers and libraries.
Boost.Unordered offers a catalog of hash containers with different standards compliance levels,
performances and intented usage scenarios:
[caption=, title='Table {counter:table-counter}. Boost.Unordered containers']
[cols="1,1,.^1", frame=all, grid=all]
|===
^h|
^h|*Node-based*
^h|*Flat*
^.^h|*Closed addressing*
^m|
boost::unordered_set +
boost::unordered_map +
boost::unordered_multiset +
boost::unordered_multimap
^|
^.^h|*Open addressing*
^m| boost::unordered_node_set +
boost::unordered_node_map
^m| boost::unordered_flat_set +
boost::unordered_flat_map
^.^h|*Concurrent*
^|
^| `boost::concurrent_flat_map`
|===
* **Closed-addressing containers** are fully compliant with the C++ specification
for unordered associative containers and feature one of the fastest implementations
in the market within the technical constraints imposed by the required standard interface.
* **Open-addressing containers** rely on much faster data structures and algorithms
(more than 2 times faster in typical scenarios) while slightly diverging from the standard
interface to accommodate the implementation.
There are two variants: **flat** (the fastest) and **node-based**, which
provide pointer stability under rehashing at the expense of being slower.
* Finally, `boost::concurrent_flat_map` (the only **concurrent container** provided
at present) is a hashmap designed and implemented to be used in high-performance
multithreaded scenarios. Its interface is radically different from that of regular C++ containers.
All sets and maps in Boost.Unordered are instantiatied similarly as
`std::unordered_set` and `std::unordered_map`, respectively:
`unordered_set` and `unordered_multiset` are defined in the header
`<boost/unordered/unordered_set.hpp>`
[source,c++]
----
namespace boost {
@@ -32,117 +71,21 @@ namespace boost {
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class unordered_set;
class unordered_set;
// same for unordered_multiset, unordered_flat_set, unordered_node_set
template<
class Key,
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class unordered_multiset;
}
----
`unordered_map` and `unordered_multimap` are defined in the header
`<boost/unordered/unordered_map.hpp>`
[source,c++]
----
namespace boost {
template <
class Key, class Mapped,
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
class unordered_map;
template<
class Key, class Mapped,
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
class unordered_multimap;
// same for unordered_multimap, unordered_flat_map, unordered_node_map
// and concurrent_flat_map
}
----
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):
[source,c++]
----
// #include <boost/unordered/unordered_flat_set.hpp>
//
// Note: no multiset version
namespace boost {
template <
class Key,
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<Key> >
class unordered_flat_set;
}
----
[source,c++]
----
// #include <boost/unordered/unordered_flat_map.hpp>
//
// Note: no multimap version
namespace boost {
template <
class Key, class Mapped,
class Hash = boost::hash<Key>,
class Pred = std::equal_to<Key>,
class Alloc = std::allocator<std::pair<Key const, Mapped> > >
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]
----
typedef boost::unordered_map<std::string, int> map;
map x;
x["one"] = 1;
x["two"] = 2;
x["three"] = 3;
assert(x.at("one") == 1);
assert(x.find("missing") == x.end());
----
But since the elements aren't ordered, the output of:
[source,c++]
----
for(const map::value_type& i: x) {
std::cout<<i.first<<","<<i.second<<"\n";
}
----
can be in any order. For example, it might be:
[source]
----
two,2
one,1
three,3
----
To store an object in an unordered associative container requires both a
Storing an object in an unordered associative container requires both a
key equality function and a hash function. The default function objects in
the standard containers support a few basic types including integer types,
floating point types, pointer types, and the standard strings. Since
@@ -152,6 +95,3 @@ you have to extend Boost.Hash to support the type or use
your own custom equality predicates and hash functions. See the
<<hash_equality,Equality Predicates and Hash Functions>> section
for more details.
There are other differences, which are listed in the
<<comparison,Comparison with Associative Containers>> section.
+41 -15
View File
@@ -4,9 +4,10 @@
= Implementation Rationale
== boost::unordered_[multi]set and boost::unordered_[multi]map
== Closed-addressing Containers
These containers adhere to the standard requirements for unordered associative
`boost::unordered_[multi]set` and `boost::unordered_[multi]map`
adhere to the standard requirements for unordered associative
containers, so the interface was fixed. But there are
still some implementation decisions to make. The priorities are
conformance to the standard and portability.
@@ -64,8 +65,8 @@ of bits in the hash value, so it was only used when `size_t` was 64 bit.
Since release 1.79.0, https://en.wikipedia.org/wiki/Hash_function#Fibonacci_hashing[Fibonacci hashing]
is used instead. With this implementation, the bucket number is determined
by using `(h * m) >> (w - k)`, where `h` is the hash value, `m` is the golden
ratio multiplied by `2^w`, `w` is the word size (32 or 64), and `2^k` is the
by using `(h * m) >> (w - k)`, where `h` is the hash value, `m` is `2^w` divided
by the golden ratio, `w` is the word size (32 or 64), and `2^k` is the
number of buckets. This provides a good compromise between speed and
distribution.
@@ -73,7 +74,7 @@ Since release 1.80.0, prime numbers are chosen for the number of buckets in
tandem with sophisticated modulo arithmetic. This removes the need for "mixing"
the result of the user's hash function as was used for release 1.79.0.
== boost::unordered_flat_set and boost::unordered_flat_map
== Open-addresing Containers
The C++ standard specification of unordered associative containers impose
severe limitations on permissible implementations, the most important being
@@ -81,30 +82,33 @@ that closed addressing is implicitly assumed. Slightly relaxing this specificati
opens up the possibility of providing container variations taking full
advantage of open-addressing techniques.
The design of `boost::unordered_flat_set` and `boost::unordered_flat_map` has been
The design of `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` has been
guided by Peter Dimov's https://pdimov.github.io/articles/unordered_dev_plan.html[Development Plan for Boost.Unordered^].
We discuss here the most relevant principles.
=== Hash function
=== Hash Function
Given its rich functionality and cross-platform interoperability,
`boost::hash` remains the default hash function of `boost::unordered_flat_set` and `boost::unordered_flat_map`.
`boost::hash` remains the default hash function of open-addressing containers.
As it happens, `boost::hash` for integral and other basic types does not possess
the statistical properties required by open addressing; to cope with this,
we implement a post-mixing stage:
* 64-bit architectures: we use the `xmx` function defined in
Jon Maiga's http://jonkagstrom.com/bit-mixer-construction/index.html[The construct of a bit mixer^].
* 32-bit architectures: the mixer used was selected from a set generated with https://github.com/skeeto/hash-prospector[Hash Function Prospector^]
as the best overall performer in our internal benchmarks. Score assigned by Hash Prospector is 333.7934929677524.
{nbsp}{nbsp}{nbsp}{nbsp} _a_ <- _h_ *mulx* _C_, +
{nbsp}{nbsp}{nbsp}{nbsp} _h_ <- *high*(_a_) *xor* *low*(_a_),
where *mulx* is an _extended multiplication_ (128 bits in 64-bit architectures, 64 bits in 32-bit environments),
and *high* and *low* are the upper and lower halves of an extended word, respectively.
In 64-bit architectures, _C_ is the integer part of 2^64^&#8725;https://en.wikipedia.org/wiki/Golden_ratio[_&phi;_],
whereas in 32 bits _C_ = 0xE817FB2Du has been obtained from https://arxiv.org/abs/2001.05304[Steele and Vigna (2021)^].
When using a hash function directly suitable for open addressing, post-mixing can be opted out by via a dedicated <<hash_traits_hash_is_avalanching,`hash_is_avalanching`>>trait.
`boost::hash` specializations for string types are marked as avalanching.
=== Platform interoperability
=== 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
The observable behavior of `boost::unordered_flat_set`/`unordered_node_set` and `boost::unordered_flat_map`/`unordered_node_map` is deterministically
identical across different compilers as long as their ``std::size_t``s are the same size and the user-provided
hash function and equality predicate are also interoperable
&#8212;this includes elements being ordered in exactly the same way for the same sequence of
operations.
@@ -113,3 +117,25 @@ Although the implementation internally uses SIMD technologies, such as https://e
and https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(NEON)[Neon^], when available,
this does not affect interoperatility. For instance, the behavior is the same
for Visual Studio on an x64-mode Intel CPU with SSE2 and for GCC on an IBM s390x without any supported SIMD technology.
== Concurrent Containers
The same data structure used by Boost.Unordered open-addressing containers has been chosen
also as the foundation of `boost::concurrent_flat_map`:
* Open-addressing is faster than closed-addressing alternatives, both in non-concurrent and
concurrent scenarios.
* Open-addressing layouts are eminently suitable for concurrent access and modification
with minimal locking. In particular, the metadata array can be used for implementations of
lookup that are lock-free up to the last step of actual element comparison.
* Layout compatibility with Boost.Unordered flat containers allows for fast transfer
of all elements between `boost::concurrent_flat_map` and `boost::unordered_flat_map`.
(This feature has not been implemented yet.)
=== Hash Function and Platform Interoperability
`boost::concurrent_flat_map` makes the same decisions and provides the same guarantees
as Boost.Unordered open-addressing containers with regards to
xref:#rationale_hash_function[hash function defaults] and
xref:#rationale_platform_interoperability[platform interoperability].
+3
View File
@@ -8,3 +8,6 @@ include::unordered_multiset.adoc[]
include::hash_traits.adoc[]
include::unordered_flat_map.adoc[]
include::unordered_flat_set.adoc[]
include::unordered_node_map.adoc[]
include::unordered_node_set.adoc[]
include::concurrent_flat_map.adoc[]
@@ -1,8 +1,99 @@
[#regular]
= Regular Containers
:idprefix: regular_
Boost.Unordered closed-addressing containers (`boost::unordered_set`, `boost::unordered_map`,
`boost::unordered_multiset` and `boost::unordered_multimap`) are fully conformant with the
C++ specification for unordered associative containers, so for those who know how to use
`std::unordered_set`, `std::unordered_map`, etc., their homonyms in Boost.Unordered are
drop-in replacements. The interface of open-addressing containers (`boost::unordered_node_set`,
`boost::unordered_node_map`, `boost::unordered_flat_set` and `boost::unordered_flat_map`)
is very similar, but they present some minor differences listed in the dedicated
xref:#compliance_open_addressing_containers[standard compliance section].
For readers without previous experience with hash containers but familiar
with normal associative containers (`std::set`, `std::map`,
`std::multiset` and `std::multimap`), Boost.Unordered containers are used in a similar manner:
[source,cpp]
----
typedef boost::unordered_map<std::string, int> map;
map x;
x["one"] = 1;
x["two"] = 2;
x["three"] = 3;
assert(x.at("one") == 1);
assert(x.find("missing") == x.end());
----
But since the elements aren't ordered, the output of:
[source,c++]
----
for(const map::value_type& i: x) {
std::cout<<i.first<<","<<i.second<<"\n";
}
----
can be in any order. For example, it might be:
[source]
----
two,2
one,1
three,3
----
There are other differences, which are listed in the
<<comparison,Comparison with Associative Containers>> section.
== Iterator Invalidation
It is not specified how member functions other than `rehash` and `reserve` affect
the bucket count, although `insert` can only invalidate iterators
when the insertion causes the container's load to be greater than the maximum allowed.
For most implementations this means that `insert` will only
change the number of buckets when this happens. Iterators can be
invalidated by calls to `insert`, `rehash` and `reserve`.
As for pointers and references,
they are never invalidated for node-based containers
(`boost::unordered_[multi]set`, `boost::unordered_[multi]map`, `boost::unordered_node_set`, `boost::unordered_node_map`),
but they will be when rehashing occurs for
`boost::unordered_flat_set` and `boost::unordered_flat_map`: this is because
these containers store elements directly into their holding buckets, so
when allocating a new bucket array the elements must be transferred by means of move construction.
In a similar manner to using `reserve` for ``vector``s, it can be a good idea
to call `reserve` before inserting a large number of elements. This will get
the expensive rehashing out of the way and let you store iterators, safe in
the knowledge that they won't be invalidated. If you are inserting `n`
elements into container `x`, you could first call:
```
x.reserve(n);
```
Note:: `reserve(n)` reserves space for at least `n` elements, allocating enough buckets
so as to not exceed the maximum load factor.
+
Because the maximum load factor is defined as the number of elements divided by the total
number of available buckets, this function is logically equivalent to:
+
```
x.rehash(std::ceil(n / x.max_load_factor()))
```
+
See the <<unordered_map_rehash,reference for more details>> on the `rehash` function.
[#comparison]
:idprefix: comparison_
= Comparison with Associative Containers
== Comparison with Associative Containers
[caption=, title='Table {counter:table-counter} Interface differences']
[cols="1,1", frame=all, grid=rows]
@@ -32,9 +123,9 @@
|`iterator`, `const_iterator` are of at least the forward category.
|Iterators, pointers and references to the container's elements are never invalidated.
|<<buckets_iterator_invalidation,Iterators can be invalidated by calls to insert or rehash>>. +
**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.
|<<regular_iterator_invalidation,Iterators can be invalidated by calls to insert or rehash>>. +
**Node-based containers:** Pointers and references to the container's elements are never invalidated. +
**Flat containers:** Pointers and references to the container's elements are invalidated when rehashing occurs.
|Iterators iterate through the container in the order defined by the comparison object.
|Iterators iterate through the container in an arbitrary order, that can change as elements are inserted, although equivalent elements are always adjacent.
+179
View File
@@ -0,0 +1,179 @@
[#structures]
= Data Structures
:idprefix: structures_
== Closed-addressing Containers
++++
<style>
.imageblock > .title {
text-align: inherit;
}
</style>
++++
Boost.Unordered sports one of the fastest implementations of closed addressing, also commonly known as https://en.wikipedia.org/wiki/Hash_table#Separate_chaining[separate chaining]. An example figure representing the data structure is below:
[#img-bucket-groups,.text-center]
.A simple bucket group approach
image::bucket-groups.png[align=center]
An array of "buckets" is allocated and each bucket in turn points to its own individual linked list. This makes meeting the standard requirements of bucket iteration straight-forward. Unfortunately, iteration of the entire container is often times slow using this layout as each bucket must be examined for occupancy, yielding a time complexity of `O(bucket_count() + size())` when the standard requires complexity to be `O(size())`.
Canonical standard implementations will wind up looking like the diagram below:
[.text-center]
.The canonical standard approach
image::singly-linked.png[align=center,link=../diagrams/singly-linked.png,window=_blank]
It's worth noting that this approach is only used by pass:[libc++] and pass:[libstdc++]; the MSVC Dinkumware implementation uses a different one. A more detailed analysis of the standard containers can be found http://bannalia.blogspot.com/2013/10/implementation-of-c-unordered.html[here].
This unusually laid out data structure is chosen to make iteration of the entire container efficient by inter-connecting all of the nodes into a singly-linked list. One might also notice that buckets point to the node _before_ the start of the bucket's elements. This is done so that removing elements from the list can be done efficiently without introducing the need for a doubly-linked list. Unfortunately, this data structure introduces a guaranteed extra indirection. For example, to access the first element of a bucket, something like this must be done:
```c++
auto const idx = get_bucket_idx(hash_function(key));
node* p = buckets[idx]; // first load
node* n = p->next; // second load
if (n && is_in_bucket(n, idx)) {
value_type const& v = *n; // third load
// ...
}
```
With a simple bucket group layout, this is all that must be done:
```c++
auto const idx = get_bucket_idx(hash_function(key));
node* n = buckets[idx]; // first load
if (n) {
value_type const& v = *n; // second load
// ...
}
```
In practice, the extra indirection can have a dramatic performance impact to common operations such as `insert`, `find` and `erase`. But to keep iteration of the container fast, Boost.Unordered introduces a novel data structure, a "bucket group". A bucket group is a fixed-width view of a subsection of the buckets array. It contains a bitmask (a `std::size_t`) which it uses to track occupancy of buckets and contains two pointers so that it can form a doubly-linked list with non-empty groups. An example diagram is below:
[#img-fca-layout]
.The new layout used by Boost
image::fca.png[align=center]
Thus container-wide iteration is turned into traversing the non-empty bucket groups (an operation with constant time complexity) which reduces the time complexity back to `O(size())`. In total, a bucket group is only 4 words in size and it views `sizeof(std::size_t) * CHAR_BIT` buckets meaning that for all common implementations, there's only 4 bits of space overhead per bucket introduced by the bucket groups.
A more detailed description of Boost.Unordered's closed-addressing implementation is
given in an
https://bannalia.blogspot.com/2022/06/advancing-state-of-art-for.html[external article].
For more information on implementation rationale, read the
xref:#rationale_closed_addressing_containers[corresponding section].
== Open-addressing Containers
The diagram shows the basic internal layout of `boost::unordered_flat_map`/`unordered_node_map` and
`boost:unordered_flat_set`/`unordered_node_set`.
[#img-foa-layout]
.Open-addressing layout used by Boost.Unordered.
image::foa.png[align=center]
As with all open-addressing containers, elements (or pointers to the element nodes in the case of
`boost::unordered_node_map` and `boost::unordered_node_set`) are stored directly in the bucket array.
This array is logically divided into 2^_n_^ _groups_ of 15 elements each.
In addition to the bucket array, there is an associated _metadata array_ with 2^_n_^
16-byte words.
[#img-foa-metadata]
.Breakdown of a metadata word.
image::foa-metadata.png[align=center]
A metadata word is divided into 15 _h_~_i_~ bytes (one for each associated
bucket), and an _overflow byte_ (_ofw_ in the diagram). The value of _h_~_i_~ is:
- 0 if the corresponding bucket is empty.
- 1 to encode a special empty bucket called a _sentinel_, which is used internally to
stop iteration when the container has been fully traversed.
- If the bucket is occupied, a _reduced hash value_ obtained from the hash value of
the element.
When looking for an element with hash value _h_, SIMD technologies such as
https://en.wikipedia.org/wiki/SSE2[SSE2] and
https://en.wikipedia.org/wiki/ARM_architecture_family#Advanced_SIMD_(Neon)[Neon] allow us
to very quickly inspect the full metadata word and look for the reduced value of _h_ among all the
15 buckets with just a handful of CPU instructions: non-matching buckets can be
readily discarded, and those whose reduced hash value matches need be inspected via full
comparison with the corresponding element. If the looked-for element is not present,
the overflow byte is inspected:
- If the bit in the position _h_ mod 8 is zero, lookup terminates (and the
element is not present).
- If the bit is set to 1 (the group has been _overflowed_), further groups are
checked using https://en.wikipedia.org/wiki/Quadratic_probing[_quadratic probing_], and
the process is repeated.
Insertion is algorithmically similar: empty buckets are located using SIMD,
and when going past a full group its corresponding overflow bit is set to 1.
In architectures without SIMD support, the logical layout stays the same, but the metadata
word is codified using a technique we call _bit interleaving_: this layout allows us
to emulate SIMD with reasonably good performance using only standard arithmetic and
logical operations.
[#img-foa-metadata-interleaving]
.Bit-interleaved metadata word.
image::foa-metadata-interleaving.png[align=center]
A more detailed description of Boost.Unordered's open-addressing implementation is
given in an
https://bannalia.blogspot.com/2022/11/inside-boostunorderedflatmap.html[external article].
For more information on implementation rationale, read the
xref:#rationale_open_addresing_containers[corresponding section].
== Concurrent Containers
`boost::concurrent_flat_map` uses the basic
xref:#structures_open_addressing_containers[open-addressing layout] described above
augmented with synchronization mechanisms.
[#img-cfoa-layout]
.Concurrent open-addressing layout used by Boost.Unordered.
image::cfoa.png[align=center]
Two levels of synchronization are used:
* Container level: A read-write mutex is used to control access from any operation
to the container. Typically, such access is in read mode (that is, concurrent) even
for modifying operations, so for most practical purposes there is no thread
contention at this level. Access is only in write mode (blocking) when rehashing or
performing container-wide operations such as swapping or assignment.
* Group level: Each 15-slot group is equipped with an 8-byte word containing:
** A read-write spinlock for synchronized access to any element in the group.
** An atomic _insertion counter_ used for optimistic insertion as described
below.
By using atomic operations to access the group metadata, lookup is (group-level)
lock-free up to the point where an actual comparison needs to be done with an element
that has been previously SIMD-matched: only then it's the group's spinlock used.
Insertion uses the following _optimistic algorithm_:
* The value of the insertion counter for the initial group in the probe
sequence is locally recorded (let's call this value `c0`).
* Lookup is as described above. If lookup finds no equivalent element,
search for an available slot for insertion successively locks/unlocks
each group in the probing sequence.
* When an available slot is located, it is preemptively occupied (its
reduced hash value is set) and the insertion counter is atomically
incremented: if no other thread has incremented the counter during the
whole operation (which is checked by comparing with `c0`), then we're
good to go and complete the insertion, otherwise we roll back and start
over.
This algorithm has very low contention both at the lookup and actual
insertion phases in exchange for the possibility that computations have
to be started over if some other thread interferes in the process by
performing a succesful insertion beginning at the same group. In
practice, the start-over frequency is extremely small, measured in the range
of parts per million for some of our benchmarks.
For more information on implementation rationale, read the
xref:#rationale_concurrent_containers[corresponding section].
+11 -10
View File
@@ -1,5 +1,5 @@
[#unordered_flat_map]
== Class template unordered_flat_map
== Class Template unordered_flat_map
:idprefix: unordered_flat_map_
@@ -280,6 +280,7 @@ namespace boost {
unordered_flat_map<Key, T, Hash, Pred, Alloc>& y)
noexcept(noexcept(x.swap(y)));
// Erasure
template<class K, class T, class H, class P, class A, class Predicate>
typename unordered_flat_map<K, T, H, P, A>::size_type
xref:#unordered_flat_map_erase_if[erase_if](unordered_flat_map<K, T, H, P, A>& c, Predicate pred);
@@ -859,7 +860,7 @@ void insert(std::initializer_list<value_type>);
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`.
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load.
@@ -875,7 +876,7 @@ template<class K, class... Args>
std::pair<iterator, bool> try_emplace(K&& k, Args&&... args);
```
Inserts a new node into the container if there is no existing element with key `k` contained within it.
Inserts a new element into the container if there is no existing element with key `k` contained within it.
If there is an existing element with key `k` this function does nothing.
@@ -904,7 +905,7 @@ unlike xref:#unordered_flat_map_emplace[emplace], which simply forwards all argu
Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load.
The `template <class K, class... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
The `template<class K, class\... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
--
@@ -920,7 +921,7 @@ template<class K, class... Args>
iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
```
Inserts a new node into the container if there is no existing element with key `k` contained within it.
Inserts a new element into the container if there is no existing element with key `k` contained within it.
If there is an existing element with key `k` this function does nothing.
@@ -949,7 +950,7 @@ unlike xref:#unordered_flat_map_emplace_hint[emplace_hint], which simply forward
Can invalidate iterators pointers and references, but only if the insert causes the load to be greater than the maximum load.
The `template <class K, class... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
The `template<class K, class\... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
--
@@ -1160,7 +1161,7 @@ template<class K>
[horizontal]
Returns:;; An iterator pointing to an element with key equivalent to `k`, or `end()` if no such element exists.
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1173,7 +1174,7 @@ template<class K>
[horizontal]
Returns:;; The number of elements with key equivalent to `k`.
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1186,7 +1187,7 @@ template<class K>
[horizontal]
Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1202,7 +1203,7 @@ template<class K>
[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 <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
+7 -6
View File
@@ -1,5 +1,5 @@
[#unordered_flat_set]
== Class template unordered_flat_set
== Class Template unordered_flat_set
:idprefix: unordered_flat_set_
@@ -234,6 +234,7 @@ namespace boost {
unordered_flat_set<Key, T, Hash, Pred, Alloc>& y)
noexcept(noexcept(x.swap(y)));
// Erasure
template<class K, class T, class H, class P, class A, class Predicate>
typename unordered_flat_set<K, T, H, P, A>::size_type
xref:#unordered_flat_set_erase_if[erase_if](unordered_flat_set<K, T, H, P, A>& c, Predicate pred);
@@ -837,7 +838,7 @@ void insert(std::initializer_list<value_type>);
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`.
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, pointers and references, but only if the insert causes the load to be greater than the maximum load.
@@ -971,7 +972,7 @@ template<class K>
[horizontal]
Returns:;; An iterator pointing to an element with key equivalent to `k`, or `end()` if no such element exists.
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -984,7 +985,7 @@ template<class K>
[horizontal]
Returns:;; The number of elements with key equivalent to `k`.
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -997,7 +998,7 @@ template<class K>
[horizontal]
Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1013,7 +1014,7 @@ template<class K>
[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 <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
+12 -11
View File
@@ -1,5 +1,5 @@
[#unordered_map]
== Class template unordered_map
== Class Template unordered_map
:idprefix: unordered_map_
@@ -286,6 +286,7 @@ namespace boost {
unordered_map<Key, T, Hash, Pred, Alloc>& y)
noexcept(noexcept(x.swap(y)));
// Erasure
template<class K, class T, class H, class P, class A, class Predicate>
typename unordered_map<K, T, H, P, A>::size_type
xref:#unordered_map_erase_if[erase_if](unordered_map<K, T, H, P, A>& c, Predicate pred);
@@ -995,7 +996,7 @@ void insert(std::initializer_list<value_type>);
Inserts a range of elements into the container. Elements are inserted if and only if there is no element in the container with an equivalent key.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `*first`.
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
+
@@ -1009,11 +1010,11 @@ template<class... Args>
std::pair<iterator, bool> try_emplace(const key_type& k, Args&&... args);
template<class... Args>
std::pair<iterator, bool> try_emplace(key_type&& k, Args&&... args);
template <class K, class... Args>
template<class K, class... Args>
std::pair<iterator, bool> try_emplace(K&& k, Args&&... args)
```
Inserts a new node into the container if there is no existing element with key `k` contained within it.
Inserts a new element into the container if there is no existing element with key `k` contained within it.
If there is an existing element with key `k` this function does nothing.
@@ -1043,7 +1044,7 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr
Pointers and references to elements are never invalidated.
The `template <class K, class... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
The `template<class K, class\... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics.
@@ -1062,7 +1063,7 @@ template<class K, class... Args>
iterator try_emplace(const_iterator hint, K&& k, Args&&... args);
```
Inserts a new node into the container if there is no existing element with key `k` contained within it.
Inserts a new element into the container if there is no existing element with key `k` contained within it.
If there is an existing element with key `k` this function does nothing.
@@ -1094,7 +1095,7 @@ Can invalidate iterators, but only if the insert causes the load factor to be gr
Pointers and references to elements are never invalidated.
The `template <class K, class... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
The `template<class K, class\... Args>` overload only participates in overload resolution if `Hash::is_transparent` and `Pred::is_transparent` are valid member typedefs and neither `iterator` nor `const_iterator` are implicitly convertible from `K`. The library assumes that `Hash` is callable with both `K` and `Key` and that `Pred` is transparent. This enables heterogeneous lookup which avoids the cost of instantiating an instance of the `Key` type.
If the compiler doesn't support variadic template arguments or rvalue references, this is emulated for up to `10` arguments, with no support for rvalue references or move semantics.
@@ -1466,7 +1467,7 @@ template<typename CompatibleKey, typename CompatibleHash, typename CompatiblePre
Returns:;; An iterator pointing to an element with key equivalent to `k`, or `b.end()` if no such element exists.
Notes:;; The templated overloads containing `CompatibleKey`, `CompatibleHash` and `CompatiblePredicate` are non-standard extensions which allow you to use a compatible hash function and equality predicate for a key of a different type in order to avoid an expensive type cast. In general, its use is not encouraged and instead the `K` member function templates should be used. +
+
The `template <typename K>` 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.
The `template<class K>` 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.
---
@@ -1479,7 +1480,7 @@ template<class K>
[horizontal]
Returns:;; The number of elements with key equivalent to `k`.
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1492,7 +1493,7 @@ template<class K>
[horizontal]
Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1508,7 +1509,7 @@ template<class K>
[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 <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
+7 -6
View File
@@ -1,5 +1,5 @@
[#unordered_multimap]
== Class template unordered_multimap
== Class Template unordered_multimap
:idprefix: unordered_multimap_
@@ -253,6 +253,7 @@ namespace boost {
unordered_multimap<Key, T, Hash, Pred, Alloc>& y)
noexcept(noexcept(x.swap(y)));
// Erasure
template<class K, class T, class H, class P, class A, class Predicate>
typename unordered_multimap<K, T, H, P, A>::size_type
xref:#unordered_multimap_erase_if[erase_if](unordered_multimap<K, T, H, P, A>& c, Predicate pred);
@@ -941,7 +942,7 @@ void insert(std::initializer_list<value_type> il);
Inserts a range of elements into the container.
[horizontal]
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/EmplaceConstructible[EmplaceConstructible^] into `X` from `*first`.
Requires:;; `value_type` is https://en.cppreference.com/w/cpp/named_req/CopyInsertable[CopyInsertable^] into the container.
Throws:;; When inserting a single element, if an exception is thrown by an operation other than a call to `hasher` the function has no effect.
Notes:;; Can invalidate iterators, but only if the insert causes the load factor to be greater to or equal to the maximum load factor. +
+
@@ -1223,7 +1224,7 @@ template<typename CompatibleKey, typename CompatibleHash, typename CompatiblePre
Returns:;; An iterator pointing to an element with key equivalent to `k`, or `b.end()` if no such element exists.
Notes:;; The templated overloads containing `CompatibleKey`, `CompatibleHash` and `CompatiblePredicate` are non-standard extensions which allow you to use a compatible hash function and equality predicate for a key of a different type in order to avoid an expensive type cast. In general, its use is not encouraged and instead the `K` member function templates should be used. +
+
The `template <typename K>` 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.
The `template<class K>` 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.
---
@@ -1236,7 +1237,7 @@ template<class K>
[horizontal]
Returns:;; The number of elements with key equivalent to `k`.
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1249,7 +1250,7 @@ template<class K>
[horizontal]
Returns:;; A boolean indicating whether or not there is an element with key equal to `key` in the container
Notes:;; The `template <typename K>` 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.
Notes:;; The `template<class K>` 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.
---
@@ -1265,7 +1266,7 @@ template<class K>
[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 <typename K>` 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.
Notes:;; The `template<class K>` 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.
---

Some files were not shown because too many files have changed in this diff Show More