You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

unordered_dense.h 78KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032
  1. ///////////////////////// ankerl::unordered_dense::{map, set} /////////////////////////
  2. // A fast & densely stored hashmap and hashset based on robin-hood backward shift deletion.
  3. // Version 4.4.0
  4. // https://github.com/martinus/unordered_dense
  5. //
  6. // Licensed under the MIT License <http://opensource.org/licenses/MIT>.
  7. // SPDX-License-Identifier: MIT
  8. // Copyright (c) 2022-2023 Martin Leitner-Ankerl <martin.ankerl@gmail.com>
  9. //
  10. // Permission is hereby granted, free of charge, to any person obtaining a copy
  11. // of this software and associated documentation files (the "Software"), to deal
  12. // in the Software without restriction, including without limitation the rights
  13. // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  14. // copies of the Software, and to permit persons to whom the Software is
  15. // furnished to do so, subject to the following conditions:
  16. //
  17. // The above copyright notice and this permission notice shall be included in all
  18. // copies or substantial portions of the Software.
  19. //
  20. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  21. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  22. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  23. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  24. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  25. // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  26. // SOFTWARE.
  27. #ifndef ANKERL_UNORDERED_DENSE_H
  28. #define ANKERL_UNORDERED_DENSE_H
  29. // see https://semver.org/spec/v2.0.0.html
  30. #define ANKERL_UNORDERED_DENSE_VERSION_MAJOR 4 // NOLINT(cppcoreguidelines-macro-usage) incompatible API changes
  31. #define ANKERL_UNORDERED_DENSE_VERSION_MINOR 4 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible functionality
  32. #define ANKERL_UNORDERED_DENSE_VERSION_PATCH 0 // NOLINT(cppcoreguidelines-macro-usage) backwards compatible bug fixes
  33. // API versioning with inline namespace, see https://www.foonathan.net/2018/11/inline-namespaces/
  34. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  35. #define ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch) v##major##_##minor##_##patch
  36. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  37. #define ANKERL_UNORDERED_DENSE_VERSION_CONCAT(major, minor, patch) ANKERL_UNORDERED_DENSE_VERSION_CONCAT1(major, minor, patch)
  38. #define ANKERL_UNORDERED_DENSE_NAMESPACE \
  39. ANKERL_UNORDERED_DENSE_VERSION_CONCAT( \
  40. ANKERL_UNORDERED_DENSE_VERSION_MAJOR, ANKERL_UNORDERED_DENSE_VERSION_MINOR, ANKERL_UNORDERED_DENSE_VERSION_PATCH)
  41. #if defined(_MSVC_LANG)
  42. # define ANKERL_UNORDERED_DENSE_CPP_VERSION _MSVC_LANG
  43. #else
  44. # define ANKERL_UNORDERED_DENSE_CPP_VERSION __cplusplus
  45. #endif
  46. #if defined(__GNUC__)
  47. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  48. # define ANKERL_UNORDERED_DENSE_PACK(decl) decl __attribute__((__packed__))
  49. #elif defined(_MSC_VER)
  50. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  51. # define ANKERL_UNORDERED_DENSE_PACK(decl) __pragma(pack(push, 1)) decl __pragma(pack(pop))
  52. #endif
  53. // exceptions
  54. #if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || defined(_CPPUNWIND)
  55. # define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 1 // NOLINT(cppcoreguidelines-macro-usage)
  56. #else
  57. # define ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() 0 // NOLINT(cppcoreguidelines-macro-usage)
  58. #endif
  59. #ifdef _MSC_VER
  60. # define ANKERL_UNORDERED_DENSE_NOINLINE __declspec(noinline)
  61. #else
  62. # define ANKERL_UNORDERED_DENSE_NOINLINE __attribute__((noinline))
  63. #endif
  64. // defined in unordered_dense.cpp
  65. #if !defined(ANKERL_UNORDERED_DENSE_EXPORT)
  66. # define ANKERL_UNORDERED_DENSE_EXPORT
  67. #endif
  68. #if ANKERL_UNORDERED_DENSE_CPP_VERSION < 201703L
  69. # error ankerl::unordered_dense requires C++17 or higher
  70. #else
  71. # include <array> // for array
  72. # include <cstdint> // for uint64_t, uint32_t, uint8_t, UINT64_C
  73. # include <cstring> // for size_t, memcpy, memset
  74. # include <functional> // for equal_to, hash
  75. # include <initializer_list> // for initializer_list
  76. # include <iterator> // for pair, distance
  77. # include <limits> // for numeric_limits
  78. # include <memory> // for allocator, allocator_traits, shared_ptr
  79. # include <optional> // for optional
  80. # include <stdexcept> // for out_of_range
  81. # include <string> // for basic_string
  82. # include <string_view> // for basic_string_view, hash
  83. # include <tuple> // for forward_as_tuple
  84. # include <type_traits> // for enable_if_t, declval, conditional_t, ena...
  85. # include <utility> // for forward, exchange, pair, as_const, piece...
  86. # include <vector> // for vector
  87. # if ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS() == 0
  88. # include <cstdlib> // for abort
  89. # endif
  90. # if defined(__has_include)
  91. # if __has_include(<memory_resource>)
  92. # define ANKERL_UNORDERED_DENSE_PMR std::pmr // NOLINT(cppcoreguidelines-macro-usage)
  93. # include <memory_resource> // for polymorphic_allocator
  94. # elif __has_include(<experimental/memory_resource>)
  95. # define ANKERL_UNORDERED_DENSE_PMR std::experimental::pmr // NOLINT(cppcoreguidelines-macro-usage)
  96. # include <experimental/memory_resource> // for polymorphic_allocator
  97. # endif
  98. # endif
  99. # if defined(_MSC_VER) && defined(_M_X64)
  100. # include <intrin.h>
  101. # pragma intrinsic(_umul128)
  102. # endif
  103. # if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__clang__)
  104. # define ANKERL_UNORDERED_DENSE_LIKELY(x) __builtin_expect(x, 1) // NOLINT(cppcoreguidelines-macro-usage)
  105. # define ANKERL_UNORDERED_DENSE_UNLIKELY(x) __builtin_expect(x, 0) // NOLINT(cppcoreguidelines-macro-usage)
  106. # else
  107. # define ANKERL_UNORDERED_DENSE_LIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
  108. # define ANKERL_UNORDERED_DENSE_UNLIKELY(x) (x) // NOLINT(cppcoreguidelines-macro-usage)
  109. # endif
  110. namespace ankerl::unordered_dense {
  111. inline namespace ANKERL_UNORDERED_DENSE_NAMESPACE {
  112. namespace detail {
  113. # if ANKERL_UNORDERED_DENSE_HAS_EXCEPTIONS()
  114. // make sure this is not inlined as it is slow and dramatically enlarges code, thus making other
  115. // inlinings more difficult. Throws are also generally the slow path.
  116. [[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_key_not_found() {
  117. throw std::out_of_range("ankerl::unordered_dense::map::at(): key not found");
  118. }
  119. [[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_bucket_overflow() {
  120. throw std::overflow_error("ankerl::unordered_dense: reached max bucket size, cannot increase size");
  121. }
  122. [[noreturn]] inline ANKERL_UNORDERED_DENSE_NOINLINE void on_error_too_many_elements() {
  123. throw std::out_of_range("ankerl::unordered_dense::map::replace(): too many elements");
  124. }
  125. # else
  126. [[noreturn]] inline void on_error_key_not_found() {
  127. abort();
  128. }
  129. [[noreturn]] inline void on_error_bucket_overflow() {
  130. abort();
  131. }
  132. [[noreturn]] inline void on_error_too_many_elements() {
  133. abort();
  134. }
  135. # endif
  136. } // namespace detail
  137. // hash ///////////////////////////////////////////////////////////////////////
  138. // This is a stripped-down implementation of wyhash: https://github.com/wangyi-fudan/wyhash
  139. // No big-endian support (because different values on different machines don't matter),
  140. // hardcodes seed and the secret, reformats the code, and clang-tidy fixes.
  141. namespace detail::wyhash {
  142. inline void mum(uint64_t* a, uint64_t* b) {
  143. # if defined(__SIZEOF_INT128__)
  144. __uint128_t r = *a;
  145. r *= *b;
  146. *a = static_cast<uint64_t>(r);
  147. *b = static_cast<uint64_t>(r >> 64U);
  148. # elif defined(_MSC_VER) && defined(_M_X64)
  149. *a = _umul128(*a, *b, b);
  150. # else
  151. uint64_t ha = *a >> 32U;
  152. uint64_t hb = *b >> 32U;
  153. uint64_t la = static_cast<uint32_t>(*a);
  154. uint64_t lb = static_cast<uint32_t>(*b);
  155. uint64_t hi{};
  156. uint64_t lo{};
  157. uint64_t rh = ha * hb;
  158. uint64_t rm0 = ha * lb;
  159. uint64_t rm1 = hb * la;
  160. uint64_t rl = la * lb;
  161. uint64_t t = rl + (rm0 << 32U);
  162. auto c = static_cast<uint64_t>(t < rl);
  163. lo = t + (rm1 << 32U);
  164. c += static_cast<uint64_t>(lo < t);
  165. hi = rh + (rm0 >> 32U) + (rm1 >> 32U) + c;
  166. *a = lo;
  167. *b = hi;
  168. # endif
  169. }
  170. // multiply and xor mix function, aka MUM
  171. [[nodiscard]] inline auto mix(uint64_t a, uint64_t b) -> uint64_t {
  172. mum(&a, &b);
  173. return a ^ b;
  174. }
  175. // read functions. WARNING: we don't care about endianness, so results are different on big endian!
  176. [[nodiscard]] inline auto r8(const uint8_t* p) -> uint64_t {
  177. uint64_t v{};
  178. std::memcpy(&v, p, 8U);
  179. return v;
  180. }
  181. [[nodiscard]] inline auto r4(const uint8_t* p) -> uint64_t {
  182. uint32_t v{};
  183. std::memcpy(&v, p, 4);
  184. return v;
  185. }
  186. // reads 1, 2, or 3 bytes
  187. [[nodiscard]] inline auto r3(const uint8_t* p, size_t k) -> uint64_t {
  188. return (static_cast<uint64_t>(p[0]) << 16U) | (static_cast<uint64_t>(p[k >> 1U]) << 8U) | p[k - 1];
  189. }
  190. [[maybe_unused]] [[nodiscard]] inline auto hash(void const* key, size_t len) -> uint64_t {
  191. static constexpr auto secret = std::array{UINT64_C(0xa0761d6478bd642f),
  192. UINT64_C(0xe7037ed1a0b428db),
  193. UINT64_C(0x8ebc6af09c88c6e3),
  194. UINT64_C(0x589965cc75374cc3)};
  195. auto const* p = static_cast<uint8_t const*>(key);
  196. uint64_t seed = secret[0];
  197. uint64_t a{};
  198. uint64_t b{};
  199. if (ANKERL_UNORDERED_DENSE_LIKELY(len <= 16)) {
  200. if (ANKERL_UNORDERED_DENSE_LIKELY(len >= 4)) {
  201. a = (r4(p) << 32U) | r4(p + ((len >> 3U) << 2U));
  202. b = (r4(p + len - 4) << 32U) | r4(p + len - 4 - ((len >> 3U) << 2U));
  203. } else if (ANKERL_UNORDERED_DENSE_LIKELY(len > 0)) {
  204. a = r3(p, len);
  205. b = 0;
  206. } else {
  207. a = 0;
  208. b = 0;
  209. }
  210. } else {
  211. size_t i = len;
  212. if (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 48)) {
  213. uint64_t see1 = seed;
  214. uint64_t see2 = seed;
  215. do {
  216. seed = mix(r8(p) ^ secret[1], r8(p + 8) ^ seed);
  217. see1 = mix(r8(p + 16) ^ secret[2], r8(p + 24) ^ see1);
  218. see2 = mix(r8(p + 32) ^ secret[3], r8(p + 40) ^ see2);
  219. p += 48;
  220. i -= 48;
  221. } while (ANKERL_UNORDERED_DENSE_LIKELY(i > 48));
  222. seed ^= see1 ^ see2;
  223. }
  224. while (ANKERL_UNORDERED_DENSE_UNLIKELY(i > 16)) {
  225. seed = mix(r8(p) ^ secret[1], r8(p + 8) ^ seed);
  226. i -= 16;
  227. p += 16;
  228. }
  229. a = r8(p + i - 16);
  230. b = r8(p + i - 8);
  231. }
  232. return mix(secret[1] ^ len, mix(a ^ secret[1], b ^ seed));
  233. }
  234. [[nodiscard]] inline auto hash(uint64_t x) -> uint64_t {
  235. return detail::wyhash::mix(x, UINT64_C(0x9E3779B97F4A7C15));
  236. }
  237. } // namespace detail::wyhash
  238. ANKERL_UNORDERED_DENSE_EXPORT template <typename T, typename Enable = void>
  239. struct hash {
  240. auto operator()(T const& obj) const noexcept(noexcept(std::declval<std::hash<T>>().operator()(std::declval<T const&>())))
  241. -> uint64_t {
  242. return std::hash<T>{}(obj);
  243. }
  244. };
  245. template <typename CharT>
  246. struct hash<std::basic_string<CharT>> {
  247. using is_avalanching = void;
  248. auto operator()(std::basic_string<CharT> const& str) const noexcept -> uint64_t {
  249. return detail::wyhash::hash(str.data(), sizeof(CharT) * str.size());
  250. }
  251. };
  252. template <typename CharT>
  253. struct hash<std::basic_string_view<CharT>> {
  254. using is_avalanching = void;
  255. auto operator()(std::basic_string_view<CharT> const& sv) const noexcept -> uint64_t {
  256. return detail::wyhash::hash(sv.data(), sizeof(CharT) * sv.size());
  257. }
  258. };
  259. template <class T>
  260. struct hash<T*> {
  261. using is_avalanching = void;
  262. auto operator()(T* ptr) const noexcept -> uint64_t {
  263. // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
  264. return detail::wyhash::hash(reinterpret_cast<uintptr_t>(ptr));
  265. }
  266. };
  267. template <class T>
  268. struct hash<std::unique_ptr<T>> {
  269. using is_avalanching = void;
  270. auto operator()(std::unique_ptr<T> const& ptr) const noexcept -> uint64_t {
  271. // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
  272. return detail::wyhash::hash(reinterpret_cast<uintptr_t>(ptr.get()));
  273. }
  274. };
  275. template <class T>
  276. struct hash<std::shared_ptr<T>> {
  277. using is_avalanching = void;
  278. auto operator()(std::shared_ptr<T> const& ptr) const noexcept -> uint64_t {
  279. // NOLINTNEXTLINE(cppcoreguidelines-pro-type-reinterpret-cast)
  280. return detail::wyhash::hash(reinterpret_cast<uintptr_t>(ptr.get()));
  281. }
  282. };
  283. template <typename Enum>
  284. struct hash<Enum, typename std::enable_if<std::is_enum<Enum>::value>::type> {
  285. using is_avalanching = void;
  286. auto operator()(Enum e) const noexcept -> uint64_t {
  287. using underlying = typename std::underlying_type_t<Enum>;
  288. return detail::wyhash::hash(static_cast<underlying>(e));
  289. }
  290. };
  291. template <typename... Args>
  292. struct tuple_hash_helper {
  293. // Converts the value into 64bit. If it is an integral type, just cast it. Mixing is doing the rest.
  294. // If it isn't an integral we need to hash it.
  295. template <typename Arg>
  296. [[nodiscard]] constexpr static auto to64(Arg const& arg) -> uint64_t {
  297. if constexpr (std::is_integral_v<Arg> || std::is_enum_v<Arg>) {
  298. return static_cast<uint64_t>(arg);
  299. } else {
  300. return hash<Arg>{}(arg);
  301. }
  302. }
  303. [[nodiscard]] static auto mix64(uint64_t state, uint64_t v) -> uint64_t {
  304. return detail::wyhash::mix(state + v, uint64_t{0x9ddfea08eb382d69});
  305. }
  306. // Creates a buffer that holds all the data from each element of the tuple. If possible we memcpy the data directly. If
  307. // not, we hash the object and use this for the array. Size of the array is known at compile time, and memcpy is optimized
  308. // away, so filling the buffer is highly efficient. Finally, call wyhash with this buffer.
  309. template <typename T, std::size_t... Idx>
  310. [[nodiscard]] static auto calc_hash(T const& t, std::index_sequence<Idx...>) noexcept -> uint64_t {
  311. auto h = uint64_t{};
  312. ((h = mix64(h, to64(std::get<Idx>(t)))), ...);
  313. return h;
  314. }
  315. };
  316. template <typename... Args>
  317. struct hash<std::tuple<Args...>> : tuple_hash_helper<Args...> {
  318. using is_avalanching = void;
  319. auto operator()(std::tuple<Args...> const& t) const noexcept -> uint64_t {
  320. return tuple_hash_helper<Args...>::calc_hash(t, std::index_sequence_for<Args...>{});
  321. }
  322. };
  323. template <typename A, typename B>
  324. struct hash<std::pair<A, B>> : tuple_hash_helper<A, B> {
  325. using is_avalanching = void;
  326. auto operator()(std::pair<A, B> const& t) const noexcept -> uint64_t {
  327. return tuple_hash_helper<A, B>::calc_hash(t, std::index_sequence_for<A, B>{});
  328. }
  329. };
  330. // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
  331. # define ANKERL_UNORDERED_DENSE_HASH_STATICCAST(T) \
  332. template <> \
  333. struct hash<T> { \
  334. using is_avalanching = void; \
  335. auto operator()(T const& obj) const noexcept -> uint64_t { \
  336. return detail::wyhash::hash(static_cast<uint64_t>(obj)); \
  337. } \
  338. }
  339. # if defined(__GNUC__) && !defined(__clang__)
  340. # pragma GCC diagnostic push
  341. # pragma GCC diagnostic ignored "-Wuseless-cast"
  342. # endif
  343. // see https://en.cppreference.com/w/cpp/utility/hash
  344. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(bool);
  345. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char);
  346. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(signed char);
  347. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned char);
  348. # if ANKERL_UNORDERED_DENSE_CPP_VERSION >= 202002L && defined(__cpp_char8_t)
  349. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char8_t);
  350. # endif
  351. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char16_t);
  352. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(char32_t);
  353. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(wchar_t);
  354. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(short);
  355. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned short);
  356. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(int);
  357. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned int);
  358. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(long);
  359. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(long long);
  360. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned long);
  361. ANKERL_UNORDERED_DENSE_HASH_STATICCAST(unsigned long long);
  362. # if defined(__GNUC__) && !defined(__clang__)
  363. # pragma GCC diagnostic pop
  364. # endif
  365. // bucket_type //////////////////////////////////////////////////////////
  366. namespace bucket_type {
  367. struct standard {
  368. static constexpr uint32_t dist_inc = 1U << 8U; // skip 1 byte fingerprint
  369. static constexpr uint32_t fingerprint_mask = dist_inc - 1; // mask for 1 byte of fingerprint
  370. uint32_t m_dist_and_fingerprint; // upper 3 byte: distance to original bucket. lower byte: fingerprint from hash
  371. uint32_t m_value_idx; // index into the m_values vector.
  372. };
  373. ANKERL_UNORDERED_DENSE_PACK(struct big {
  374. static constexpr uint32_t dist_inc = 1U << 8U; // skip 1 byte fingerprint
  375. static constexpr uint32_t fingerprint_mask = dist_inc - 1; // mask for 1 byte of fingerprint
  376. uint32_t m_dist_and_fingerprint; // upper 3 byte: distance to original bucket. lower byte: fingerprint from hash
  377. size_t m_value_idx; // index into the m_values vector.
  378. });
  379. } // namespace bucket_type
  380. namespace detail {
  381. struct nonesuch {};
  382. template <class Default, class AlwaysVoid, template <class...> class Op, class... Args>
  383. struct detector {
  384. using value_t = std::false_type;
  385. using type = Default;
  386. };
  387. template <class Default, template <class...> class Op, class... Args>
  388. struct detector<Default, std::void_t<Op<Args...>>, Op, Args...> {
  389. using value_t = std::true_type;
  390. using type = Op<Args...>;
  391. };
  392. template <template <class...> class Op, class... Args>
  393. using is_detected = typename detail::detector<detail::nonesuch, void, Op, Args...>::value_t;
  394. template <template <class...> class Op, class... Args>
  395. constexpr bool is_detected_v = is_detected<Op, Args...>::value;
  396. template <typename T>
  397. using detect_avalanching = typename T::is_avalanching;
  398. template <typename T>
  399. using detect_is_transparent = typename T::is_transparent;
  400. template <typename T>
  401. using detect_iterator = typename T::iterator;
  402. template <typename T>
  403. using detect_reserve = decltype(std::declval<T&>().reserve(size_t{}));
  404. // enable_if helpers
  405. template <typename Mapped>
  406. constexpr bool is_map_v = !std::is_void_v<Mapped>;
  407. // clang-format off
  408. template <typename Hash, typename KeyEqual>
  409. constexpr bool is_transparent_v = is_detected_v<detect_is_transparent, Hash> && is_detected_v<detect_is_transparent, KeyEqual>;
  410. // clang-format on
  411. template <typename From, typename To1, typename To2>
  412. constexpr bool is_neither_convertible_v = !std::is_convertible_v<From, To1> && !std::is_convertible_v<From, To2>;
  413. template <typename T>
  414. constexpr bool has_reserve = is_detected_v<detect_reserve, T>;
  415. // base type for map has mapped_type
  416. template <class T>
  417. struct base_table_type_map {
  418. using mapped_type = T;
  419. };
  420. // base type for set doesn't have mapped_type
  421. struct base_table_type_set {};
  422. } // namespace detail
  423. // Very much like std::deque, but faster for indexing (in most cases). As of now this doesn't implement the full std::vector
  424. // API, but merely what's necessary to work as an underlying container for ankerl::unordered_dense::{map, set}.
  425. // It allocates blocks of equal size and puts them into the m_blocks vector. That means it can grow simply by adding a new
  426. // block to the back of m_blocks, and doesn't double its size like an std::vector. The disadvantage is that memory is not
  427. // linear and thus there is one more indirection necessary for indexing.
  428. template <typename T, typename Allocator = std::allocator<T>, size_t MaxSegmentSizeBytes = 4096>
  429. class segmented_vector {
  430. template <bool IsConst>
  431. class iter_t;
  432. public:
  433. using allocator_type = Allocator;
  434. using pointer = typename std::allocator_traits<allocator_type>::pointer;
  435. using const_pointer = typename std::allocator_traits<allocator_type>::const_pointer;
  436. using difference_type = typename std::allocator_traits<allocator_type>::difference_type;
  437. using value_type = T;
  438. using size_type = std::size_t;
  439. using reference = T&;
  440. using const_reference = T const&;
  441. using iterator = iter_t<false>;
  442. using const_iterator = iter_t<true>;
  443. private:
  444. using vec_alloc = typename std::allocator_traits<Allocator>::template rebind_alloc<pointer>;
  445. std::vector<pointer, vec_alloc> m_blocks{};
  446. size_t m_size{};
  447. // Calculates the maximum number for x in (s << x) <= max_val
  448. static constexpr auto num_bits_closest(size_t max_val, size_t s) -> size_t {
  449. auto f = size_t{0};
  450. while (s << (f + 1) <= max_val) {
  451. ++f;
  452. }
  453. return f;
  454. }
  455. using self_t = segmented_vector<T, Allocator, MaxSegmentSizeBytes>;
  456. static constexpr auto num_bits = num_bits_closest(MaxSegmentSizeBytes, sizeof(T));
  457. static constexpr auto num_elements_in_block = 1U << num_bits;
  458. static constexpr auto mask = num_elements_in_block - 1U;
  459. /**
  460. * Iterator class doubles as const_iterator and iterator
  461. */
  462. template <bool IsConst>
  463. class iter_t {
  464. using ptr_t = typename std::conditional_t<IsConst, segmented_vector::const_pointer const*, segmented_vector::pointer*>;
  465. ptr_t m_data{};
  466. size_t m_idx{};
  467. template <bool B>
  468. friend class iter_t;
  469. public:
  470. using difference_type = segmented_vector::difference_type;
  471. using value_type = T;
  472. using reference = typename std::conditional_t<IsConst, value_type const&, value_type&>;
  473. using pointer = typename std::conditional_t<IsConst, segmented_vector::const_pointer, segmented_vector::pointer>;
  474. using iterator_category = std::forward_iterator_tag;
  475. iter_t() noexcept = default;
  476. template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
  477. // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
  478. constexpr iter_t(iter_t<OtherIsConst> const& other) noexcept
  479. : m_data(other.m_data)
  480. , m_idx(other.m_idx) {}
  481. constexpr iter_t(ptr_t data, size_t idx) noexcept
  482. : m_data(data)
  483. , m_idx(idx) {}
  484. template <bool OtherIsConst, typename = typename std::enable_if<IsConst && !OtherIsConst>::type>
  485. constexpr auto operator=(iter_t<OtherIsConst> const& other) noexcept -> iter_t& {
  486. m_data = other.m_data;
  487. m_idx = other.m_idx;
  488. return *this;
  489. }
  490. constexpr auto operator++() noexcept -> iter_t& {
  491. ++m_idx;
  492. return *this;
  493. }
  494. constexpr auto operator+(difference_type diff) noexcept -> iter_t {
  495. return {m_data, static_cast<size_t>(static_cast<difference_type>(m_idx) + diff)};
  496. }
  497. template <bool OtherIsConst>
  498. constexpr auto operator-(iter_t<OtherIsConst> const& other) noexcept -> difference_type {
  499. return static_cast<difference_type>(m_idx) - static_cast<difference_type>(other.m_idx);
  500. }
  501. constexpr auto operator*() const noexcept -> reference {
  502. return m_data[m_idx >> num_bits][m_idx & mask];
  503. }
  504. constexpr auto operator->() const noexcept -> pointer {
  505. return &m_data[m_idx >> num_bits][m_idx & mask];
  506. }
  507. template <bool O>
  508. constexpr auto operator==(iter_t<O> const& o) const noexcept -> bool {
  509. return m_idx == o.m_idx;
  510. }
  511. template <bool O>
  512. constexpr auto operator!=(iter_t<O> const& o) const noexcept -> bool {
  513. return !(*this == o);
  514. }
  515. };
  516. // slow path: need to allocate a new segment every once in a while
  517. void increase_capacity() {
  518. auto ba = Allocator(m_blocks.get_allocator());
  519. pointer block = std::allocator_traits<Allocator>::allocate(ba, num_elements_in_block);
  520. m_blocks.push_back(block);
  521. }
  522. // Moves everything from other
  523. void append_everything_from(segmented_vector&& other) {
  524. reserve(size() + other.size());
  525. for (auto&& o : other) {
  526. emplace_back(std::move(o));
  527. }
  528. }
  529. // Copies everything from other
  530. void append_everything_from(segmented_vector const& other) {
  531. reserve(size() + other.size());
  532. for (auto const& o : other) {
  533. emplace_back(o);
  534. }
  535. }
  536. void dealloc() {
  537. auto ba = Allocator(m_blocks.get_allocator());
  538. for (auto ptr : m_blocks) {
  539. std::allocator_traits<Allocator>::deallocate(ba, ptr, num_elements_in_block);
  540. }
  541. }
  542. [[nodiscard]] static constexpr auto calc_num_blocks_for_capacity(size_t capacity) {
  543. return (capacity + num_elements_in_block - 1U) / num_elements_in_block;
  544. }
  545. public:
  546. segmented_vector() = default;
  547. // NOLINTNEXTLINE(google-explicit-constructor,hicpp-explicit-conversions)
  548. segmented_vector(Allocator alloc)
  549. : m_blocks(vec_alloc(alloc)) {}
  550. segmented_vector(segmented_vector&& other, Allocator alloc)
  551. : segmented_vector(alloc) {
  552. *this = std::move(other);
  553. }
  554. segmented_vector(segmented_vector const& other, Allocator alloc)
  555. : m_blocks(vec_alloc(alloc)) {
  556. append_everything_from(other);
  557. }
  558. segmented_vector(segmented_vector&& other) noexcept
  559. : segmented_vector(std::move(other), get_allocator()) {}
  560. segmented_vector(segmented_vector const& other) {
  561. append_everything_from(other);
  562. }
  563. auto operator=(segmented_vector const& other) -> segmented_vector& {
  564. if (this == &other) {
  565. return *this;
  566. }
  567. clear();
  568. append_everything_from(other);
  569. return *this;
  570. }
  571. auto operator=(segmented_vector&& other) noexcept -> segmented_vector& {
  572. clear();
  573. dealloc();
  574. if (other.get_allocator() == get_allocator()) {
  575. m_blocks = std::move(other.m_blocks);
  576. m_size = std::exchange(other.m_size, {});
  577. } else {
  578. // make sure to construct with other's allocator!
  579. m_blocks = std::vector<pointer, vec_alloc>(vec_alloc(other.get_allocator()));
  580. append_everything_from(std::move(other));
  581. }
  582. return *this;
  583. }
  584. ~segmented_vector() {
  585. clear();
  586. dealloc();
  587. }
  588. [[nodiscard]] constexpr auto size() const -> size_t {
  589. return m_size;
  590. }
  591. [[nodiscard]] constexpr auto capacity() const -> size_t {
  592. return m_blocks.size() * num_elements_in_block;
  593. }
  594. // Indexing is highly performance critical
  595. [[nodiscard]] constexpr auto operator[](size_t i) const noexcept -> T const& {
  596. return m_blocks[i >> num_bits][i & mask];
  597. }
  598. [[nodiscard]] constexpr auto operator[](size_t i) noexcept -> T& {
  599. return m_blocks[i >> num_bits][i & mask];
  600. }
  601. [[nodiscard]] constexpr auto begin() -> iterator {
  602. return {m_blocks.data(), 0U};
  603. }
  604. [[nodiscard]] constexpr auto begin() const -> const_iterator {
  605. return {m_blocks.data(), 0U};
  606. }
  607. [[nodiscard]] constexpr auto cbegin() const -> const_iterator {
  608. return {m_blocks.data(), 0U};
  609. }
  610. [[nodiscard]] constexpr auto end() -> iterator {
  611. return {m_blocks.data(), m_size};
  612. }
  613. [[nodiscard]] constexpr auto end() const -> const_iterator {
  614. return {m_blocks.data(), m_size};
  615. }
  616. [[nodiscard]] constexpr auto cend() const -> const_iterator {
  617. return {m_blocks.data(), m_size};
  618. }
  619. [[nodiscard]] constexpr auto back() -> reference {
  620. return operator[](m_size - 1);
  621. }
  622. [[nodiscard]] constexpr auto back() const -> const_reference {
  623. return operator[](m_size - 1);
  624. }
  625. void pop_back() {
  626. back().~T();
  627. --m_size;
  628. }
  629. [[nodiscard]] auto empty() const {
  630. return 0 == m_size;
  631. }
  632. void reserve(size_t new_capacity) {
  633. m_blocks.reserve(calc_num_blocks_for_capacity(new_capacity));
  634. while (new_capacity > capacity()) {
  635. increase_capacity();
  636. }
  637. }
  638. [[nodiscard]] auto get_allocator() const -> allocator_type {
  639. return allocator_type{m_blocks.get_allocator()};
  640. }
  641. template <class... Args>
  642. auto emplace_back(Args&&... args) -> reference {
  643. if (m_size == capacity()) {
  644. increase_capacity();
  645. }
  646. auto* ptr = static_cast<void*>(&operator[](m_size));
  647. auto& ref = *new (ptr) T(std::forward<Args>(args)...);
  648. ++m_size;
  649. return ref;
  650. }
  651. void clear() {
  652. if constexpr (!std::is_trivially_destructible_v<T>) {
  653. for (size_t i = 0, s = size(); i < s; ++i) {
  654. operator[](i).~T();
  655. }
  656. }
  657. m_size = 0;
  658. }
  659. void shrink_to_fit() {
  660. auto ba = Allocator(m_blocks.get_allocator());
  661. auto num_blocks_required = calc_num_blocks_for_capacity(m_size);
  662. while (m_blocks.size() > num_blocks_required) {
  663. std::allocator_traits<Allocator>::deallocate(ba, m_blocks.back(), num_elements_in_block);
  664. m_blocks.pop_back();
  665. }
  666. m_blocks.shrink_to_fit();
  667. }
  668. };
  669. namespace detail {
  670. // This is it, the table. Doubles as map and set, and uses `void` for T when its used as a set.
  671. template <class Key,
  672. class T, // when void, treat it as a set.
  673. class Hash,
  674. class KeyEqual,
  675. class AllocatorOrContainer,
  676. class Bucket,
  677. bool IsSegmented>
  678. class table : public std::conditional_t<is_map_v<T>, base_table_type_map<T>, base_table_type_set> {
  679. using underlying_value_type = typename std::conditional_t<is_map_v<T>, std::pair<Key, T>, Key>;
  680. using underlying_container_type = std::conditional_t<IsSegmented,
  681. segmented_vector<underlying_value_type, AllocatorOrContainer>,
  682. std::vector<underlying_value_type, AllocatorOrContainer>>;
  683. public:
  684. using value_container_type = std::
  685. conditional_t<is_detected_v<detect_iterator, AllocatorOrContainer>, AllocatorOrContainer, underlying_container_type>;
  686. private:
  687. using bucket_alloc =
  688. typename std::allocator_traits<typename value_container_type::allocator_type>::template rebind_alloc<Bucket>;
  689. using bucket_alloc_traits = std::allocator_traits<bucket_alloc>;
  690. static constexpr uint8_t initial_shifts = 64 - 2; // 2^(64-m_shift) number of buckets
  691. static constexpr float default_max_load_factor = 0.8F;
  692. public:
  693. using key_type = Key;
  694. using value_type = typename value_container_type::value_type;
  695. using size_type = typename value_container_type::size_type;
  696. using difference_type = typename value_container_type::difference_type;
  697. using hasher = Hash;
  698. using key_equal = KeyEqual;
  699. using allocator_type = typename value_container_type::allocator_type;
  700. using reference = typename value_container_type::reference;
  701. using const_reference = typename value_container_type::const_reference;
  702. using pointer = typename value_container_type::pointer;
  703. using const_pointer = typename value_container_type::const_pointer;
  704. using const_iterator = typename value_container_type::const_iterator;
  705. using iterator = std::conditional_t<is_map_v<T>, typename value_container_type::iterator, const_iterator>;
  706. using bucket_type = Bucket;
  707. private:
  708. using value_idx_type = decltype(Bucket::m_value_idx);
  709. using dist_and_fingerprint_type = decltype(Bucket::m_dist_and_fingerprint);
  710. static_assert(std::is_trivially_destructible_v<Bucket>, "assert there's no need to call destructor / std::destroy");
  711. static_assert(std::is_trivially_copyable_v<Bucket>, "assert we can just memset / memcpy");
  712. value_container_type m_values{}; // Contains all the key-value pairs in one densely stored container. No holes.
  713. using bucket_pointer = typename std::allocator_traits<bucket_alloc>::pointer;
  714. bucket_pointer m_buckets{};
  715. size_t m_num_buckets = 0;
  716. size_t m_max_bucket_capacity = 0;
  717. float m_max_load_factor = default_max_load_factor;
  718. Hash m_hash{};
  719. KeyEqual m_equal{};
  720. uint8_t m_shifts = initial_shifts;
  721. [[nodiscard]] auto next(value_idx_type bucket_idx) const -> value_idx_type {
  722. return ANKERL_UNORDERED_DENSE_UNLIKELY(bucket_idx + 1U == m_num_buckets)
  723. ? 0
  724. : static_cast<value_idx_type>(bucket_idx + 1U);
  725. }
  726. // Helper to access bucket through pointer types
  727. [[nodiscard]] static constexpr auto at(bucket_pointer bucket_ptr, size_t offset) -> Bucket& {
  728. return *(bucket_ptr + static_cast<typename std::allocator_traits<bucket_alloc>::difference_type>(offset));
  729. }
  730. // use the dist_inc and dist_dec functions so that uint16_t types work without warning
  731. [[nodiscard]] static constexpr auto dist_inc(dist_and_fingerprint_type x) -> dist_and_fingerprint_type {
  732. return static_cast<dist_and_fingerprint_type>(x + Bucket::dist_inc);
  733. }
  734. [[nodiscard]] static constexpr auto dist_dec(dist_and_fingerprint_type x) -> dist_and_fingerprint_type {
  735. return static_cast<dist_and_fingerprint_type>(x - Bucket::dist_inc);
  736. }
  737. // The goal of mixed_hash is to always produce a high quality 64bit hash.
  738. template <typename K>
  739. [[nodiscard]] constexpr auto mixed_hash(K const& key) const -> uint64_t {
  740. if constexpr (is_detected_v<detect_avalanching, Hash>) {
  741. // we know that the hash is good because is_avalanching.
  742. if constexpr (sizeof(decltype(m_hash(key))) < sizeof(uint64_t)) {
  743. // 32bit hash and is_avalanching => multiply with a constant to avalanche bits upwards
  744. return m_hash(key) * UINT64_C(0x9ddfea08eb382d69);
  745. } else {
  746. // 64bit and is_avalanching => only use the hash itself.
  747. return m_hash(key);
  748. }
  749. } else {
  750. // not is_avalanching => apply wyhash
  751. return wyhash::hash(m_hash(key));
  752. }
  753. }
  754. [[nodiscard]] constexpr auto dist_and_fingerprint_from_hash(uint64_t hash) const -> dist_and_fingerprint_type {
  755. return Bucket::dist_inc | (static_cast<dist_and_fingerprint_type>(hash) & Bucket::fingerprint_mask);
  756. }
  757. [[nodiscard]] constexpr auto bucket_idx_from_hash(uint64_t hash) const -> value_idx_type {
  758. return static_cast<value_idx_type>(hash >> m_shifts);
  759. }
  760. [[nodiscard]] static constexpr auto get_key(value_type const& vt) -> key_type const& {
  761. if constexpr (is_map_v<T>) {
  762. return vt.first;
  763. } else {
  764. return vt;
  765. }
  766. }
  767. template <typename K>
  768. [[nodiscard]] auto next_while_less(K const& key) const -> Bucket {
  769. auto hash = mixed_hash(key);
  770. auto dist_and_fingerprint = dist_and_fingerprint_from_hash(hash);
  771. auto bucket_idx = bucket_idx_from_hash(hash);
  772. while (dist_and_fingerprint < at(m_buckets, bucket_idx).m_dist_and_fingerprint) {
  773. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  774. bucket_idx = next(bucket_idx);
  775. }
  776. return {dist_and_fingerprint, bucket_idx};
  777. }
  778. void place_and_shift_up(Bucket bucket, value_idx_type place) {
  779. while (0 != at(m_buckets, place).m_dist_and_fingerprint) {
  780. bucket = std::exchange(at(m_buckets, place), bucket);
  781. bucket.m_dist_and_fingerprint = dist_inc(bucket.m_dist_and_fingerprint);
  782. place = next(place);
  783. }
  784. at(m_buckets, place) = bucket;
  785. }
  786. [[nodiscard]] static constexpr auto calc_num_buckets(uint8_t shifts) -> size_t {
  787. return (std::min)(max_bucket_count(), size_t{1} << (64U - shifts));
  788. }
  789. [[nodiscard]] constexpr auto calc_shifts_for_size(size_t s) const -> uint8_t {
  790. auto shifts = initial_shifts;
  791. while (shifts > 0 && static_cast<size_t>(static_cast<float>(calc_num_buckets(shifts)) * max_load_factor()) < s) {
  792. --shifts;
  793. }
  794. return shifts;
  795. }
  796. // assumes m_values has data, m_buckets=m_buckets_end=nullptr, m_shifts is INITIAL_SHIFTS
  797. void copy_buckets(table const& other) {
  798. // assumes m_values has already the correct data copied over.
  799. if (empty()) {
  800. // when empty, at least allocate an initial buckets and clear them.
  801. allocate_buckets_from_shift();
  802. clear_buckets();
  803. } else {
  804. m_shifts = other.m_shifts;
  805. allocate_buckets_from_shift();
  806. std::memcpy(m_buckets, other.m_buckets, sizeof(Bucket) * bucket_count());
  807. }
  808. }
  809. /**
  810. * True when no element can be added any more without increasing the size
  811. */
  812. [[nodiscard]] auto is_full() const -> bool {
  813. return size() > m_max_bucket_capacity;
  814. }
  815. void deallocate_buckets() {
  816. auto ba = bucket_alloc(m_values.get_allocator());
  817. if (nullptr != m_buckets) {
  818. bucket_alloc_traits::deallocate(ba, m_buckets, bucket_count());
  819. m_buckets = nullptr;
  820. }
  821. m_num_buckets = 0;
  822. m_max_bucket_capacity = 0;
  823. }
  824. void allocate_buckets_from_shift() {
  825. auto ba = bucket_alloc(m_values.get_allocator());
  826. m_num_buckets = calc_num_buckets(m_shifts);
  827. m_buckets = bucket_alloc_traits::allocate(ba, m_num_buckets);
  828. if (m_num_buckets == max_bucket_count()) {
  829. // reached the maximum, make sure we can use each bucket
  830. m_max_bucket_capacity = max_bucket_count();
  831. } else {
  832. m_max_bucket_capacity = static_cast<value_idx_type>(static_cast<float>(m_num_buckets) * max_load_factor());
  833. }
  834. }
  835. void clear_buckets() {
  836. if (m_buckets != nullptr) {
  837. std::memset(&*m_buckets, 0, sizeof(Bucket) * bucket_count());
  838. }
  839. }
  840. void clear_and_fill_buckets_from_values() {
  841. clear_buckets();
  842. for (value_idx_type value_idx = 0, end_idx = static_cast<value_idx_type>(m_values.size()); value_idx < end_idx;
  843. ++value_idx) {
  844. auto const& key = get_key(m_values[value_idx]);
  845. auto [dist_and_fingerprint, bucket] = next_while_less(key);
  846. // we know for certain that key has not yet been inserted, so no need to check it.
  847. place_and_shift_up({dist_and_fingerprint, value_idx}, bucket);
  848. }
  849. }
  850. void increase_size() {
  851. if (m_max_bucket_capacity == max_bucket_count()) {
  852. // remove the value again, we can't add it!
  853. m_values.pop_back();
  854. on_error_bucket_overflow();
  855. }
  856. --m_shifts;
  857. deallocate_buckets();
  858. allocate_buckets_from_shift();
  859. clear_and_fill_buckets_from_values();
  860. }
  861. template <typename Op>
  862. void do_erase(value_idx_type bucket_idx, Op handle_erased_value) {
  863. auto const value_idx_to_remove = at(m_buckets, bucket_idx).m_value_idx;
  864. // shift down until either empty or an element with correct spot is found
  865. auto next_bucket_idx = next(bucket_idx);
  866. while (at(m_buckets, next_bucket_idx).m_dist_and_fingerprint >= Bucket::dist_inc * 2) {
  867. at(m_buckets, bucket_idx) = {dist_dec(at(m_buckets, next_bucket_idx).m_dist_and_fingerprint),
  868. at(m_buckets, next_bucket_idx).m_value_idx};
  869. bucket_idx = std::exchange(next_bucket_idx, next(next_bucket_idx));
  870. }
  871. at(m_buckets, bucket_idx) = {};
  872. handle_erased_value(std::move(m_values[value_idx_to_remove]));
  873. // update m_values
  874. if (value_idx_to_remove != m_values.size() - 1) {
  875. // no luck, we'll have to replace the value with the last one and update the index accordingly
  876. auto& val = m_values[value_idx_to_remove];
  877. val = std::move(m_values.back());
  878. // update the values_idx of the moved entry. No need to play the info game, just look until we find the values_idx
  879. auto mh = mixed_hash(get_key(val));
  880. bucket_idx = bucket_idx_from_hash(mh);
  881. auto const values_idx_back = static_cast<value_idx_type>(m_values.size() - 1);
  882. while (values_idx_back != at(m_buckets, bucket_idx).m_value_idx) {
  883. bucket_idx = next(bucket_idx);
  884. }
  885. at(m_buckets, bucket_idx).m_value_idx = value_idx_to_remove;
  886. }
  887. m_values.pop_back();
  888. }
  889. template <typename K, typename Op>
  890. auto do_erase_key(K&& key, Op handle_erased_value) -> size_t {
  891. if (empty()) {
  892. return 0;
  893. }
  894. auto [dist_and_fingerprint, bucket_idx] = next_while_less(key);
  895. while (dist_and_fingerprint == at(m_buckets, bucket_idx).m_dist_and_fingerprint &&
  896. !m_equal(key, get_key(m_values[at(m_buckets, bucket_idx).m_value_idx]))) {
  897. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  898. bucket_idx = next(bucket_idx);
  899. }
  900. if (dist_and_fingerprint != at(m_buckets, bucket_idx).m_dist_and_fingerprint) {
  901. return 0;
  902. }
  903. do_erase(bucket_idx, handle_erased_value);
  904. return 1;
  905. }
  906. template <class K, class M>
  907. auto do_insert_or_assign(K&& key, M&& mapped) -> std::pair<iterator, bool> {
  908. auto it_isinserted = try_emplace(std::forward<K>(key), std::forward<M>(mapped));
  909. if (!it_isinserted.second) {
  910. it_isinserted.first->second = std::forward<M>(mapped);
  911. }
  912. return it_isinserted;
  913. }
  914. template <typename... Args>
  915. auto do_place_element(dist_and_fingerprint_type dist_and_fingerprint, value_idx_type bucket_idx, Args&&... args)
  916. -> std::pair<iterator, bool> {
  917. // emplace the new value. If that throws an exception, no harm done; index is still in a valid state
  918. m_values.emplace_back(std::forward<Args>(args)...);
  919. auto value_idx = static_cast<value_idx_type>(m_values.size() - 1);
  920. if (ANKERL_UNORDERED_DENSE_UNLIKELY(is_full())) {
  921. increase_size();
  922. } else {
  923. place_and_shift_up({dist_and_fingerprint, value_idx}, bucket_idx);
  924. }
  925. // place element and shift up until we find an empty spot
  926. return {begin() + static_cast<difference_type>(value_idx), true};
  927. }
  928. template <typename K, typename... Args>
  929. auto do_try_emplace(K&& key, Args&&... args) -> std::pair<iterator, bool> {
  930. auto hash = mixed_hash(key);
  931. auto dist_and_fingerprint = dist_and_fingerprint_from_hash(hash);
  932. auto bucket_idx = bucket_idx_from_hash(hash);
  933. while (true) {
  934. auto* bucket = &at(m_buckets, bucket_idx);
  935. if (dist_and_fingerprint == bucket->m_dist_and_fingerprint) {
  936. if (m_equal(key, get_key(m_values[bucket->m_value_idx]))) {
  937. return {begin() + static_cast<difference_type>(bucket->m_value_idx), false};
  938. }
  939. } else if (dist_and_fingerprint > bucket->m_dist_and_fingerprint) {
  940. return do_place_element(dist_and_fingerprint,
  941. bucket_idx,
  942. std::piecewise_construct,
  943. std::forward_as_tuple(std::forward<K>(key)),
  944. std::forward_as_tuple(std::forward<Args>(args)...));
  945. }
  946. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  947. bucket_idx = next(bucket_idx);
  948. }
  949. }
  950. template <typename K>
  951. auto do_find(K const& key) -> iterator {
  952. if (ANKERL_UNORDERED_DENSE_UNLIKELY(empty())) {
  953. return end();
  954. }
  955. auto mh = mixed_hash(key);
  956. auto dist_and_fingerprint = dist_and_fingerprint_from_hash(mh);
  957. auto bucket_idx = bucket_idx_from_hash(mh);
  958. auto* bucket = &at(m_buckets, bucket_idx);
  959. // unrolled loop. *Always* check a few directly, then enter the loop. This is faster.
  960. if (dist_and_fingerprint == bucket->m_dist_and_fingerprint && m_equal(key, get_key(m_values[bucket->m_value_idx]))) {
  961. return begin() + static_cast<difference_type>(bucket->m_value_idx);
  962. }
  963. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  964. bucket_idx = next(bucket_idx);
  965. bucket = &at(m_buckets, bucket_idx);
  966. if (dist_and_fingerprint == bucket->m_dist_and_fingerprint && m_equal(key, get_key(m_values[bucket->m_value_idx]))) {
  967. return begin() + static_cast<difference_type>(bucket->m_value_idx);
  968. }
  969. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  970. bucket_idx = next(bucket_idx);
  971. bucket = &at(m_buckets, bucket_idx);
  972. while (true) {
  973. if (dist_and_fingerprint == bucket->m_dist_and_fingerprint) {
  974. if (m_equal(key, get_key(m_values[bucket->m_value_idx]))) {
  975. return begin() + static_cast<difference_type>(bucket->m_value_idx);
  976. }
  977. } else if (dist_and_fingerprint > bucket->m_dist_and_fingerprint) {
  978. return end();
  979. }
  980. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  981. bucket_idx = next(bucket_idx);
  982. bucket = &at(m_buckets, bucket_idx);
  983. }
  984. }
  985. template <typename K>
  986. auto do_find(K const& key) const -> const_iterator {
  987. return const_cast<table*>(this)->do_find(key); // NOLINT(cppcoreguidelines-pro-type-const-cast)
  988. }
  989. template <typename K, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  990. auto do_at(K const& key) -> Q& {
  991. if (auto it = find(key); ANKERL_UNORDERED_DENSE_LIKELY(end() != it)) {
  992. return it->second;
  993. }
  994. on_error_key_not_found();
  995. }
  996. template <typename K, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  997. auto do_at(K const& key) const -> Q const& {
  998. return const_cast<table*>(this)->at(key); // NOLINT(cppcoreguidelines-pro-type-const-cast)
  999. }
  1000. public:
  1001. explicit table(size_t bucket_count,
  1002. Hash const& hash = Hash(),
  1003. KeyEqual const& equal = KeyEqual(),
  1004. allocator_type const& alloc_or_container = allocator_type())
  1005. : m_values(alloc_or_container)
  1006. , m_hash(hash)
  1007. , m_equal(equal) {
  1008. if (0 != bucket_count) {
  1009. reserve(bucket_count);
  1010. } else {
  1011. allocate_buckets_from_shift();
  1012. clear_buckets();
  1013. }
  1014. }
  1015. table()
  1016. : table(0) {}
  1017. table(size_t bucket_count, allocator_type const& alloc)
  1018. : table(bucket_count, Hash(), KeyEqual(), alloc) {}
  1019. table(size_t bucket_count, Hash const& hash, allocator_type const& alloc)
  1020. : table(bucket_count, hash, KeyEqual(), alloc) {}
  1021. explicit table(allocator_type const& alloc)
  1022. : table(0, Hash(), KeyEqual(), alloc) {}
  1023. template <class InputIt>
  1024. table(InputIt first,
  1025. InputIt last,
  1026. size_type bucket_count = 0,
  1027. Hash const& hash = Hash(),
  1028. KeyEqual const& equal = KeyEqual(),
  1029. allocator_type const& alloc = allocator_type())
  1030. : table(bucket_count, hash, equal, alloc) {
  1031. insert(first, last);
  1032. }
  1033. template <class InputIt>
  1034. table(InputIt first, InputIt last, size_type bucket_count, allocator_type const& alloc)
  1035. : table(first, last, bucket_count, Hash(), KeyEqual(), alloc) {}
  1036. template <class InputIt>
  1037. table(InputIt first, InputIt last, size_type bucket_count, Hash const& hash, allocator_type const& alloc)
  1038. : table(first, last, bucket_count, hash, KeyEqual(), alloc) {}
  1039. table(table const& other)
  1040. : table(other, other.m_values.get_allocator()) {}
  1041. table(table const& other, allocator_type const& alloc)
  1042. : m_values(other.m_values, alloc)
  1043. , m_max_load_factor(other.m_max_load_factor)
  1044. , m_hash(other.m_hash)
  1045. , m_equal(other.m_equal) {
  1046. copy_buckets(other);
  1047. }
  1048. table(table&& other) noexcept
  1049. : table(std::move(other), other.m_values.get_allocator()) {}
  1050. table(table&& other, allocator_type const& alloc) noexcept
  1051. : m_values(alloc) {
  1052. *this = std::move(other);
  1053. }
  1054. table(std::initializer_list<value_type> ilist,
  1055. size_t bucket_count = 0,
  1056. Hash const& hash = Hash(),
  1057. KeyEqual const& equal = KeyEqual(),
  1058. allocator_type const& alloc = allocator_type())
  1059. : table(bucket_count, hash, equal, alloc) {
  1060. insert(ilist);
  1061. }
  1062. table(std::initializer_list<value_type> ilist, size_type bucket_count, allocator_type const& alloc)
  1063. : table(ilist, bucket_count, Hash(), KeyEqual(), alloc) {}
  1064. table(std::initializer_list<value_type> init, size_type bucket_count, Hash const& hash, allocator_type const& alloc)
  1065. : table(init, bucket_count, hash, KeyEqual(), alloc) {}
  1066. ~table() {
  1067. if (nullptr != m_buckets) {
  1068. auto ba = bucket_alloc(m_values.get_allocator());
  1069. bucket_alloc_traits::deallocate(ba, m_buckets, bucket_count());
  1070. }
  1071. }
  1072. auto operator=(table const& other) -> table& {
  1073. if (&other != this) {
  1074. deallocate_buckets(); // deallocate before m_values is set (might have another allocator)
  1075. m_values = other.m_values;
  1076. m_max_load_factor = other.m_max_load_factor;
  1077. m_hash = other.m_hash;
  1078. m_equal = other.m_equal;
  1079. m_shifts = initial_shifts;
  1080. copy_buckets(other);
  1081. }
  1082. return *this;
  1083. }
  1084. auto operator=(table&& other) noexcept(noexcept(std::is_nothrow_move_assignable_v<value_container_type> &&
  1085. std::is_nothrow_move_assignable_v<Hash> &&
  1086. std::is_nothrow_move_assignable_v<KeyEqual>)) -> table& {
  1087. if (&other != this) {
  1088. deallocate_buckets(); // deallocate before m_values is set (might have another allocator)
  1089. m_values = std::move(other.m_values);
  1090. other.m_values.clear();
  1091. // we can only reuse m_buckets when both maps have the same allocator!
  1092. if (get_allocator() == other.get_allocator()) {
  1093. m_buckets = std::exchange(other.m_buckets, nullptr);
  1094. m_num_buckets = std::exchange(other.m_num_buckets, 0);
  1095. m_max_bucket_capacity = std::exchange(other.m_max_bucket_capacity, 0);
  1096. m_shifts = std::exchange(other.m_shifts, initial_shifts);
  1097. m_max_load_factor = std::exchange(other.m_max_load_factor, default_max_load_factor);
  1098. m_hash = std::exchange(other.m_hash, {});
  1099. m_equal = std::exchange(other.m_equal, {});
  1100. other.allocate_buckets_from_shift();
  1101. other.clear_buckets();
  1102. } else {
  1103. // set max_load_factor *before* copying the other's buckets, so we have the same
  1104. // behavior
  1105. m_max_load_factor = other.m_max_load_factor;
  1106. // copy_buckets sets m_buckets, m_num_buckets, m_max_bucket_capacity, m_shifts
  1107. copy_buckets(other);
  1108. // clear's the other's buckets so other is now already usable.
  1109. other.clear_buckets();
  1110. m_hash = other.m_hash;
  1111. m_equal = other.m_equal;
  1112. }
  1113. // map "other" is now already usable, it's empty.
  1114. }
  1115. return *this;
  1116. }
  1117. auto operator=(std::initializer_list<value_type> ilist) -> table& {
  1118. clear();
  1119. insert(ilist);
  1120. return *this;
  1121. }
  1122. auto get_allocator() const noexcept -> allocator_type {
  1123. return m_values.get_allocator();
  1124. }
  1125. // iterators //////////////////////////////////////////////////////////////
  1126. auto begin() noexcept -> iterator {
  1127. return m_values.begin();
  1128. }
  1129. auto begin() const noexcept -> const_iterator {
  1130. return m_values.begin();
  1131. }
  1132. auto cbegin() const noexcept -> const_iterator {
  1133. return m_values.cbegin();
  1134. }
  1135. auto end() noexcept -> iterator {
  1136. return m_values.end();
  1137. }
  1138. auto cend() const noexcept -> const_iterator {
  1139. return m_values.cend();
  1140. }
  1141. auto end() const noexcept -> const_iterator {
  1142. return m_values.end();
  1143. }
  1144. // capacity ///////////////////////////////////////////////////////////////
  1145. [[nodiscard]] auto empty() const noexcept -> bool {
  1146. return m_values.empty();
  1147. }
  1148. [[nodiscard]] auto size() const noexcept -> size_t {
  1149. return m_values.size();
  1150. }
  1151. [[nodiscard]] static constexpr auto max_size() noexcept -> size_t {
  1152. if constexpr ((std::numeric_limits<value_idx_type>::max)() == (std::numeric_limits<size_t>::max)()) {
  1153. return size_t{1} << (sizeof(value_idx_type) * 8 - 1);
  1154. } else {
  1155. return size_t{1} << (sizeof(value_idx_type) * 8);
  1156. }
  1157. }
  1158. // modifiers //////////////////////////////////////////////////////////////
  1159. void clear() {
  1160. m_values.clear();
  1161. clear_buckets();
  1162. }
  1163. auto insert(value_type const& value) -> std::pair<iterator, bool> {
  1164. return emplace(value);
  1165. }
  1166. auto insert(value_type&& value) -> std::pair<iterator, bool> {
  1167. return emplace(std::move(value));
  1168. }
  1169. template <class P, std::enable_if_t<std::is_constructible_v<value_type, P&&>, bool> = true>
  1170. auto insert(P&& value) -> std::pair<iterator, bool> {
  1171. return emplace(std::forward<P>(value));
  1172. }
  1173. auto insert(const_iterator /*hint*/, value_type const& value) -> iterator {
  1174. return insert(value).first;
  1175. }
  1176. auto insert(const_iterator /*hint*/, value_type&& value) -> iterator {
  1177. return insert(std::move(value)).first;
  1178. }
  1179. template <class P, std::enable_if_t<std::is_constructible_v<value_type, P&&>, bool> = true>
  1180. auto insert(const_iterator /*hint*/, P&& value) -> iterator {
  1181. return insert(std::forward<P>(value)).first;
  1182. }
  1183. template <class InputIt>
  1184. void insert(InputIt first, InputIt last) {
  1185. while (first != last) {
  1186. insert(*first);
  1187. ++first;
  1188. }
  1189. }
  1190. void insert(std::initializer_list<value_type> ilist) {
  1191. insert(ilist.begin(), ilist.end());
  1192. }
  1193. // nonstandard API: *this is emptied.
  1194. // Also see "A Standard flat_map" https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0429r9.pdf
  1195. auto extract() && -> value_container_type {
  1196. return std::move(m_values);
  1197. }
  1198. // nonstandard API:
  1199. // Discards the internally held container and replaces it with the one passed. Erases non-unique elements.
  1200. auto replace(value_container_type&& container) {
  1201. if (ANKERL_UNORDERED_DENSE_UNLIKELY(container.size() > max_size())) {
  1202. on_error_too_many_elements();
  1203. }
  1204. auto shifts = calc_shifts_for_size(container.size());
  1205. if (0 == m_num_buckets || shifts < m_shifts || container.get_allocator() != m_values.get_allocator()) {
  1206. m_shifts = shifts;
  1207. deallocate_buckets();
  1208. allocate_buckets_from_shift();
  1209. }
  1210. clear_buckets();
  1211. m_values = std::move(container);
  1212. // can't use clear_and_fill_buckets_from_values() because container elements might not be unique
  1213. auto value_idx = value_idx_type{};
  1214. // loop until we reach the end of the container. duplicated entries will be replaced with back().
  1215. while (value_idx != static_cast<value_idx_type>(m_values.size())) {
  1216. auto const& key = get_key(m_values[value_idx]);
  1217. auto hash = mixed_hash(key);
  1218. auto dist_and_fingerprint = dist_and_fingerprint_from_hash(hash);
  1219. auto bucket_idx = bucket_idx_from_hash(hash);
  1220. bool key_found = false;
  1221. while (true) {
  1222. auto const& bucket = at(m_buckets, bucket_idx);
  1223. if (dist_and_fingerprint > bucket.m_dist_and_fingerprint) {
  1224. break;
  1225. }
  1226. if (dist_and_fingerprint == bucket.m_dist_and_fingerprint &&
  1227. m_equal(key, get_key(m_values[bucket.m_value_idx]))) {
  1228. key_found = true;
  1229. break;
  1230. }
  1231. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  1232. bucket_idx = next(bucket_idx);
  1233. }
  1234. if (key_found) {
  1235. if (value_idx != static_cast<value_idx_type>(m_values.size() - 1)) {
  1236. m_values[value_idx] = std::move(m_values.back());
  1237. }
  1238. m_values.pop_back();
  1239. } else {
  1240. place_and_shift_up({dist_and_fingerprint, value_idx}, bucket_idx);
  1241. ++value_idx;
  1242. }
  1243. }
  1244. }
  1245. template <class M, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1246. auto insert_or_assign(Key const& key, M&& mapped) -> std::pair<iterator, bool> {
  1247. return do_insert_or_assign(key, std::forward<M>(mapped));
  1248. }
  1249. template <class M, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1250. auto insert_or_assign(Key&& key, M&& mapped) -> std::pair<iterator, bool> {
  1251. return do_insert_or_assign(std::move(key), std::forward<M>(mapped));
  1252. }
  1253. template <typename K,
  1254. typename M,
  1255. typename Q = T,
  1256. typename H = Hash,
  1257. typename KE = KeyEqual,
  1258. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE>, bool> = true>
  1259. auto insert_or_assign(K&& key, M&& mapped) -> std::pair<iterator, bool> {
  1260. return do_insert_or_assign(std::forward<K>(key), std::forward<M>(mapped));
  1261. }
  1262. template <class M, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1263. auto insert_or_assign(const_iterator /*hint*/, Key const& key, M&& mapped) -> iterator {
  1264. return do_insert_or_assign(key, std::forward<M>(mapped)).first;
  1265. }
  1266. template <class M, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1267. auto insert_or_assign(const_iterator /*hint*/, Key&& key, M&& mapped) -> iterator {
  1268. return do_insert_or_assign(std::move(key), std::forward<M>(mapped)).first;
  1269. }
  1270. template <typename K,
  1271. typename M,
  1272. typename Q = T,
  1273. typename H = Hash,
  1274. typename KE = KeyEqual,
  1275. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE>, bool> = true>
  1276. auto insert_or_assign(const_iterator /*hint*/, K&& key, M&& mapped) -> iterator {
  1277. return do_insert_or_assign(std::forward<K>(key), std::forward<M>(mapped)).first;
  1278. }
  1279. // Single arguments for unordered_set can be used without having to construct the value_type
  1280. template <class K,
  1281. typename Q = T,
  1282. typename H = Hash,
  1283. typename KE = KeyEqual,
  1284. std::enable_if_t<!is_map_v<Q> && is_transparent_v<H, KE>, bool> = true>
  1285. auto emplace(K&& key) -> std::pair<iterator, bool> {
  1286. auto hash = mixed_hash(key);
  1287. auto dist_and_fingerprint = dist_and_fingerprint_from_hash(hash);
  1288. auto bucket_idx = bucket_idx_from_hash(hash);
  1289. while (dist_and_fingerprint <= at(m_buckets, bucket_idx).m_dist_and_fingerprint) {
  1290. if (dist_and_fingerprint == at(m_buckets, bucket_idx).m_dist_and_fingerprint &&
  1291. m_equal(key, m_values[at(m_buckets, bucket_idx).m_value_idx])) {
  1292. // found it, return without ever actually creating anything
  1293. return {begin() + static_cast<difference_type>(at(m_buckets, bucket_idx).m_value_idx), false};
  1294. }
  1295. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  1296. bucket_idx = next(bucket_idx);
  1297. }
  1298. // value is new, insert element first, so when exception happens we are in a valid state
  1299. return do_place_element(dist_and_fingerprint, bucket_idx, std::forward<K>(key));
  1300. }
  1301. template <class... Args>
  1302. auto emplace(Args&&... args) -> std::pair<iterator, bool> {
  1303. // we have to instantiate the value_type to be able to access the key.
  1304. // 1. emplace_back the object so it is constructed. 2. If the key is already there, pop it later in the loop.
  1305. auto& key = get_key(m_values.emplace_back(std::forward<Args>(args)...));
  1306. auto hash = mixed_hash(key);
  1307. auto dist_and_fingerprint = dist_and_fingerprint_from_hash(hash);
  1308. auto bucket_idx = bucket_idx_from_hash(hash);
  1309. while (dist_and_fingerprint <= at(m_buckets, bucket_idx).m_dist_and_fingerprint) {
  1310. if (dist_and_fingerprint == at(m_buckets, bucket_idx).m_dist_and_fingerprint &&
  1311. m_equal(key, get_key(m_values[at(m_buckets, bucket_idx).m_value_idx]))) {
  1312. m_values.pop_back(); // value was already there, so get rid of it
  1313. return {begin() + static_cast<difference_type>(at(m_buckets, bucket_idx).m_value_idx), false};
  1314. }
  1315. dist_and_fingerprint = dist_inc(dist_and_fingerprint);
  1316. bucket_idx = next(bucket_idx);
  1317. }
  1318. // value is new, place the bucket and shift up until we find an empty spot
  1319. auto value_idx = static_cast<value_idx_type>(m_values.size() - 1);
  1320. if (ANKERL_UNORDERED_DENSE_UNLIKELY(is_full())) {
  1321. // increase_size just rehashes all the data we have in m_values
  1322. increase_size();
  1323. } else {
  1324. // place element and shift up until we find an empty spot
  1325. place_and_shift_up({dist_and_fingerprint, value_idx}, bucket_idx);
  1326. }
  1327. return {begin() + static_cast<difference_type>(value_idx), true};
  1328. }
  1329. template <class... Args>
  1330. auto emplace_hint(const_iterator /*hint*/, Args&&... args) -> iterator {
  1331. return emplace(std::forward<Args>(args)...).first;
  1332. }
  1333. template <class... Args, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1334. auto try_emplace(Key const& key, Args&&... args) -> std::pair<iterator, bool> {
  1335. return do_try_emplace(key, std::forward<Args>(args)...);
  1336. }
  1337. template <class... Args, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1338. auto try_emplace(Key&& key, Args&&... args) -> std::pair<iterator, bool> {
  1339. return do_try_emplace(std::move(key), std::forward<Args>(args)...);
  1340. }
  1341. template <class... Args, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1342. auto try_emplace(const_iterator /*hint*/, Key const& key, Args&&... args) -> iterator {
  1343. return do_try_emplace(key, std::forward<Args>(args)...).first;
  1344. }
  1345. template <class... Args, typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1346. auto try_emplace(const_iterator /*hint*/, Key&& key, Args&&... args) -> iterator {
  1347. return do_try_emplace(std::move(key), std::forward<Args>(args)...).first;
  1348. }
  1349. template <
  1350. typename K,
  1351. typename... Args,
  1352. typename Q = T,
  1353. typename H = Hash,
  1354. typename KE = KeyEqual,
  1355. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE> && is_neither_convertible_v<K&&, iterator, const_iterator>,
  1356. bool> = true>
  1357. auto try_emplace(K&& key, Args&&... args) -> std::pair<iterator, bool> {
  1358. return do_try_emplace(std::forward<K>(key), std::forward<Args>(args)...);
  1359. }
  1360. template <
  1361. typename K,
  1362. typename... Args,
  1363. typename Q = T,
  1364. typename H = Hash,
  1365. typename KE = KeyEqual,
  1366. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE> && is_neither_convertible_v<K&&, iterator, const_iterator>,
  1367. bool> = true>
  1368. auto try_emplace(const_iterator /*hint*/, K&& key, Args&&... args) -> iterator {
  1369. return do_try_emplace(std::forward<K>(key), std::forward<Args>(args)...).first;
  1370. }
  1371. auto erase(iterator it) -> iterator {
  1372. auto hash = mixed_hash(get_key(*it));
  1373. auto bucket_idx = bucket_idx_from_hash(hash);
  1374. auto const value_idx_to_remove = static_cast<value_idx_type>(it - cbegin());
  1375. while (at(m_buckets, bucket_idx).m_value_idx != value_idx_to_remove) {
  1376. bucket_idx = next(bucket_idx);
  1377. }
  1378. do_erase(bucket_idx, [](value_type&& /*unused*/) {
  1379. });
  1380. return begin() + static_cast<difference_type>(value_idx_to_remove);
  1381. }
  1382. auto extract(iterator it) -> value_type {
  1383. auto hash = mixed_hash(get_key(*it));
  1384. auto bucket_idx = bucket_idx_from_hash(hash);
  1385. auto const value_idx_to_remove = static_cast<value_idx_type>(it - cbegin());
  1386. while (at(m_buckets, bucket_idx).m_value_idx != value_idx_to_remove) {
  1387. bucket_idx = next(bucket_idx);
  1388. }
  1389. auto tmp = std::optional<value_type>{};
  1390. do_erase(bucket_idx, [&tmp](value_type&& val) {
  1391. tmp = std::move(val);
  1392. });
  1393. return std::move(tmp).value();
  1394. }
  1395. template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1396. auto erase(const_iterator it) -> iterator {
  1397. return erase(begin() + (it - cbegin()));
  1398. }
  1399. template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1400. auto extract(const_iterator it) -> value_type {
  1401. return extract(begin() + (it - cbegin()));
  1402. }
  1403. auto erase(const_iterator first, const_iterator last) -> iterator {
  1404. auto const idx_first = first - cbegin();
  1405. auto const idx_last = last - cbegin();
  1406. auto const first_to_last = std::distance(first, last);
  1407. auto const last_to_end = std::distance(last, cend());
  1408. // remove elements from left to right which moves elements from the end back
  1409. auto const mid = idx_first + (std::min)(first_to_last, last_to_end);
  1410. auto idx = idx_first;
  1411. while (idx != mid) {
  1412. erase(begin() + idx);
  1413. ++idx;
  1414. }
  1415. // all elements from the right are moved, now remove the last element until all done
  1416. idx = idx_last;
  1417. while (idx != mid) {
  1418. --idx;
  1419. erase(begin() + idx);
  1420. }
  1421. return begin() + idx_first;
  1422. }
  1423. auto erase(Key const& key) -> size_t {
  1424. return do_erase_key(key, [](value_type&& /*unused*/) {
  1425. });
  1426. }
  1427. auto extract(Key const& key) -> std::optional<value_type> {
  1428. auto tmp = std::optional<value_type>{};
  1429. do_erase_key(key, [&tmp](value_type&& val) {
  1430. tmp = std::move(val);
  1431. });
  1432. return tmp;
  1433. }
  1434. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1435. auto erase(K&& key) -> size_t {
  1436. return do_erase_key(std::forward<K>(key), [](value_type&& /*unused*/) {
  1437. });
  1438. }
  1439. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1440. auto extract(K&& key) -> std::optional<value_type> {
  1441. auto tmp = std::optional<value_type>{};
  1442. do_erase_key(std::forward<K>(key), [&tmp](value_type&& val) {
  1443. tmp = std::move(val);
  1444. });
  1445. return tmp;
  1446. }
  1447. void swap(table& other) noexcept(noexcept(std::is_nothrow_swappable_v<value_container_type> &&
  1448. std::is_nothrow_swappable_v<Hash> && std::is_nothrow_swappable_v<KeyEqual>)) {
  1449. using std::swap;
  1450. swap(other, *this);
  1451. }
  1452. // lookup /////////////////////////////////////////////////////////////////
  1453. template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1454. auto at(key_type const& key) -> Q& {
  1455. return do_at(key);
  1456. }
  1457. template <typename K,
  1458. typename Q = T,
  1459. typename H = Hash,
  1460. typename KE = KeyEqual,
  1461. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE>, bool> = true>
  1462. auto at(K const& key) -> Q& {
  1463. return do_at(key);
  1464. }
  1465. template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1466. auto at(key_type const& key) const -> Q const& {
  1467. return do_at(key);
  1468. }
  1469. template <typename K,
  1470. typename Q = T,
  1471. typename H = Hash,
  1472. typename KE = KeyEqual,
  1473. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE>, bool> = true>
  1474. auto at(K const& key) const -> Q const& {
  1475. return do_at(key);
  1476. }
  1477. template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1478. auto operator[](Key const& key) -> Q& {
  1479. return try_emplace(key).first->second;
  1480. }
  1481. template <typename Q = T, std::enable_if_t<is_map_v<Q>, bool> = true>
  1482. auto operator[](Key&& key) -> Q& {
  1483. return try_emplace(std::move(key)).first->second;
  1484. }
  1485. template <typename K,
  1486. typename Q = T,
  1487. typename H = Hash,
  1488. typename KE = KeyEqual,
  1489. std::enable_if_t<is_map_v<Q> && is_transparent_v<H, KE>, bool> = true>
  1490. auto operator[](K&& key) -> Q& {
  1491. return try_emplace(std::forward<K>(key)).first->second;
  1492. }
  1493. auto count(Key const& key) const -> size_t {
  1494. return find(key) == end() ? 0 : 1;
  1495. }
  1496. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1497. auto count(K const& key) const -> size_t {
  1498. return find(key) == end() ? 0 : 1;
  1499. }
  1500. auto find(Key const& key) -> iterator {
  1501. return do_find(key);
  1502. }
  1503. auto find(Key const& key) const -> const_iterator {
  1504. return do_find(key);
  1505. }
  1506. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1507. auto find(K const& key) -> iterator {
  1508. return do_find(key);
  1509. }
  1510. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1511. auto find(K const& key) const -> const_iterator {
  1512. return do_find(key);
  1513. }
  1514. auto contains(Key const& key) const -> bool {
  1515. return find(key) != end();
  1516. }
  1517. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1518. auto contains(K const& key) const -> bool {
  1519. return find(key) != end();
  1520. }
  1521. auto equal_range(Key const& key) -> std::pair<iterator, iterator> {
  1522. auto it = do_find(key);
  1523. return {it, it == end() ? end() : it + 1};
  1524. }
  1525. auto equal_range(const Key& key) const -> std::pair<const_iterator, const_iterator> {
  1526. auto it = do_find(key);
  1527. return {it, it == end() ? end() : it + 1};
  1528. }
  1529. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1530. auto equal_range(K const& key) -> std::pair<iterator, iterator> {
  1531. auto it = do_find(key);
  1532. return {it, it == end() ? end() : it + 1};
  1533. }
  1534. template <class K, class H = Hash, class KE = KeyEqual, std::enable_if_t<is_transparent_v<H, KE>, bool> = true>
  1535. auto equal_range(K const& key) const -> std::pair<const_iterator, const_iterator> {
  1536. auto it = do_find(key);
  1537. return {it, it == end() ? end() : it + 1};
  1538. }
  1539. // bucket interface ///////////////////////////////////////////////////////
  1540. auto bucket_count() const noexcept -> size_t { // NOLINT(modernize-use-nodiscard)
  1541. return m_num_buckets;
  1542. }
  1543. static constexpr auto max_bucket_count() noexcept -> size_t { // NOLINT(modernize-use-nodiscard)
  1544. return max_size();
  1545. }
  1546. // hash policy ////////////////////////////////////////////////////////////
  1547. [[nodiscard]] auto load_factor() const -> float {
  1548. return bucket_count() ? static_cast<float>(size()) / static_cast<float>(bucket_count()) : 0.0F;
  1549. }
  1550. [[nodiscard]] auto max_load_factor() const -> float {
  1551. return m_max_load_factor;
  1552. }
  1553. void max_load_factor(float ml) {
  1554. m_max_load_factor = ml;
  1555. if (m_num_buckets != max_bucket_count()) {
  1556. m_max_bucket_capacity = static_cast<value_idx_type>(static_cast<float>(bucket_count()) * max_load_factor());
  1557. }
  1558. }
  1559. void rehash(size_t count) {
  1560. count = (std::min)(count, max_size());
  1561. auto shifts = calc_shifts_for_size((std::max)(count, size()));
  1562. if (shifts != m_shifts) {
  1563. m_shifts = shifts;
  1564. deallocate_buckets();
  1565. m_values.shrink_to_fit();
  1566. allocate_buckets_from_shift();
  1567. clear_and_fill_buckets_from_values();
  1568. }
  1569. }
  1570. void reserve(size_t capa) {
  1571. capa = (std::min)(capa, max_size());
  1572. if constexpr (has_reserve<value_container_type>) {
  1573. // std::deque doesn't have reserve(). Make sure we only call when available
  1574. m_values.reserve(capa);
  1575. }
  1576. auto shifts = calc_shifts_for_size((std::max)(capa, size()));
  1577. if (0 == m_num_buckets || shifts < m_shifts) {
  1578. m_shifts = shifts;
  1579. deallocate_buckets();
  1580. allocate_buckets_from_shift();
  1581. clear_and_fill_buckets_from_values();
  1582. }
  1583. }
  1584. // observers //////////////////////////////////////////////////////////////
  1585. auto hash_function() const -> hasher {
  1586. return m_hash;
  1587. }
  1588. auto key_eq() const -> key_equal {
  1589. return m_equal;
  1590. }
  1591. // nonstandard API: expose the underlying values container
  1592. [[nodiscard]] auto values() const noexcept -> value_container_type const& {
  1593. return m_values;
  1594. }
  1595. // non-member functions ///////////////////////////////////////////////////
  1596. friend auto operator==(table const& a, table const& b) -> bool {
  1597. if (&a == &b) {
  1598. return true;
  1599. }
  1600. if (a.size() != b.size()) {
  1601. return false;
  1602. }
  1603. for (auto const& b_entry : b) {
  1604. auto it = a.find(get_key(b_entry));
  1605. if constexpr (is_map_v<T>) {
  1606. // map: check that key is here, then also check that value is the same
  1607. if (a.end() == it || !(b_entry.second == it->second)) {
  1608. return false;
  1609. }
  1610. } else {
  1611. // set: only check that the key is here
  1612. if (a.end() == it) {
  1613. return false;
  1614. }
  1615. }
  1616. }
  1617. return true;
  1618. }
  1619. friend auto operator!=(table const& a, table const& b) -> bool {
  1620. return !(a == b);
  1621. }
  1622. };
  1623. } // namespace detail
  1624. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1625. class T,
  1626. class Hash = hash<Key>,
  1627. class KeyEqual = std::equal_to<Key>,
  1628. class AllocatorOrContainer = std::allocator<std::pair<Key, T>>,
  1629. class Bucket = bucket_type::standard>
  1630. using map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
  1631. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1632. class T,
  1633. class Hash = hash<Key>,
  1634. class KeyEqual = std::equal_to<Key>,
  1635. class AllocatorOrContainer = std::allocator<std::pair<Key, T>>,
  1636. class Bucket = bucket_type::standard>
  1637. using segmented_map = detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>;
  1638. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1639. class Hash = hash<Key>,
  1640. class KeyEqual = std::equal_to<Key>,
  1641. class AllocatorOrContainer = std::allocator<Key>,
  1642. class Bucket = bucket_type::standard>
  1643. using set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, false>;
  1644. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1645. class Hash = hash<Key>,
  1646. class KeyEqual = std::equal_to<Key>,
  1647. class AllocatorOrContainer = std::allocator<Key>,
  1648. class Bucket = bucket_type::standard>
  1649. using segmented_set = detail::table<Key, void, Hash, KeyEqual, AllocatorOrContainer, Bucket, true>;
  1650. # if defined(ANKERL_UNORDERED_DENSE_PMR)
  1651. namespace pmr {
  1652. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1653. class T,
  1654. class Hash = hash<Key>,
  1655. class KeyEqual = std::equal_to<Key>,
  1656. class Bucket = bucket_type::standard>
  1657. using map =
  1658. detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, false>;
  1659. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1660. class T,
  1661. class Hash = hash<Key>,
  1662. class KeyEqual = std::equal_to<Key>,
  1663. class Bucket = bucket_type::standard>
  1664. using segmented_map =
  1665. detail::table<Key, T, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<std::pair<Key, T>>, Bucket, true>;
  1666. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1667. class Hash = hash<Key>,
  1668. class KeyEqual = std::equal_to<Key>,
  1669. class Bucket = bucket_type::standard>
  1670. using set = detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, false>;
  1671. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1672. class Hash = hash<Key>,
  1673. class KeyEqual = std::equal_to<Key>,
  1674. class Bucket = bucket_type::standard>
  1675. using segmented_set =
  1676. detail::table<Key, void, Hash, KeyEqual, ANKERL_UNORDERED_DENSE_PMR::polymorphic_allocator<Key>, Bucket, true>;
  1677. } // namespace pmr
  1678. # endif
  1679. // deduction guides ///////////////////////////////////////////////////////////
  1680. // deduction guides for alias templates are only possible since C++20
  1681. // see https://en.cppreference.com/w/cpp/language/class_template_argument_deduction
  1682. } // namespace ANKERL_UNORDERED_DENSE_NAMESPACE
  1683. } // namespace ankerl::unordered_dense
  1684. // std extensions /////////////////////////////////////////////////////////////
  1685. namespace std { // NOLINT(cert-dcl58-cpp)
  1686. ANKERL_UNORDERED_DENSE_EXPORT template <class Key,
  1687. class T,
  1688. class Hash,
  1689. class KeyEqual,
  1690. class AllocatorOrContainer,
  1691. class Bucket,
  1692. class Pred,
  1693. bool IsSegmented>
  1694. // NOLINTNEXTLINE(cert-dcl58-cpp)
  1695. auto erase_if(ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>& map,
  1696. Pred pred) -> size_t {
  1697. using map_t = ankerl::unordered_dense::detail::table<Key, T, Hash, KeyEqual, AllocatorOrContainer, Bucket, IsSegmented>;
  1698. // going back to front because erase() invalidates the end iterator
  1699. auto const old_size = map.size();
  1700. auto idx = old_size;
  1701. while (idx) {
  1702. --idx;
  1703. auto it = map.begin() + static_cast<typename map_t::difference_type>(idx);
  1704. if (pred(*it)) {
  1705. map.erase(it);
  1706. }
  1707. }
  1708. return old_size - map.size();
  1709. }
  1710. } // namespace std
  1711. #endif
  1712. #endif