File indexing completed on 2025-01-18 09:53:19
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #ifndef BOOST_UNORDERED_DETAIL_FOA_CORE_HPP
0013 #define BOOST_UNORDERED_DETAIL_FOA_CORE_HPP
0014
0015 #include <boost/assert.hpp>
0016 #include <boost/config.hpp>
0017 #include <boost/config/workaround.hpp>
0018 #include <boost/core/allocator_traits.hpp>
0019 #include <boost/core/bit.hpp>
0020 #include <boost/core/empty_value.hpp>
0021 #include <boost/core/no_exceptions_support.hpp>
0022 #include <boost/core/pointer_traits.hpp>
0023 #include <boost/cstdint.hpp>
0024 #include <boost/predef.h>
0025 #include <boost/unordered/detail/narrow_cast.hpp>
0026 #include <boost/unordered/detail/mulx.hpp>
0027 #include <boost/unordered/detail/static_assert.hpp>
0028 #include <boost/unordered/detail/type_traits.hpp>
0029 #include <boost/unordered/hash_traits.hpp>
0030 #include <climits>
0031 #include <cmath>
0032 #include <cstddef>
0033 #include <cstring>
0034 #include <limits>
0035 #include <memory>
0036 #include <new>
0037 #include <tuple>
0038 #include <type_traits>
0039 #include <utility>
0040
0041 #if !defined(BOOST_UNORDERED_DISABLE_SSE2)
0042 #if defined(BOOST_UNORDERED_ENABLE_SSE2)|| \
0043 defined(__SSE2__)|| \
0044 defined(_M_X64)||(defined(_M_IX86_FP)&&_M_IX86_FP>=2)
0045 #define BOOST_UNORDERED_SSE2
0046 #endif
0047 #endif
0048
0049 #if !defined(BOOST_UNORDERED_DISABLE_NEON)
0050 #if defined(BOOST_UNORDERED_ENABLE_NEON)||\
0051 (defined(__ARM_NEON)&&!defined(__ARM_BIG_ENDIAN))
0052 #define BOOST_UNORDERED_LITTLE_ENDIAN_NEON
0053 #endif
0054 #endif
0055
0056 #if defined(BOOST_UNORDERED_SSE2)
0057 #include <emmintrin.h>
0058 #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON)
0059 #include <arm_neon.h>
0060 #endif
0061
0062 #ifdef __has_builtin
0063 #define BOOST_UNORDERED_HAS_BUILTIN(x) __has_builtin(x)
0064 #else
0065 #define BOOST_UNORDERED_HAS_BUILTIN(x) 0
0066 #endif
0067
0068 #if !defined(NDEBUG)
0069 #define BOOST_UNORDERED_ASSUME(cond) BOOST_ASSERT(cond)
0070 #elif BOOST_UNORDERED_HAS_BUILTIN(__builtin_assume)
0071 #define BOOST_UNORDERED_ASSUME(cond) __builtin_assume(cond)
0072 #elif defined(__GNUC__) || BOOST_UNORDERED_HAS_BUILTIN(__builtin_unreachable)
0073 #define BOOST_UNORDERED_ASSUME(cond) \
0074 do{ \
0075 if(!(cond))__builtin_unreachable(); \
0076 }while(0)
0077 #elif defined(_MSC_VER)
0078 #define BOOST_UNORDERED_ASSUME(cond) __assume(cond)
0079 #else
0080 #define BOOST_UNORDERED_ASSUME(cond) \
0081 do{ \
0082 static_cast<void>(false&&(cond)); \
0083 }while(0)
0084 #endif
0085
0086
0087
0088
0089
0090 #if defined(BOOST_GCC)||defined(BOOST_CLANG)
0091 #define BOOST_UNORDERED_PREFETCH(p) __builtin_prefetch((const char*)(p))
0092 #elif defined(BOOST_UNORDERED_SSE2)
0093 #define BOOST_UNORDERED_PREFETCH(p) _mm_prefetch((const char*)(p),_MM_HINT_T0)
0094 #else
0095 #define BOOST_UNORDERED_PREFETCH(p) ((void)(p))
0096 #endif
0097
0098
0099
0100
0101
0102
0103
0104
0105 #if BOOST_ARCH_ARM
0106
0107
0108
0109
0110 #define BOOST_UNORDERED_PREFETCH_ELEMENTS(p,N) \
0111 do{ \
0112 auto BOOST_UNORDERED_P=(p); \
0113 constexpr int cache_line=64; \
0114 const char *p0=reinterpret_cast<const char*>(BOOST_UNORDERED_P), \
0115 *p1=p0+sizeof(*BOOST_UNORDERED_P)*(N)/2; \
0116 for(;p0<p1;p0+=cache_line)BOOST_UNORDERED_PREFETCH(p0); \
0117 }while(0)
0118 #else
0119 #define BOOST_UNORDERED_PREFETCH_ELEMENTS(p,N) BOOST_UNORDERED_PREFETCH(p)
0120 #endif
0121
0122 #ifdef __has_feature
0123 #define BOOST_UNORDERED_HAS_FEATURE(x) __has_feature(x)
0124 #else
0125 #define BOOST_UNORDERED_HAS_FEATURE(x) 0
0126 #endif
0127
0128 #if BOOST_UNORDERED_HAS_FEATURE(thread_sanitizer)|| \
0129 defined(__SANITIZE_THREAD__)
0130 #define BOOST_UNORDERED_THREAD_SANITIZER
0131 #endif
0132
0133 #define BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred) \
0134 static_assert(boost::unordered::detail::is_nothrow_swappable<Hash>::value, \
0135 "Template parameter Hash is required to be nothrow Swappable."); \
0136 static_assert(boost::unordered::detail::is_nothrow_swappable<Pred>::value, \
0137 "Template parameter Pred is required to be nothrow Swappable");
0138
0139 namespace boost{
0140 namespace unordered{
0141 namespace detail{
0142 namespace foa{
0143
0144 static constexpr std::size_t default_bucket_count=0;
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168
0169
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193
0194
0195
0196
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210 #if defined(BOOST_UNORDERED_SSE2)
0211
0212 template<template<typename> class IntegralWrapper>
0213 struct group15
0214 {
0215 static constexpr std::size_t N=15;
0216 static constexpr bool regular_layout=true;
0217
0218 struct dummy_group_type
0219 {
0220 alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0};
0221 };
0222
0223 inline void initialize()
0224 {
0225 _mm_store_si128(
0226 reinterpret_cast<__m128i*>(m),_mm_setzero_si128());
0227 }
0228
0229 inline void set(std::size_t pos,std::size_t hash)
0230 {
0231 BOOST_ASSERT(pos<N);
0232 at(pos)=reduced_hash(hash);
0233 }
0234
0235 inline void set_sentinel()
0236 {
0237 at(N-1)=sentinel_;
0238 }
0239
0240 inline bool is_sentinel(std::size_t pos)const
0241 {
0242 BOOST_ASSERT(pos<N);
0243 return at(pos)==sentinel_;
0244 }
0245
0246 static inline bool is_sentinel(unsigned char* pc)noexcept
0247 {
0248 return *pc==sentinel_;
0249 }
0250
0251 inline void reset(std::size_t pos)
0252 {
0253 BOOST_ASSERT(pos<N);
0254 at(pos)=available_;
0255 }
0256
0257 static inline void reset(unsigned char* pc)
0258 {
0259 *reinterpret_cast<slot_type*>(pc)=available_;
0260 }
0261
0262 inline int match(std::size_t hash)const
0263 {
0264 return _mm_movemask_epi8(
0265 _mm_cmpeq_epi8(load_metadata(),_mm_set1_epi32(match_word(hash))))&0x7FFF;
0266 }
0267
0268 inline bool is_not_overflowed(std::size_t hash)const
0269 {
0270 static constexpr unsigned char shift[]={1,2,4,8,16,32,64,128};
0271
0272 return !(overflow()&shift[hash%8]);
0273 }
0274
0275 inline void mark_overflow(std::size_t hash)
0276 {
0277 overflow()|=static_cast<unsigned char>(1<<(hash%8));
0278 }
0279
0280 static inline bool maybe_caused_overflow(unsigned char* pc)
0281 {
0282 std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
0283 group15 *pg=reinterpret_cast<group15*>(pc-pos);
0284 return !pg->is_not_overflowed(*pc);
0285 }
0286
0287 inline int match_available()const
0288 {
0289 return _mm_movemask_epi8(
0290 _mm_cmpeq_epi8(load_metadata(),_mm_setzero_si128()))&0x7FFF;
0291 }
0292
0293 inline bool is_occupied(std::size_t pos)const
0294 {
0295 BOOST_ASSERT(pos<N);
0296 return at(pos)!=available_;
0297 }
0298
0299 static inline bool is_occupied(unsigned char* pc)noexcept
0300 {
0301 return *reinterpret_cast<slot_type*>(pc)!=available_;
0302 }
0303
0304 inline int match_occupied()const
0305 {
0306 return (~match_available())&0x7FFF;
0307 }
0308
0309 private:
0310 using slot_type=IntegralWrapper<unsigned char>;
0311 BOOST_UNORDERED_STATIC_ASSERT(sizeof(slot_type)==1);
0312
0313 static constexpr unsigned char available_=0,
0314 sentinel_=1;
0315
0316 inline __m128i load_metadata()const
0317 {
0318 #if defined(BOOST_UNORDERED_THREAD_SANITIZER)
0319
0320
0321
0322
0323 return _mm_set_epi8(
0324 (char)m[15],(char)m[14],(char)m[13],(char)m[12],
0325 (char)m[11],(char)m[10],(char)m[ 9],(char)m[ 8],
0326 (char)m[ 7],(char)m[ 6],(char)m[ 5],(char)m[ 4],
0327 (char)m[ 3],(char)m[ 2],(char)m[ 1],(char)m[ 0]);
0328 #else
0329 return _mm_load_si128(reinterpret_cast<const __m128i*>(m));
0330 #endif
0331 }
0332
0333 inline static int match_word(std::size_t hash)
0334 {
0335 static constexpr boost::uint32_t word[]=
0336 {
0337 0x08080808u,0x09090909u,0x02020202u,0x03030303u,0x04040404u,0x05050505u,
0338 0x06060606u,0x07070707u,0x08080808u,0x09090909u,0x0A0A0A0Au,0x0B0B0B0Bu,
0339 0x0C0C0C0Cu,0x0D0D0D0Du,0x0E0E0E0Eu,0x0F0F0F0Fu,0x10101010u,0x11111111u,
0340 0x12121212u,0x13131313u,0x14141414u,0x15151515u,0x16161616u,0x17171717u,
0341 0x18181818u,0x19191919u,0x1A1A1A1Au,0x1B1B1B1Bu,0x1C1C1C1Cu,0x1D1D1D1Du,
0342 0x1E1E1E1Eu,0x1F1F1F1Fu,0x20202020u,0x21212121u,0x22222222u,0x23232323u,
0343 0x24242424u,0x25252525u,0x26262626u,0x27272727u,0x28282828u,0x29292929u,
0344 0x2A2A2A2Au,0x2B2B2B2Bu,0x2C2C2C2Cu,0x2D2D2D2Du,0x2E2E2E2Eu,0x2F2F2F2Fu,
0345 0x30303030u,0x31313131u,0x32323232u,0x33333333u,0x34343434u,0x35353535u,
0346 0x36363636u,0x37373737u,0x38383838u,0x39393939u,0x3A3A3A3Au,0x3B3B3B3Bu,
0347 0x3C3C3C3Cu,0x3D3D3D3Du,0x3E3E3E3Eu,0x3F3F3F3Fu,0x40404040u,0x41414141u,
0348 0x42424242u,0x43434343u,0x44444444u,0x45454545u,0x46464646u,0x47474747u,
0349 0x48484848u,0x49494949u,0x4A4A4A4Au,0x4B4B4B4Bu,0x4C4C4C4Cu,0x4D4D4D4Du,
0350 0x4E4E4E4Eu,0x4F4F4F4Fu,0x50505050u,0x51515151u,0x52525252u,0x53535353u,
0351 0x54545454u,0x55555555u,0x56565656u,0x57575757u,0x58585858u,0x59595959u,
0352 0x5A5A5A5Au,0x5B5B5B5Bu,0x5C5C5C5Cu,0x5D5D5D5Du,0x5E5E5E5Eu,0x5F5F5F5Fu,
0353 0x60606060u,0x61616161u,0x62626262u,0x63636363u,0x64646464u,0x65656565u,
0354 0x66666666u,0x67676767u,0x68686868u,0x69696969u,0x6A6A6A6Au,0x6B6B6B6Bu,
0355 0x6C6C6C6Cu,0x6D6D6D6Du,0x6E6E6E6Eu,0x6F6F6F6Fu,0x70707070u,0x71717171u,
0356 0x72727272u,0x73737373u,0x74747474u,0x75757575u,0x76767676u,0x77777777u,
0357 0x78787878u,0x79797979u,0x7A7A7A7Au,0x7B7B7B7Bu,0x7C7C7C7Cu,0x7D7D7D7Du,
0358 0x7E7E7E7Eu,0x7F7F7F7Fu,0x80808080u,0x81818181u,0x82828282u,0x83838383u,
0359 0x84848484u,0x85858585u,0x86868686u,0x87878787u,0x88888888u,0x89898989u,
0360 0x8A8A8A8Au,0x8B8B8B8Bu,0x8C8C8C8Cu,0x8D8D8D8Du,0x8E8E8E8Eu,0x8F8F8F8Fu,
0361 0x90909090u,0x91919191u,0x92929292u,0x93939393u,0x94949494u,0x95959595u,
0362 0x96969696u,0x97979797u,0x98989898u,0x99999999u,0x9A9A9A9Au,0x9B9B9B9Bu,
0363 0x9C9C9C9Cu,0x9D9D9D9Du,0x9E9E9E9Eu,0x9F9F9F9Fu,0xA0A0A0A0u,0xA1A1A1A1u,
0364 0xA2A2A2A2u,0xA3A3A3A3u,0xA4A4A4A4u,0xA5A5A5A5u,0xA6A6A6A6u,0xA7A7A7A7u,
0365 0xA8A8A8A8u,0xA9A9A9A9u,0xAAAAAAAAu,0xABABABABu,0xACACACACu,0xADADADADu,
0366 0xAEAEAEAEu,0xAFAFAFAFu,0xB0B0B0B0u,0xB1B1B1B1u,0xB2B2B2B2u,0xB3B3B3B3u,
0367 0xB4B4B4B4u,0xB5B5B5B5u,0xB6B6B6B6u,0xB7B7B7B7u,0xB8B8B8B8u,0xB9B9B9B9u,
0368 0xBABABABAu,0xBBBBBBBBu,0xBCBCBCBCu,0xBDBDBDBDu,0xBEBEBEBEu,0xBFBFBFBFu,
0369 0xC0C0C0C0u,0xC1C1C1C1u,0xC2C2C2C2u,0xC3C3C3C3u,0xC4C4C4C4u,0xC5C5C5C5u,
0370 0xC6C6C6C6u,0xC7C7C7C7u,0xC8C8C8C8u,0xC9C9C9C9u,0xCACACACAu,0xCBCBCBCBu,
0371 0xCCCCCCCCu,0xCDCDCDCDu,0xCECECECEu,0xCFCFCFCFu,0xD0D0D0D0u,0xD1D1D1D1u,
0372 0xD2D2D2D2u,0xD3D3D3D3u,0xD4D4D4D4u,0xD5D5D5D5u,0xD6D6D6D6u,0xD7D7D7D7u,
0373 0xD8D8D8D8u,0xD9D9D9D9u,0xDADADADAu,0xDBDBDBDBu,0xDCDCDCDCu,0xDDDDDDDDu,
0374 0xDEDEDEDEu,0xDFDFDFDFu,0xE0E0E0E0u,0xE1E1E1E1u,0xE2E2E2E2u,0xE3E3E3E3u,
0375 0xE4E4E4E4u,0xE5E5E5E5u,0xE6E6E6E6u,0xE7E7E7E7u,0xE8E8E8E8u,0xE9E9E9E9u,
0376 0xEAEAEAEAu,0xEBEBEBEBu,0xECECECECu,0xEDEDEDEDu,0xEEEEEEEEu,0xEFEFEFEFu,
0377 0xF0F0F0F0u,0xF1F1F1F1u,0xF2F2F2F2u,0xF3F3F3F3u,0xF4F4F4F4u,0xF5F5F5F5u,
0378 0xF6F6F6F6u,0xF7F7F7F7u,0xF8F8F8F8u,0xF9F9F9F9u,0xFAFAFAFAu,0xFBFBFBFBu,
0379 0xFCFCFCFCu,0xFDFDFDFDu,0xFEFEFEFEu,0xFFFFFFFFu,
0380 };
0381
0382 return (int)word[narrow_cast<unsigned char>(hash)];
0383 }
0384
0385 inline static unsigned char reduced_hash(std::size_t hash)
0386 {
0387 return narrow_cast<unsigned char>(match_word(hash));
0388 }
0389
0390 inline slot_type& at(std::size_t pos)
0391 {
0392 return m[pos];
0393 }
0394
0395 inline const slot_type& at(std::size_t pos)const
0396 {
0397 return m[pos];
0398 }
0399
0400 inline slot_type& overflow()
0401 {
0402 return at(N);
0403 }
0404
0405 inline const slot_type& overflow()const
0406 {
0407 return at(N);
0408 }
0409
0410 alignas(16) slot_type m[16];
0411 };
0412
0413 #elif defined(BOOST_UNORDERED_LITTLE_ENDIAN_NEON)
0414
0415 template<template<typename> class IntegralWrapper>
0416 struct group15
0417 {
0418 static constexpr std::size_t N=15;
0419 static constexpr bool regular_layout=true;
0420
0421 struct dummy_group_type
0422 {
0423 alignas(16) unsigned char storage[N+1]={0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0};
0424 };
0425
0426 inline void initialize()
0427 {
0428 vst1q_u8(reinterpret_cast<uint8_t*>(m),vdupq_n_u8(0));
0429 }
0430
0431 inline void set(std::size_t pos,std::size_t hash)
0432 {
0433 BOOST_ASSERT(pos<N);
0434 at(pos)=reduced_hash(hash);
0435 }
0436
0437 inline void set_sentinel()
0438 {
0439 at(N-1)=sentinel_;
0440 }
0441
0442 inline bool is_sentinel(std::size_t pos)const
0443 {
0444 BOOST_ASSERT(pos<N);
0445 return pos==N-1&&at(N-1)==sentinel_;
0446 }
0447
0448 static inline bool is_sentinel(unsigned char* pc)noexcept
0449 {
0450 return *reinterpret_cast<slot_type*>(pc)==sentinel_;
0451 }
0452
0453 inline void reset(std::size_t pos)
0454 {
0455 BOOST_ASSERT(pos<N);
0456 at(pos)=available_;
0457 }
0458
0459 static inline void reset(unsigned char* pc)
0460 {
0461 *reinterpret_cast<slot_type*>(pc)=available_;
0462 }
0463
0464 inline int match(std::size_t hash)const
0465 {
0466 return simde_mm_movemask_epi8(vceqq_u8(
0467 load_metadata(),vdupq_n_u8(reduced_hash(hash))))&0x7FFF;
0468 }
0469
0470 inline bool is_not_overflowed(std::size_t hash)const
0471 {
0472 static constexpr unsigned char shift[]={1,2,4,8,16,32,64,128};
0473
0474 return !(overflow()&shift[hash%8]);
0475 }
0476
0477 inline void mark_overflow(std::size_t hash)
0478 {
0479 overflow()|=static_cast<unsigned char>(1<<(hash%8));
0480 }
0481
0482 static inline bool maybe_caused_overflow(unsigned char* pc)
0483 {
0484 std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
0485 group15 *pg=reinterpret_cast<group15*>(pc-pos);
0486 return !pg->is_not_overflowed(*pc);
0487 };
0488
0489 inline int match_available()const
0490 {
0491 return simde_mm_movemask_epi8(vceqq_u8(
0492 load_metadata(),vdupq_n_u8(0)))&0x7FFF;
0493 }
0494
0495 inline bool is_occupied(std::size_t pos)const
0496 {
0497 BOOST_ASSERT(pos<N);
0498 return at(pos)!=available_;
0499 }
0500
0501 static inline bool is_occupied(unsigned char* pc)noexcept
0502 {
0503 return *reinterpret_cast<slot_type*>(pc)!=available_;
0504 }
0505
0506 inline int match_occupied()const
0507 {
0508 return simde_mm_movemask_epi8(vcgtq_u8(
0509 load_metadata(),vdupq_n_u8(0)))&0x7FFF;
0510 }
0511
0512 private:
0513 using slot_type=IntegralWrapper<unsigned char>;
0514 BOOST_UNORDERED_STATIC_ASSERT(sizeof(slot_type)==1);
0515
0516 static constexpr unsigned char available_=0,
0517 sentinel_=1;
0518
0519 inline uint8x16_t load_metadata()const
0520 {
0521 #if defined(BOOST_UNORDERED_THREAD_SANITIZER)
0522
0523
0524
0525
0526 alignas(16) uint8_t data[16]={
0527 m[ 0],m[ 1],m[ 2],m[ 3],m[ 4],m[ 5],m[ 6],m[ 7],
0528 m[ 8],m[ 9],m[10],m[11],m[12],m[13],m[14],m[15]};
0529 return vld1q_u8(data);
0530 #else
0531 return vld1q_u8(reinterpret_cast<const uint8_t*>(m));
0532 #endif
0533 }
0534
0535 inline static unsigned char reduced_hash(std::size_t hash)
0536 {
0537 static constexpr unsigned char table[]={
0538 8,9,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0539 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
0540 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
0541 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
0542 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
0543 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
0544 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
0545 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
0546 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
0547 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
0548 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
0549 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
0550 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
0551 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
0552 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
0553 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
0554 };
0555
0556 return table[(unsigned char)hash];
0557 }
0558
0559
0560
0561
0562
0563
0564 static inline int simde_mm_movemask_epi8(uint8x16_t a)
0565 {
0566 static constexpr uint8_t md[16]={
0567 1 << 0, 1 << 1, 1 << 2, 1 << 3,
0568 1 << 4, 1 << 5, 1 << 6, 1 << 7,
0569 1 << 0, 1 << 1, 1 << 2, 1 << 3,
0570 1 << 4, 1 << 5, 1 << 6, 1 << 7,
0571 };
0572
0573 uint8x16_t masked=vandq_u8(vld1q_u8(md),a);
0574 uint8x8x2_t tmp=vzip_u8(vget_low_u8(masked),vget_high_u8(masked));
0575 uint16x8_t x=vreinterpretq_u16_u8(vcombine_u8(tmp.val[0],tmp.val[1]));
0576
0577 #if defined(__ARM_ARCH_ISA_A64)
0578 return vaddvq_u16(x);
0579 #else
0580 uint64x2_t t64=vpaddlq_u32(vpaddlq_u16(x));
0581 return int(vgetq_lane_u64(t64,0))+int(vgetq_lane_u64(t64,1));
0582 #endif
0583 }
0584
0585 inline slot_type& at(std::size_t pos)
0586 {
0587 return m[pos];
0588 }
0589
0590 inline const slot_type& at(std::size_t pos)const
0591 {
0592 return m[pos];
0593 }
0594
0595 inline slot_type& overflow()
0596 {
0597 return at(N);
0598 }
0599
0600 inline const slot_type& overflow()const
0601 {
0602 return at(N);
0603 }
0604
0605 alignas(16) slot_type m[16];
0606 };
0607
0608 #else
0609
0610 template<template<typename> class IntegralWrapper>
0611 struct group15
0612 {
0613 static constexpr std::size_t N=15;
0614 static constexpr bool regular_layout=false;
0615
0616 struct dummy_group_type
0617 {
0618 alignas(16) boost::uint64_t m[2]=
0619 {0x0000000000004000ull,0x0000000000000000ull};
0620 };
0621
0622 inline void initialize(){m[0]=0;m[1]=0;}
0623
0624 inline void set(std::size_t pos,std::size_t hash)
0625 {
0626 BOOST_ASSERT(pos<N);
0627 set_impl(pos,reduced_hash(hash));
0628 }
0629
0630 inline void set_sentinel()
0631 {
0632 set_impl(N-1,sentinel_);
0633 }
0634
0635 inline bool is_sentinel(std::size_t pos)const
0636 {
0637 BOOST_ASSERT(pos<N);
0638 return
0639 pos==N-1&&
0640 (m[0] & boost::uint64_t(0x4000400040004000ull))==
0641 boost::uint64_t(0x4000ull)&&
0642 (m[1] & boost::uint64_t(0x4000400040004000ull))==0;
0643 }
0644
0645 inline void reset(std::size_t pos)
0646 {
0647 BOOST_ASSERT(pos<N);
0648 set_impl(pos,available_);
0649 }
0650
0651 static inline void reset(unsigned char* pc)
0652 {
0653 std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
0654 pc-=pos;
0655 reinterpret_cast<group15*>(pc)->reset(pos);
0656 }
0657
0658 inline int match(std::size_t hash)const
0659 {
0660 return match_impl(reduced_hash(hash));
0661 }
0662
0663 inline bool is_not_overflowed(std::size_t hash)const
0664 {
0665 return !(reinterpret_cast<const boost::uint16_t*>(m)[hash%8] & 0x8000u);
0666 }
0667
0668 inline void mark_overflow(std::size_t hash)
0669 {
0670 reinterpret_cast<boost::uint16_t*>(m)[hash%8]|=0x8000u;
0671 }
0672
0673 static inline bool maybe_caused_overflow(unsigned char* pc)
0674 {
0675 std::size_t pos=reinterpret_cast<uintptr_t>(pc)%sizeof(group15);
0676 group15 *pg=reinterpret_cast<group15*>(pc-pos);
0677 boost::uint64_t x=((pg->m[0])>>pos)&0x000100010001ull;
0678 boost::uint32_t y=narrow_cast<boost::uint32_t>(x|(x>>15)|(x>>30));
0679 return !pg->is_not_overflowed(y);
0680 };
0681
0682 inline int match_available()const
0683 {
0684 boost::uint64_t x=~(m[0]|m[1]);
0685 boost::uint32_t y=static_cast<boost::uint32_t>(x&(x>>32));
0686 y&=y>>16;
0687 return y&0x7FFF;
0688 }
0689
0690 inline bool is_occupied(std::size_t pos)const
0691 {
0692 BOOST_ASSERT(pos<N);
0693 boost::uint64_t x=m[0]|m[1];
0694 return (x&(0x0001000100010001ull<<pos))!=0;
0695 }
0696
0697 inline int match_occupied()const
0698 {
0699 boost::uint64_t x=m[0]|m[1];
0700 boost::uint32_t y=narrow_cast<boost::uint32_t>(x|(x>>32));
0701 y|=y>>16;
0702 return y&0x7FFF;
0703 }
0704
0705 private:
0706 using word_type=IntegralWrapper<uint64_t>;
0707 BOOST_UNORDERED_STATIC_ASSERT(sizeof(word_type)==8);
0708
0709 static constexpr unsigned char available_=0,
0710 sentinel_=1;
0711
0712 inline static unsigned char reduced_hash(std::size_t hash)
0713 {
0714 static constexpr unsigned char table[]={
0715 8,9,2,3,4,5,6,7,8,9,10,11,12,13,14,15,
0716 16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,
0717 32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,
0718 48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,
0719 64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,
0720 80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,
0721 96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,
0722 112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,
0723 128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,
0724 144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,
0725 160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,
0726 176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,
0727 192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,
0728 208,209,210,211,212,213,214,215,216,217,218,219,220,221,222,223,
0729 224,225,226,227,228,229,230,231,232,233,234,235,236,237,238,239,
0730 240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,
0731 };
0732
0733 return table[narrow_cast<unsigned char>(hash)];
0734 }
0735
0736 inline void set_impl(std::size_t pos,std::size_t n)
0737 {
0738 BOOST_ASSERT(n<256);
0739 set_impl(m[0],pos,n&0xFu);
0740 set_impl(m[1],pos,n>>4);
0741 }
0742
0743 static inline void set_impl(word_type& x,std::size_t pos,std::size_t n)
0744 {
0745 static constexpr boost::uint64_t mask[]=
0746 {
0747 0x0000000000000000ull,0x0000000000000001ull,0x0000000000010000ull,
0748 0x0000000000010001ull,0x0000000100000000ull,0x0000000100000001ull,
0749 0x0000000100010000ull,0x0000000100010001ull,0x0001000000000000ull,
0750 0x0001000000000001ull,0x0001000000010000ull,0x0001000000010001ull,
0751 0x0001000100000000ull,0x0001000100000001ull,0x0001000100010000ull,
0752 0x0001000100010001ull,
0753 };
0754 static constexpr boost::uint64_t imask[]=
0755 {
0756 0x0001000100010001ull,0x0001000100010000ull,0x0001000100000001ull,
0757 0x0001000100000000ull,0x0001000000010001ull,0x0001000000010000ull,
0758 0x0001000000000001ull,0x0001000000000000ull,0x0000000100010001ull,
0759 0x0000000100010000ull,0x0000000100000001ull,0x0000000100000000ull,
0760 0x0000000000010001ull,0x0000000000010000ull,0x0000000000000001ull,
0761 0x0000000000000000ull,
0762 };
0763
0764 BOOST_ASSERT(pos<16&&n<16);
0765 x|= mask[n]<<pos;
0766 x&=~(imask[n]<<pos);
0767 }
0768
0769 inline int match_impl(std::size_t n)const
0770 {
0771 static constexpr boost::uint64_t mask[]=
0772 {
0773 0x0000000000000000ull,0x000000000000ffffull,0x00000000ffff0000ull,
0774 0x00000000ffffffffull,0x0000ffff00000000ull,0x0000ffff0000ffffull,
0775 0x0000ffffffff0000ull,0x0000ffffffffffffull,0xffff000000000000ull,
0776 0xffff00000000ffffull,0xffff0000ffff0000ull,0xffff0000ffffffffull,
0777 0xffffffff00000000ull,0xffffffff0000ffffull,0xffffffffffff0000ull,
0778 0xffffffffffffffffull,
0779 };
0780
0781 BOOST_ASSERT(n<256);
0782 boost::uint64_t x=m[0]^mask[n&0xFu];
0783 x=~((m[1]^mask[n>>4])|x);
0784 boost::uint32_t y=static_cast<boost::uint32_t>(x&(x>>32));
0785 y&=y>>16;
0786 return y&0x7FFF;
0787 }
0788
0789 alignas(16) word_type m[2];
0790 };
0791
0792 #endif
0793
0794
0795
0796
0797
0798
0799
0800
0801
0802
0803
0804
0805
0806
0807
0808
0809
0810
0811
0812
0813
0814
0815
0816
0817
0818
0819
0820
0821
0822 struct pow2_size_policy
0823 {
0824 static inline std::size_t size_index(std::size_t n)
0825 {
0826
0827
0828
0829 return sizeof(std::size_t)*CHAR_BIT-
0830 (n<=2?1:((std::size_t)(boost::core::bit_width(n-1))));
0831 }
0832
0833 static inline std::size_t size(std::size_t size_index_)
0834 {
0835 return std::size_t(1)<<(sizeof(std::size_t)*CHAR_BIT-size_index_);
0836 }
0837
0838 static constexpr std::size_t min_size(){return 2;}
0839
0840 static inline std::size_t position(std::size_t hash,std::size_t size_index_)
0841 {
0842 return hash>>size_index_;
0843 }
0844 };
0845
0846
0847
0848 template<typename Group,typename SizePolicy>
0849 static inline std::size_t size_index_for(std::size_t n)
0850 {
0851
0852 return SizePolicy::size_index(n/Group::N+1);
0853 }
0854
0855
0856
0857
0858
0859
0860 struct pow2_quadratic_prober
0861 {
0862 pow2_quadratic_prober(std::size_t pos_):pos{pos_}{}
0863
0864 inline std::size_t get()const{return pos;}
0865
0866
0867
0868
0869
0870
0871 inline bool next(std::size_t mask)
0872 {
0873 step+=1;
0874 pos=(pos+step)&mask;
0875 return step<=mask;
0876 }
0877
0878 private:
0879 std::size_t pos,step=0;
0880 };
0881
0882
0883
0884
0885
0886
0887
0888
0889
0890 struct no_mix
0891 {
0892 template<typename Hash,typename T>
0893 static inline std::size_t mix(const Hash& h,const T& x)
0894 {
0895 return h(x);
0896 }
0897 };
0898
0899 struct mulx_mix
0900 {
0901 template<typename Hash,typename T>
0902 static inline std::size_t mix(const Hash& h,const T& x)
0903 {
0904 return mulx(h(x));
0905 }
0906 };
0907
0908
0909
0910
0911
0912 inline unsigned int unchecked_countr_zero(int x)
0913 {
0914 #if defined(BOOST_MSVC)
0915 unsigned long r;
0916 _BitScanForward(&r,(unsigned long)x);
0917 return (unsigned int)r;
0918 #else
0919 BOOST_UNORDERED_ASSUME(x!=0);
0920 return (unsigned int)boost::core::countr_zero((unsigned int)x);
0921 #endif
0922 }
0923
0924
0925
0926
0927
0928
0929
0930
0931
0932
0933 template<typename Group,std::size_t Size>
0934 Group* dummy_groups()
0935 {
0936
0937
0938
0939
0940
0941
0942
0943
0944 static constexpr typename Group::dummy_group_type
0945 storage[Size]={typename Group::dummy_group_type(),};
0946
0947 return reinterpret_cast<Group*>(
0948 const_cast<typename Group::dummy_group_type*>(storage));
0949 }
0950
0951 template<
0952 typename Ptr,typename Ptr2,
0953 typename std::enable_if<!std::is_same<Ptr,Ptr2>::value>::type* = nullptr
0954 >
0955 Ptr to_pointer(Ptr2 p)
0956 {
0957 if(!p){return nullptr;}
0958 return boost::pointer_traits<Ptr>::pointer_to(*p);
0959 }
0960
0961 template<typename Ptr>
0962 Ptr to_pointer(Ptr p)
0963 {
0964 return p;
0965 }
0966
0967 template<typename Arrays,typename Allocator>
0968 struct arrays_holder
0969 {
0970 arrays_holder(const Arrays& arrays,const Allocator& al):
0971 arrays_{arrays},al_{al}
0972 {}
0973
0974
0975 arrays_holder(arrays_holder const&);
0976 arrays_holder& operator=(arrays_holder const&)=delete;
0977
0978 ~arrays_holder(){if(!released_)arrays_.delete_(al_,arrays_);}
0979
0980 const Arrays& release()
0981 {
0982 released_=true;
0983 return arrays_;
0984 }
0985
0986 private:
0987 Arrays arrays_;
0988 Allocator al_;
0989 bool released_=false;
0990 };
0991
0992 template<typename Value,typename Group,typename SizePolicy,typename Allocator>
0993 struct table_arrays
0994 {
0995 using allocator_type=typename boost::allocator_rebind<Allocator,Value>::type;
0996
0997 using value_type=Value;
0998 using group_type=Group;
0999 static constexpr auto N=group_type::N;
1000 using size_policy=SizePolicy;
1001 using value_type_pointer=
1002 typename boost::allocator_pointer<allocator_type>::type;
1003 using group_type_pointer=
1004 typename boost::pointer_traits<value_type_pointer>::template
1005 rebind<group_type>;
1006 using group_type_pointer_traits=boost::pointer_traits<group_type_pointer>;
1007
1008 table_arrays(
1009 std::size_t gsi,std::size_t gsm,
1010 group_type_pointer pg,value_type_pointer pe):
1011 groups_size_index{gsi},groups_size_mask{gsm},groups_{pg},elements_{pe}{}
1012
1013 value_type* elements()const noexcept{return boost::to_address(elements_);}
1014 group_type* groups()const noexcept{return boost::to_address(groups_);}
1015
1016 static void set_arrays(table_arrays& arrays,allocator_type al,std::size_t n)
1017 {
1018 return set_arrays(
1019 arrays,al,n,std::is_same<group_type*,group_type_pointer>{});
1020 }
1021
1022 static void set_arrays(
1023 table_arrays& arrays,allocator_type al,std::size_t,
1024 std::false_type )
1025 {
1026 using storage_traits=boost::allocator_traits<allocator_type>;
1027 auto groups_size_index=arrays.groups_size_index;
1028 auto groups_size=size_policy::size(groups_size_index);
1029
1030 auto sal=allocator_type(al);
1031 arrays.elements_=storage_traits::allocate(sal,buffer_size(groups_size));
1032
1033
1034
1035
1036
1037 auto p=reinterpret_cast<unsigned char*>(arrays.elements()+groups_size*N-1);
1038 p+=(uintptr_t(sizeof(group_type))-
1039 reinterpret_cast<uintptr_t>(p))%sizeof(group_type);
1040 arrays.groups_=
1041 group_type_pointer_traits::pointer_to(*reinterpret_cast<group_type*>(p));
1042
1043 initialize_groups(
1044 arrays.groups(),groups_size,
1045 is_trivially_default_constructible<group_type>{});
1046 arrays.groups()[groups_size-1].set_sentinel();
1047 }
1048
1049 static void set_arrays(
1050 table_arrays& arrays,allocator_type al,std::size_t n,
1051 std::true_type )
1052 {
1053 if(!n){
1054 arrays.groups_=dummy_groups<group_type,size_policy::min_size()>();
1055 }
1056 else{
1057 set_arrays(arrays,al,n,std::false_type{});
1058 }
1059 }
1060
1061 static table_arrays new_(allocator_type al,std::size_t n)
1062 {
1063 auto groups_size_index=size_index_for<group_type,size_policy>(n);
1064 auto groups_size=size_policy::size(groups_size_index);
1065 table_arrays arrays{groups_size_index,groups_size-1,nullptr,nullptr};
1066
1067 set_arrays(arrays,al,n);
1068 return arrays;
1069 }
1070
1071 static void delete_(allocator_type al,table_arrays& arrays)noexcept
1072 {
1073 using storage_traits=boost::allocator_traits<allocator_type>;
1074
1075 auto sal=allocator_type(al);
1076 if(arrays.elements()){
1077 storage_traits::deallocate(
1078 sal,arrays.elements_,buffer_size(arrays.groups_size_mask+1));
1079 }
1080 }
1081
1082
1083
1084 static std::size_t buffer_size(std::size_t groups_size)
1085 {
1086 auto buffer_bytes=
1087
1088 sizeof(value_type)*(groups_size*N-1)+
1089
1090 sizeof(group_type)*(groups_size+1)-1;
1091
1092
1093 return (buffer_bytes+sizeof(value_type)-1)/sizeof(value_type);
1094 }
1095
1096 static void initialize_groups(
1097 group_type* pg,std::size_t size,std::true_type )
1098 {
1099
1100
1101
1102
1103
1104
1105 std::memset(
1106 reinterpret_cast<unsigned char*>(pg),0,sizeof(group_type)*size);
1107 }
1108
1109 static void initialize_groups(
1110 group_type* pg,std::size_t size,std::false_type )
1111 {
1112 while(size--!=0)::new (pg++) group_type();
1113 }
1114
1115 std::size_t groups_size_index;
1116 std::size_t groups_size_mask;
1117 group_type_pointer groups_;
1118 value_type_pointer elements_;
1119 };
1120
1121 struct if_constexpr_void_else{void operator()()const{}};
1122
1123 template<bool B,typename F,typename G=if_constexpr_void_else>
1124 void if_constexpr(F f,G g={})
1125 {
1126 std::get<B?0:1>(std::forward_as_tuple(f,g))();
1127 }
1128
1129 template<bool B,typename T,typename std::enable_if<B>::type* =nullptr>
1130 void copy_assign_if(T& x,const T& y){x=y;}
1131
1132 template<bool B,typename T,typename std::enable_if<!B>::type* =nullptr>
1133 void copy_assign_if(T&,const T&){}
1134
1135 template<bool B,typename T,typename std::enable_if<B>::type* =nullptr>
1136 void move_assign_if(T& x,T& y){x=std::move(y);}
1137
1138 template<bool B,typename T,typename std::enable_if<!B>::type* =nullptr>
1139 void move_assign_if(T&,T&){}
1140
1141 template<bool B,typename T,typename std::enable_if<B>::type* =nullptr>
1142 void swap_if(T& x,T& y){using std::swap; swap(x,y);}
1143
1144 template<bool B,typename T,typename std::enable_if<!B>::type* =nullptr>
1145 void swap_if(T&,T&){}
1146
1147 template<typename Allocator>
1148 struct is_std_allocator:std::false_type{};
1149
1150 template<typename T>
1151 struct is_std_allocator<std::allocator<T>>:std::true_type{};
1152
1153
1154 #if defined(_LIBCPP_SUPPRESS_DEPRECATED_PUSH)
1155 _LIBCPP_SUPPRESS_DEPRECATED_PUSH
1156 #elif defined(_STL_DISABLE_DEPRECATED_WARNING)
1157 _STL_DISABLE_DEPRECATED_WARNING
1158 #elif defined(_MSC_VER)
1159 #pragma warning(push)
1160 #pragma warning(disable:4996)
1161 #endif
1162
1163 template<typename Allocator,typename Ptr,typename... Args>
1164 struct alloc_has_construct
1165 {
1166 private:
1167 template<typename Allocator2>
1168 static decltype(
1169 std::declval<Allocator2&>().construct(
1170 std::declval<Ptr>(),std::declval<Args&&>()...),
1171 std::true_type{}
1172 ) check(int);
1173
1174 template<typename> static std::false_type check(...);
1175
1176 public:
1177 static constexpr bool value=decltype(check<Allocator>(0))::value;
1178 };
1179
1180 #if defined(_LIBCPP_SUPPRESS_DEPRECATED_POP)
1181 _LIBCPP_SUPPRESS_DEPRECATED_POP
1182 #elif defined(_STL_RESTORE_DEPRECATED_WARNING)
1183 _STL_RESTORE_DEPRECATED_WARNING
1184 #elif defined(_MSC_VER)
1185 #pragma warning(pop)
1186 #endif
1187
1188
1189
1190
1191
1192 static constexpr float mlf=0.875f;
1193
1194 template<typename Group,typename Element>
1195 struct table_locator
1196 {
1197 table_locator()=default;
1198 table_locator(Group* pg_,unsigned int n_,Element* p_):pg{pg_},n{n_},p{p_}{}
1199
1200 explicit operator bool()const noexcept{return p!=nullptr;}
1201
1202 Group *pg=nullptr;
1203 unsigned int n=0;
1204 Element *p=nullptr;
1205 };
1206
1207 struct try_emplace_args_t{};
1208
1209 template<typename TypePolicy,typename Allocator,typename... Args>
1210 class alloc_cted_insert_type
1211 {
1212 using emplace_type=typename std::conditional<
1213 std::is_constructible<typename TypePolicy::init_type,Args...>::value,
1214 typename TypePolicy::init_type,
1215 typename TypePolicy::value_type
1216 >::type;
1217
1218 using insert_type=typename std::conditional<
1219 std::is_constructible<typename TypePolicy::value_type,emplace_type>::value,
1220 emplace_type,typename TypePolicy::element_type
1221 >::type;
1222
1223 alignas(insert_type) unsigned char storage[sizeof(insert_type)];
1224 Allocator al;
1225
1226 public:
1227 alloc_cted_insert_type(const Allocator& al_,Args&&... args):al{al_}
1228 {
1229 TypePolicy::construct(al,data(),std::forward<Args>(args)...);
1230 }
1231
1232 ~alloc_cted_insert_type()
1233 {
1234 TypePolicy::destroy(al,data());
1235 }
1236
1237 insert_type* data(){return reinterpret_cast<insert_type*>(&storage);}
1238 insert_type& value(){return *data();}
1239 };
1240
1241 template<typename TypePolicy,typename Allocator,typename... Args>
1242 alloc_cted_insert_type<TypePolicy,Allocator,Args...>
1243 alloc_make_insert_type(const Allocator& al,Args&&... args)
1244 {
1245 return {al,std::forward<Args>(args)...};
1246 }
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291 #include <boost/unordered/detail/foa/ignore_wshadow.hpp>
1292
1293 #if defined(BOOST_MSVC)
1294 #pragma warning(push)
1295 #pragma warning(disable:4714)
1296 #endif
1297
1298 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
1299
1300
1301
1302 #pragma warning(push)
1303 #pragma warning(disable:4702)
1304 #endif
1305
1306 template<
1307 typename TypePolicy,typename Group,template<typename...> class Arrays,
1308 typename SizeControl,typename Hash,typename Pred,typename Allocator
1309 >
1310 class
1311
1312 #if defined(_MSC_VER)&&_MSC_FULL_VER>=190023918
1313 __declspec(empty_bases)
1314 #endif
1315
1316 table_core:empty_value<Hash,0>,empty_value<Pred,1>,empty_value<Allocator,2>
1317 {
1318 public:
1319 using type_policy=TypePolicy;
1320 using group_type=Group;
1321 static constexpr auto N=group_type::N;
1322 using size_policy=pow2_size_policy;
1323 using prober=pow2_quadratic_prober;
1324 using mix_policy=typename std::conditional<
1325 hash_is_avalanching<Hash>::value,
1326 no_mix,
1327 mulx_mix
1328 >::type;
1329 using alloc_traits=boost::allocator_traits<Allocator>;
1330 using element_type=typename type_policy::element_type;
1331 using arrays_type=Arrays<element_type,group_type,size_policy,Allocator>;
1332 using size_ctrl_type=SizeControl;
1333 static constexpr auto uses_fancy_pointers=!std::is_same<
1334 typename alloc_traits::pointer,
1335 typename alloc_traits::value_type*
1336 >::value;
1337
1338 using key_type=typename type_policy::key_type;
1339 using init_type=typename type_policy::init_type;
1340 using value_type=typename type_policy::value_type;
1341 using hasher=Hash;
1342 using key_equal=Pred;
1343 using allocator_type=Allocator;
1344 using pointer=value_type*;
1345 using const_pointer=const value_type*;
1346 using reference=value_type&;
1347 using const_reference=const value_type&;
1348 using size_type=std::size_t;
1349 using difference_type=std::ptrdiff_t;
1350 using locator=table_locator<group_type,element_type>;
1351 using arrays_holder_type=arrays_holder<arrays_type,Allocator>;
1352
1353 table_core(
1354 std::size_t n=default_bucket_count,const Hash& h_=Hash(),
1355 const Pred& pred_=Pred(),const Allocator& al_=Allocator()):
1356 hash_base{empty_init,h_},pred_base{empty_init,pred_},
1357 allocator_base{empty_init,al_},arrays(new_arrays(n)),
1358 size_ctrl{initial_max_load(),0}
1359 {}
1360
1361
1362
1363
1364
1365 template<typename ArraysFn>
1366 table_core(
1367 Hash&& h_,Pred&& pred_,Allocator&& al_,
1368 ArraysFn arrays_fn,const size_ctrl_type& size_ctrl_):
1369 hash_base{empty_init,std::move(h_)},
1370 pred_base{empty_init,std::move(pred_)},
1371 allocator_base{empty_init,std::move(al_)},
1372 arrays(arrays_fn()),size_ctrl(size_ctrl_)
1373 {}
1374
1375 table_core(const table_core& x):
1376 table_core{x,alloc_traits::select_on_container_copy_construction(x.al())}{}
1377
1378 template<typename ArraysFn>
1379 table_core(table_core&& x,arrays_holder_type&& ah,ArraysFn arrays_fn):
1380 table_core(
1381 std::move(x.h()),std::move(x.pred()),std::move(x.al()),
1382 arrays_fn,x.size_ctrl)
1383 {
1384 x.arrays=ah.release();
1385 x.size_ctrl.ml=x.initial_max_load();
1386 x.size_ctrl.size=0;
1387 }
1388
1389 table_core(table_core&& x)
1390 noexcept(
1391 std::is_nothrow_move_constructible<Hash>::value&&
1392 std::is_nothrow_move_constructible<Pred>::value&&
1393 std::is_nothrow_move_constructible<Allocator>::value&&
1394 !uses_fancy_pointers):
1395 table_core{
1396 std::move(x),x.make_empty_arrays(),[&x]{return x.arrays;}}
1397 {}
1398
1399 table_core(const table_core& x,const Allocator& al_):
1400 table_core{std::size_t(std::ceil(float(x.size())/mlf)),x.h(),x.pred(),al_}
1401 {
1402 copy_elements_from(x);
1403 }
1404
1405 table_core(table_core&& x,const Allocator& al_):
1406 table_core{std::move(x.h()),std::move(x.pred()),al_}
1407 {
1408 if(al()==x.al()){
1409 using std::swap;
1410 swap(arrays,x.arrays);
1411 swap(size_ctrl,x.size_ctrl);
1412 }
1413 else{
1414 reserve(x.size());
1415 clear_on_exit c{x};
1416 (void)c;
1417
1418
1419
1420
1421 x.for_all_elements([this](element_type* p){
1422 unchecked_insert(type_policy::move(type_policy::value_from(*p)));
1423 });
1424 }
1425 }
1426
1427 ~table_core()noexcept
1428 {
1429 for_all_elements([this](element_type* p){
1430 destroy_element(p);
1431 });
1432 delete_arrays(arrays);
1433 }
1434
1435 std::size_t initial_max_load()const
1436 {
1437 static constexpr std::size_t small_capacity=2*N-1;
1438
1439 auto capacity_=capacity();
1440 if(capacity_<=small_capacity){
1441 return capacity_;
1442 }
1443 else{
1444 return (std::size_t)(mlf*(float)(capacity_));
1445 }
1446 }
1447
1448 arrays_holder_type make_empty_arrays()const
1449 {
1450 return make_arrays(0);
1451 }
1452
1453 table_core& operator=(const table_core& x)
1454 {
1455 BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred)
1456
1457 static constexpr auto pocca=
1458 alloc_traits::propagate_on_container_copy_assignment::value;
1459
1460 if(this!=std::addressof(x)){
1461
1462
1463
1464 hasher tmp_h=x.h();
1465 key_equal tmp_p=x.pred();
1466
1467 clear();
1468
1469
1470
1471
1472
1473 using std::swap;
1474 swap(h(),tmp_h);
1475 swap(pred(),tmp_p);
1476
1477 if_constexpr<pocca>([&,this]{
1478 if(al()!=x.al()){
1479 auto ah=x.make_arrays(std::size_t(std::ceil(float(x.size())/mlf)));
1480 delete_arrays(arrays);
1481 arrays=ah.release();
1482 size_ctrl.ml=initial_max_load();
1483 }
1484 copy_assign_if<pocca>(al(),x.al());
1485 });
1486
1487 noshrink_reserve(x.size());
1488 copy_elements_from(x);
1489 }
1490 return *this;
1491 }
1492
1493 #if defined(BOOST_MSVC)
1494 #pragma warning(push)
1495 #pragma warning(disable:4127)
1496 #endif
1497
1498 table_core& operator=(table_core&& x)
1499 noexcept(
1500 (alloc_traits::propagate_on_container_move_assignment::value||
1501 alloc_traits::is_always_equal::value)&&!uses_fancy_pointers)
1502 {
1503 BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred)
1504
1505 static constexpr auto pocma=
1506 alloc_traits::propagate_on_container_move_assignment::value;
1507
1508 if(this!=std::addressof(x)){
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519 using std::swap;
1520
1521 clear();
1522
1523 if(pocma||al()==x.al()){
1524 auto ah=x.make_empty_arrays();
1525 swap(h(),x.h());
1526 swap(pred(),x.pred());
1527 delete_arrays(arrays);
1528 move_assign_if<pocma>(al(),x.al());
1529 arrays=x.arrays;
1530 size_ctrl.ml=std::size_t(x.size_ctrl.ml);
1531 size_ctrl.size=std::size_t(x.size_ctrl.size);
1532 x.arrays=ah.release();
1533 x.size_ctrl.ml=x.initial_max_load();
1534 x.size_ctrl.size=0;
1535 }
1536 else{
1537 swap(h(),x.h());
1538 swap(pred(),x.pred());
1539
1540
1541 noshrink_reserve(x.size());
1542 clear_on_exit c{x};
1543 (void)c;
1544
1545
1546
1547
1548 x.for_all_elements([this](element_type* p){
1549 unchecked_insert(type_policy::move(type_policy::value_from(*p)));
1550 });
1551 }
1552 }
1553 return *this;
1554 }
1555
1556 #if defined(BOOST_MSVC)
1557 #pragma warning(pop)
1558 #endif
1559
1560 allocator_type get_allocator()const noexcept{return al();}
1561
1562 bool empty()const noexcept{return size()==0;}
1563 std::size_t size()const noexcept{return size_ctrl.size;}
1564 std::size_t max_size()const noexcept{return SIZE_MAX;}
1565
1566 BOOST_FORCEINLINE
1567 void erase(group_type* pg,unsigned int pos,element_type* p)noexcept
1568 {
1569 destroy_element(p);
1570 recover_slot(pg,pos);
1571 }
1572
1573 BOOST_FORCEINLINE
1574 void erase(unsigned char* pc,element_type* p)noexcept
1575 {
1576 destroy_element(p);
1577 recover_slot(pc);
1578 }
1579
1580 template<typename Key>
1581 BOOST_FORCEINLINE locator find(const Key& x)const
1582 {
1583 auto hash=hash_for(x);
1584 return find(x,position_for(hash),hash);
1585 }
1586
1587 #if defined(BOOST_MSVC)
1588
1589 #pragma warning(push)
1590 #pragma warning(disable:4800)
1591 #endif
1592
1593 template<typename Key>
1594 BOOST_FORCEINLINE locator find(
1595 const Key& x,std::size_t pos0,std::size_t hash)const
1596 {
1597 prober pb(pos0);
1598 do{
1599 auto pos=pb.get();
1600 auto pg=arrays.groups()+pos;
1601 auto mask=pg->match(hash);
1602 if(mask){
1603 auto elements=arrays.elements();
1604 BOOST_UNORDERED_ASSUME(elements!=nullptr);
1605 auto p=elements+pos*N;
1606 BOOST_UNORDERED_PREFETCH_ELEMENTS(p,N);
1607 do{
1608 auto n=unchecked_countr_zero(mask);
1609 if(BOOST_LIKELY(bool(pred()(x,key_from(p[n]))))){
1610 return {pg,n,p+n};
1611 }
1612 mask&=mask-1;
1613 }while(mask);
1614 }
1615 if(BOOST_LIKELY(pg->is_not_overflowed(hash))){
1616 return {};
1617 }
1618 }
1619 while(BOOST_LIKELY(pb.next(arrays.groups_size_mask)));
1620 return {};
1621 }
1622
1623 #if defined(BOOST_MSVC)
1624 #pragma warning(pop)
1625 #endif
1626
1627 void swap(table_core& x)
1628 noexcept(
1629 alloc_traits::propagate_on_container_swap::value||
1630 alloc_traits::is_always_equal::value)
1631 {
1632 BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED(Hash, Pred)
1633
1634 static constexpr auto pocs=
1635 alloc_traits::propagate_on_container_swap::value;
1636
1637 using std::swap;
1638 if_constexpr<pocs>([&,this]{
1639 swap_if<pocs>(al(),x.al());
1640 },
1641 [&,this]{
1642 BOOST_ASSERT(al()==x.al());
1643 (void)this;
1644 });
1645
1646 swap(h(),x.h());
1647 swap(pred(),x.pred());
1648 swap(arrays,x.arrays);
1649 swap(size_ctrl,x.size_ctrl);
1650 }
1651
1652 void clear()noexcept
1653 {
1654 auto p=arrays.elements();
1655 if(p){
1656 for(auto pg=arrays.groups(),last=pg+arrays.groups_size_mask+1;
1657 pg!=last;++pg,p+=N){
1658 auto mask=match_really_occupied(pg,last);
1659 while(mask){
1660 destroy_element(p+unchecked_countr_zero(mask));
1661 mask&=mask-1;
1662 }
1663
1664 pg->initialize();
1665 }
1666 arrays.groups()[arrays.groups_size_mask].set_sentinel();
1667 size_ctrl.ml=initial_max_load();
1668 size_ctrl.size=0;
1669 }
1670 }
1671
1672 hasher hash_function()const{return h();}
1673 key_equal key_eq()const{return pred();}
1674
1675 std::size_t capacity()const noexcept
1676 {
1677 return arrays.elements()?(arrays.groups_size_mask+1)*N-1:0;
1678 }
1679
1680 float load_factor()const noexcept
1681 {
1682 if(capacity()==0)return 0;
1683 else return float(size())/float(capacity());
1684 }
1685
1686 float max_load_factor()const noexcept{return mlf;}
1687
1688 std::size_t max_load()const noexcept{return size_ctrl.ml;}
1689
1690 void rehash(std::size_t n)
1691 {
1692 auto m=size_t(std::ceil(float(size())/mlf));
1693 if(m>n)n=m;
1694 if(n)n=capacity_for(n);
1695
1696 if(n!=capacity())unchecked_rehash(n);
1697 }
1698
1699 void reserve(std::size_t n)
1700 {
1701 rehash(std::size_t(std::ceil(float(n)/mlf)));
1702 }
1703
1704 friend bool operator==(const table_core& x,const table_core& y)
1705 {
1706 return
1707 x.size()==y.size()&&
1708 x.for_all_elements_while([&](element_type* p){
1709 auto loc=y.find(key_from(*p));
1710 return loc&&
1711 const_cast<const value_type&>(type_policy::value_from(*p))==
1712 const_cast<const value_type&>(type_policy::value_from(*loc.p));
1713 });
1714 }
1715
1716 friend bool operator!=(const table_core& x,const table_core& y)
1717 {
1718 return !(x==y);
1719 }
1720
1721 struct clear_on_exit
1722 {
1723 ~clear_on_exit(){x.clear();}
1724 table_core& x;
1725 };
1726
1727 Hash& h(){return hash_base::get();}
1728 const Hash& h()const{return hash_base::get();}
1729 Pred& pred(){return pred_base::get();}
1730 const Pred& pred()const{return pred_base::get();}
1731 Allocator& al(){return allocator_base::get();}
1732 const Allocator& al()const{return allocator_base::get();}
1733
1734 template<typename... Args>
1735 void construct_element(element_type* p,Args&&... args)
1736 {
1737 type_policy::construct(al(),p,std::forward<Args>(args)...);
1738 }
1739
1740 template<typename... Args>
1741 void construct_element(element_type* p,try_emplace_args_t,Args&&... args)
1742 {
1743 construct_element_from_try_emplace_args(
1744 p,
1745 std::integral_constant<bool,std::is_same<key_type,value_type>::value>{},
1746 std::forward<Args>(args)...);
1747 }
1748
1749 void destroy_element(element_type* p)noexcept
1750 {
1751 type_policy::destroy(al(),p);
1752 }
1753
1754 struct destroy_element_on_exit
1755 {
1756 ~destroy_element_on_exit(){this_->destroy_element(p);}
1757 table_core *this_;
1758 element_type *p;
1759 };
1760
1761 template<typename T>
1762 static inline auto key_from(const T& x)
1763 ->decltype(type_policy::extract(x))
1764 {
1765 return type_policy::extract(x);
1766 }
1767
1768 template<typename Key,typename... Args>
1769 static inline const Key& key_from(
1770 try_emplace_args_t,const Key& x,const Args&...)
1771 {
1772 return x;
1773 }
1774
1775 template<typename Key>
1776 inline std::size_t hash_for(const Key& x)const
1777 {
1778 return mix_policy::mix(h(),x);
1779 }
1780
1781 inline std::size_t position_for(std::size_t hash)const
1782 {
1783 return position_for(hash,arrays);
1784 }
1785
1786 static inline std::size_t position_for(
1787 std::size_t hash,const arrays_type& arrays_)
1788 {
1789 return size_policy::position(hash,arrays_.groups_size_index);
1790 }
1791
1792 static inline int match_really_occupied(group_type* pg,group_type* last)
1793 {
1794
1795 return pg->match_occupied()&~(int(pg==last-1)<<(N-1));
1796 }
1797
1798 template<typename... Args>
1799 locator unchecked_emplace_at(
1800 std::size_t pos0,std::size_t hash,Args&&... args)
1801 {
1802 auto res=nosize_unchecked_emplace_at(
1803 arrays,pos0,hash,std::forward<Args>(args)...);
1804 ++size_ctrl.size;
1805 return res;
1806 }
1807
1808 BOOST_NOINLINE void unchecked_rehash_for_growth()
1809 {
1810 auto new_arrays_=new_arrays_for_growth();
1811 unchecked_rehash(new_arrays_);
1812 }
1813
1814 template<typename... Args>
1815 BOOST_NOINLINE locator
1816 unchecked_emplace_with_rehash(std::size_t hash,Args&&... args)
1817 {
1818 auto new_arrays_=new_arrays_for_growth();
1819 locator it;
1820 BOOST_TRY{
1821
1822 it=nosize_unchecked_emplace_at(
1823 new_arrays_,position_for(hash,new_arrays_),
1824 hash,std::forward<Args>(args)...);
1825 }
1826 BOOST_CATCH(...){
1827 delete_arrays(new_arrays_);
1828 BOOST_RETHROW
1829 }
1830 BOOST_CATCH_END
1831
1832
1833 unchecked_rehash(new_arrays_);
1834 ++size_ctrl.size;
1835 return it;
1836 }
1837
1838 void noshrink_reserve(std::size_t n)
1839 {
1840
1841 BOOST_ASSERT(empty());
1842
1843 if(n){
1844 n=std::size_t(std::ceil(float(n)/mlf));
1845 n=capacity_for(n);
1846
1847 if(n>capacity()){
1848 auto new_arrays_=new_arrays(n);
1849 delete_arrays(arrays);
1850 arrays=new_arrays_;
1851 size_ctrl.ml=initial_max_load();
1852 }
1853 }
1854 }
1855
1856 template<typename F>
1857 void for_all_elements(F f)const
1858 {
1859 for_all_elements(arrays,f);
1860 }
1861
1862 template<typename F>
1863 static auto for_all_elements(const arrays_type& arrays_,F f)
1864 ->decltype(f(nullptr),void())
1865 {
1866 for_all_elements_while(arrays_,[&](element_type* p){f(p);return true;});
1867 }
1868
1869 template<typename F>
1870 static auto for_all_elements(const arrays_type& arrays_,F f)
1871 ->decltype(f(nullptr,0,nullptr),void())
1872 {
1873 for_all_elements_while(
1874 arrays_,[&](group_type* pg,unsigned int n,element_type* p)
1875 {f(pg,n,p);return true;});
1876 }
1877
1878 template<typename F>
1879 bool for_all_elements_while(F f)const
1880 {
1881 return for_all_elements_while(arrays,f);
1882 }
1883
1884 template<typename F>
1885 static auto for_all_elements_while(const arrays_type& arrays_,F f)
1886 ->decltype(f(nullptr),bool())
1887 {
1888 return for_all_elements_while(
1889 arrays_,[&](group_type*,unsigned int,element_type* p){return f(p);});
1890 }
1891
1892 template<typename F>
1893 static auto for_all_elements_while(const arrays_type& arrays_,F f)
1894 ->decltype(f(nullptr,0,nullptr),bool())
1895 {
1896 auto p=arrays_.elements();
1897 if(p){
1898 for(auto pg=arrays_.groups(),last=pg+arrays_.groups_size_mask+1;
1899 pg!=last;++pg,p+=N){
1900 auto mask=match_really_occupied(pg,last);
1901 while(mask){
1902 auto n=unchecked_countr_zero(mask);
1903 if(!f(pg,n,p+n))return false;
1904 mask&=mask-1;
1905 }
1906 }
1907 }
1908 return true;
1909 }
1910
1911 arrays_type arrays;
1912 size_ctrl_type size_ctrl;
1913
1914 private:
1915 template<
1916 typename,typename,template<typename...> class,
1917 typename,typename,typename,typename
1918 >
1919 friend class table_core;
1920
1921 using hash_base=empty_value<Hash,0>;
1922 using pred_base=empty_value<Pred,1>;
1923 using allocator_base=empty_value<Allocator,2>;
1924
1925
1926
1927 table_core(Hash&& h_,Pred&& pred_,const Allocator& al_):
1928 hash_base{empty_init,std::move(h_)},
1929 pred_base{empty_init,std::move(pred_)},
1930 allocator_base{empty_init,al_},arrays(new_arrays(0)),
1931 size_ctrl{initial_max_load(),0}
1932 {
1933 }
1934
1935 arrays_type new_arrays(std::size_t n)const
1936 {
1937 return arrays_type::new_(al(),n);
1938 }
1939
1940 arrays_type new_arrays_for_growth()const
1941 {
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952 return new_arrays(std::size_t(
1953 std::ceil(static_cast<float>(size()+size()/61+1)/mlf)));
1954 }
1955
1956 void delete_arrays(arrays_type& arrays_)noexcept
1957 {
1958 arrays_type::delete_(al(),arrays_);
1959 }
1960
1961 arrays_holder_type make_arrays(std::size_t n)const
1962 {
1963 return {new_arrays(n),al()};
1964 }
1965
1966 template<typename Key,typename... Args>
1967 void construct_element_from_try_emplace_args(
1968 element_type* p,std::false_type,Key&& x,Args&&... args)
1969 {
1970 type_policy::construct(
1971 this->al(),p,
1972 std::piecewise_construct,
1973 std::forward_as_tuple(std::forward<Key>(x)),
1974 std::forward_as_tuple(std::forward<Args>(args)...));
1975 }
1976
1977
1978
1979
1980
1981 template<typename Key>
1982 void construct_element_from_try_emplace_args(
1983 element_type* p,std::true_type,Key&& x)
1984 {
1985 type_policy::construct(this->al(),p,std::forward<Key>(x));
1986 }
1987
1988 void copy_elements_from(const table_core& x)
1989 {
1990 BOOST_ASSERT(empty());
1991 BOOST_ASSERT(this!=std::addressof(x));
1992 if(arrays.groups_size_mask==x.arrays.groups_size_mask){
1993 fast_copy_elements_from(x);
1994 }
1995 else{
1996 x.for_all_elements([this](const element_type* p){
1997 unchecked_insert(*p);
1998 });
1999 }
2000 }
2001
2002 void fast_copy_elements_from(const table_core& x)
2003 {
2004 if(arrays.elements()&&x.arrays.elements()){
2005 copy_elements_array_from(x);
2006 copy_groups_array_from(x);
2007 size_ctrl.ml=std::size_t(x.size_ctrl.ml);
2008 size_ctrl.size=std::size_t(x.size_ctrl.size);
2009 }
2010 }
2011
2012 void copy_elements_array_from(const table_core& x)
2013 {
2014 copy_elements_array_from(
2015 x,
2016 std::integral_constant<
2017 bool,
2018 is_trivially_copy_constructible<element_type>::value&&(
2019 is_std_allocator<Allocator>::value||
2020 !alloc_has_construct<Allocator,value_type*,const value_type&>::value)
2021 >{}
2022 );
2023 }
2024
2025 void copy_elements_array_from(
2026 const table_core& x,std::true_type )
2027 {
2028
2029
2030
2031 std::memcpy(
2032 reinterpret_cast<unsigned char*>(arrays.elements()),
2033 reinterpret_cast<unsigned char*>(x.arrays.elements()),
2034 x.capacity()*sizeof(value_type));
2035 }
2036
2037 void copy_elements_array_from(
2038 const table_core& x,std::false_type )
2039 {
2040 std::size_t num_constructed=0;
2041 BOOST_TRY{
2042 x.for_all_elements([&,this](const element_type* p){
2043 construct_element(arrays.elements()+(p-x.arrays.elements()),*p);
2044 ++num_constructed;
2045 });
2046 }
2047 BOOST_CATCH(...){
2048 if(num_constructed){
2049 x.for_all_elements_while([&,this](const element_type* p){
2050 destroy_element(arrays.elements()+(p-x.arrays.elements()));
2051 return --num_constructed!=0;
2052 });
2053 }
2054 BOOST_RETHROW
2055 }
2056 BOOST_CATCH_END
2057 }
2058
2059 void copy_groups_array_from(const table_core& x) {
2060 copy_groups_array_from(x,is_trivially_copy_assignable<group_type>{});
2061 }
2062
2063 void copy_groups_array_from(
2064 const table_core& x, std::true_type )
2065 {
2066 std::memcpy(
2067 arrays.groups(),x.arrays.groups(),
2068 (arrays.groups_size_mask+1)*sizeof(group_type));
2069 }
2070
2071 void copy_groups_array_from(
2072 const table_core& x, std::false_type )
2073 {
2074 auto pg=arrays.groups();
2075 auto xpg=x.arrays.groups();
2076 for(std::size_t i=0;i<arrays.groups_size_mask+1;++i){
2077 pg[i]=xpg[i];
2078 }
2079 }
2080
2081 void recover_slot(unsigned char* pc)
2082 {
2083
2084
2085
2086
2087 size_ctrl.ml-=group_type::maybe_caused_overflow(pc);
2088 group_type::reset(pc);
2089 --size_ctrl.size;
2090 }
2091
2092 void recover_slot(group_type* pg,std::size_t pos)
2093 {
2094 recover_slot(reinterpret_cast<unsigned char*>(pg)+pos);
2095 }
2096
2097 static std::size_t capacity_for(std::size_t n)
2098 {
2099 return size_policy::size(size_index_for<group_type,size_policy>(n))*N-1;
2100 }
2101
2102 BOOST_NOINLINE void unchecked_rehash(std::size_t n)
2103 {
2104 auto new_arrays_=new_arrays(n);
2105 unchecked_rehash(new_arrays_);
2106 }
2107
2108 BOOST_NOINLINE void unchecked_rehash(arrays_type& new_arrays_)
2109 {
2110 std::size_t num_destroyed=0;
2111 BOOST_TRY{
2112 for_all_elements([&,this](element_type* p){
2113 nosize_transfer_element(p,new_arrays_,num_destroyed);
2114 });
2115 }
2116 BOOST_CATCH(...){
2117 if(num_destroyed){
2118 for_all_elements_while(
2119 [&,this](group_type* pg,unsigned int n,element_type*){
2120 recover_slot(pg,n);
2121 return --num_destroyed!=0;
2122 }
2123 );
2124 }
2125 for_all_elements(new_arrays_,[this](element_type* p){
2126 destroy_element(p);
2127 });
2128 delete_arrays(new_arrays_);
2129 BOOST_RETHROW
2130 }
2131 BOOST_CATCH_END
2132
2133
2134 BOOST_ASSERT(num_destroyed==size()||num_destroyed==0);
2135 if(num_destroyed!=size()){
2136 for_all_elements([this](element_type* p){
2137 destroy_element(p);
2138 });
2139 }
2140 delete_arrays(arrays);
2141 arrays=new_arrays_;
2142 size_ctrl.ml=initial_max_load();
2143 }
2144
2145 template<typename Value>
2146 void unchecked_insert(Value&& x)
2147 {
2148 auto hash=hash_for(key_from(x));
2149 unchecked_emplace_at(position_for(hash),hash,std::forward<Value>(x));
2150 }
2151
2152 void nosize_transfer_element(
2153 element_type* p,const arrays_type& arrays_,std::size_t& num_destroyed)
2154 {
2155 nosize_transfer_element(
2156 p,hash_for(key_from(*p)),arrays_,num_destroyed,
2157 std::integral_constant<
2158 bool,
2159 std::is_nothrow_move_constructible<init_type>::value||
2160 !std::is_same<element_type,value_type>::value||
2161 !std::is_copy_constructible<element_type>::value>{});
2162 }
2163
2164 void nosize_transfer_element(
2165 element_type* p,std::size_t hash,const arrays_type& arrays_,
2166 std::size_t& num_destroyed,std::true_type )
2167 {
2168
2169
2170
2171 ++num_destroyed;
2172 destroy_element_on_exit d{this,p};
2173 (void)d;
2174 nosize_unchecked_emplace_at(
2175 arrays_,position_for(hash,arrays_),hash,type_policy::move(*p));
2176 }
2177
2178 void nosize_transfer_element(
2179 element_type* p,std::size_t hash,const arrays_type& arrays_,
2180 std::size_t& ,std::false_type )
2181 {
2182 nosize_unchecked_emplace_at(
2183 arrays_,position_for(hash,arrays_),hash,
2184 const_cast<const element_type&>(*p));
2185 }
2186
2187 template<typename... Args>
2188 locator nosize_unchecked_emplace_at(
2189 const arrays_type& arrays_,std::size_t pos0,std::size_t hash,
2190 Args&&... args)
2191 {
2192 for(prober pb(pos0);;pb.next(arrays_.groups_size_mask)){
2193 auto pos=pb.get();
2194 auto pg=arrays_.groups()+pos;
2195 auto mask=pg->match_available();
2196 if(BOOST_LIKELY(mask!=0)){
2197 auto n=unchecked_countr_zero(mask);
2198 auto p=arrays_.elements()+pos*N+n;
2199 construct_element(p,std::forward<Args>(args)...);
2200 pg->set(n,hash);
2201 return {pg,n,p};
2202 }
2203 else pg->mark_overflow(hash);
2204 }
2205 }
2206 };
2207
2208 #if BOOST_WORKAROUND(BOOST_MSVC,<=1900)
2209 #pragma warning(pop)
2210 #endif
2211
2212 #if defined(BOOST_MSVC)
2213 #pragma warning(pop)
2214 #endif
2215
2216 #include <boost/unordered/detail/foa/restore_wshadow.hpp>
2217
2218 }
2219 }
2220 }
2221 }
2222
2223 #undef BOOST_UNORDERED_STATIC_ASSERT_HASH_PRED
2224 #undef BOOST_UNORDERED_HAS_FEATURE
2225 #undef BOOST_UNORDERED_HAS_BUILTIN
2226 #endif