20 #include <type_traits> 33 #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE 39 template <
typename Ptr>
40 using NonConstPtr =
typename std::pointer_traits<Ptr>::template rebind<
41 std::remove_const_t<typename std::pointer_traits<Ptr>::element_type>>;
43 template <
typename KeyType,
typename MappedType>
44 using MapValueType = std::pair<KeyType const, MappedType>;
46 template <
typename KeyType,
typename MappedTypeOrVo
id>
47 using SetOrMapValueType = std::conditional_t<
50 MapValueType<KeyType, MappedTypeOrVoid>>;
61 template <
typename...
Args>
62 ObjectHolder(
Args&&... args) : value_{std::forward<Args>(args)...} {}
67 T
const& operator*()
const {
72 template <
char Tag,
typename T>
73 struct ObjectHolder<Tag, T, true> :
private T {
74 template <
typename...
Args>
75 ObjectHolder(
Args&&... args) : T{std::forward<Args>(args)...} {}
80 T
const& operator*()
const {
107 typename MappedTypeOrVoid,
108 typename HasherOrVoid,
109 typename KeyEqualOrVoid,
110 typename AllocOrVoid,
113 :
private ObjectHolder<
115 Defaulted<HasherOrVoid, DefaultHasher<KeyType>>>,
116 private ObjectHolder<
118 Defaulted<KeyEqualOrVoid, DefaultKeyEqual<KeyType>>>,
119 private ObjectHolder<
123 DefaultAlloc<SetOrMapValueType<KeyType, MappedTypeOrVoid>>>> {
127 using Mapped = MappedTypeOrVoid;
128 using Value = SetOrMapValueType<Key, Mapped>;
129 using Item = ItemType;
130 using Hasher = Defaulted<HasherOrVoid, DefaultHasher<Key>>;
131 using KeyEqual = Defaulted<KeyEqualOrVoid, DefaultKeyEqual<Key>>;
132 using Alloc = Defaulted<AllocOrVoid, DefaultAlloc<Value>>;
133 using AllocTraits = std::allocator_traits<Alloc>;
135 using ByteAlloc =
typename AllocTraits::template rebind_alloc<uint8_t>;
136 using ByteAllocTraits =
typename std::allocator_traits<ByteAlloc>;
137 using BytePtr =
typename ByteAllocTraits::pointer;
143 "wrong allocator value_type");
146 using HasherHolder = ObjectHolder<'H', Hasher>;
147 using KeyEqualHolder = ObjectHolder<'E', KeyEqual>;
148 using AllocHolder = ObjectHolder<'A', Alloc>;
152 template <
typename A,
typename =
void>
153 struct AllocIsAlwaysEqual : std::is_empty<A> {};
155 template <
typename A>
156 struct AllocIsAlwaysEqual<
A, typename
A::is_always_equal>
157 : A::is_always_equal {};
160 template <
typename T>
161 static constexpr
bool isNothrowSwap() {
163 return noexcept(
swap(std::declval<T&>(), std::declval<T&>()));
169 static constexpr
bool kDefaultConstructIsNoexcept =
174 static constexpr
bool kSwapIsNoexcept = kAllocIsAlwaysEqual &&
175 isNothrowSwap<Hasher>() && isNothrowSwap<KeyEqual>();
177 static constexpr
bool isAvalanchingHasher() {
183 using InternalSizeType = std::size_t;
186 static constexpr
bool kEnableItemIteration =
true;
188 using Chunk = F14Chunk<Item>;
189 using ChunkPtr =
typename std::pointer_traits<
190 typename AllocTraits::pointer>::template rebind<Chunk>;
191 using ItemIter = F14ItemIter<ChunkPtr>;
196 "Assumption for the kIsMap check violated.");
198 using MappedOrBool = std::conditional_t<kIsMap, Mapped, bool>;
202 BasePolicy(Hasher
const& hasher, KeyEqual
const& keyEqual,
Alloc const& alloc)
203 : HasherHolder{hasher}, KeyEqualHolder{keyEqual}, AllocHolder{alloc} {}
205 BasePolicy(BasePolicy
const&
rhs)
206 : HasherHolder{rhs.hasher()},
207 KeyEqualHolder{rhs.keyEqual()},
209 AllocTraits::select_on_container_copy_construction(rhs.alloc())} {}
211 BasePolicy(BasePolicy
const& rhs,
Alloc const& alloc)
212 : HasherHolder{rhs.hasher()},
213 KeyEqualHolder{rhs.keyEqual()},
214 AllocHolder{alloc} {}
216 BasePolicy(BasePolicy&& rhs)
noexcept 218 KeyEqualHolder{
std::move(rhs.keyEqual())},
223 KeyEqualHolder{
std::move(rhs.keyEqual())},
224 AllocHolder{alloc} {}
226 BasePolicy& operator=(BasePolicy
const& rhs) {
227 hasher() = rhs.hasher();
228 keyEqual() = rhs.keyEqual();
230 alloc() = rhs.alloc();
235 BasePolicy& operator=(BasePolicy&& rhs)
noexcept {
244 void swapBasePolicy(BasePolicy& rhs) {
246 swap(hasher(), rhs.hasher());
247 swap(keyEqual(), rhs.keyEqual());
249 swap(alloc(), rhs.alloc());
254 return *
static_cast<HasherHolder&
>(*this);
256 Hasher
const& hasher()
const {
257 return *
static_cast<HasherHolder
const&
>(*this);
259 KeyEqual& keyEqual() {
260 return *
static_cast<KeyEqualHolder&
>(*this);
262 KeyEqual
const& keyEqual()
const {
263 return *
static_cast<KeyEqualHolder
const&
>(*this);
266 return *
static_cast<AllocHolder&
>(*this);
268 Alloc const& alloc()
const {
269 return *
static_cast<AllocHolder
const&
>(*this);
272 template <
typename K>
273 std::size_t computeKeyHash(K
const& key)
const {
277 !isAvalanchingHasher() ||
278 sizeof(decltype(hasher()(key))) >=
sizeof(std::size_t),
279 "hasher is not avalanching if it doesn't return enough bits");
280 return hasher()(key);
283 Key
const& keyForValue(Key
const&
v)
const {
286 Key
const& keyForValue(std::pair<Key const, MappedOrBool>
const& p)
const {
289 Key
const& keyForValue(std::pair<Key&&, MappedOrBool&&>
const& p)
const {
300 template <
typename Dummy =
int>
301 static std::pair<Key&&, MappedOrBool&&> moveValue(
302 std::pair<Key const, MappedOrBool>&
value,
303 std::enable_if_t<kIsMap, Dummy> = 0) {
307 template <
typename Dummy =
int>
308 static Value&& moveValue(
Value& value, std::enable_if_t<!kIsMap, Dummy> = 0) {
312 template <
typename P>
314 beforeBuild(std::size_t , std::size_t , P&& ) {
318 template <
typename P>
326 std::size_t alignedAllocSize(std::size_t n)
const {
327 if (kRequiredVectorAlignment <=
alignof(max_align_t) ||
328 std::is_same<ByteAlloc, std::allocator<uint8_t>>::value) {
331 return n + kRequiredVectorAlignment;
339 std::size_t chunkAllocSize,
340 BytePtr& outChunkAllocation) {
342 allocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
343 ByteAlloc{alloc()}, chunkAllocSize);
353 BytePtr chunkAllocation,
354 std::size_t chunkAllocSize) {
356 if (chunkAllocation !=
nullptr) {
357 deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
358 ByteAlloc{alloc()}, chunkAllocation, chunkAllocSize);
362 void beforeClear(std::size_t , std::size_t ) {}
364 void afterClear(std::size_t , std::size_t ) {}
366 void beforeReset(std::size_t , std::size_t ) {}
371 BytePtr chunkAllocation,
372 std::size_t chunkAllocSize) {
373 deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
374 ByteAlloc{alloc()}, chunkAllocation, chunkAllocSize);
377 void prefetchValue(Item
const&)
const {
385 void afterDestroyWithoutDeallocate(
Value*
addr, std::size_t n) {
387 memset(static_cast<void*>(addr), 0x66,
sizeof(
Value) * n);
393 template <
typename ValuePtr,
typename Item>
394 class BaseIter :
public std::iterator<
395 std::forward_iterator_tag,
397 typename std::pointer_traits<ValuePtr>::element_type>,
400 decltype(*std::declval<ValuePtr>())> {
402 using Chunk = F14Chunk<Item>;
404 typename std::pointer_traits<ValuePtr>::template rebind<Chunk>;
405 using ItemIter = F14ItemIter<ChunkPtr>;
407 using ValueConstPtr =
typename std::pointer_traits<ValuePtr>::template rebind<
408 std::add_const_t<typename std::pointer_traits<ValuePtr>::element_type>>;
416 typename HasherOrVoid,
417 typename KeyEqualOrVoid,
418 typename AllocOrVoid>
419 class ValueContainerPolicy;
421 template <
typename ValuePtr>
422 using ValueContainerIteratorBase = BaseIter<
424 std::remove_const_t<typename std::pointer_traits<ValuePtr>::element_type>>;
426 template <
typename ValuePtr>
427 class ValueContainerIterator :
public ValueContainerIteratorBase<ValuePtr> {
428 using Super = ValueContainerIteratorBase<ValuePtr>;
429 using ItemIter =
typename Super::ItemIter;
430 using ValueConstPtr =
typename Super::ValueConstPtr;
433 using pointer =
typename Super::pointer;
434 using reference =
typename Super::reference;
435 using value_type =
typename Super::value_type;
437 ValueContainerIterator() =
default;
438 ValueContainerIterator(ValueContainerIterator
const&) =
default;
439 ValueContainerIterator(ValueContainerIterator&&) =
default;
440 ValueContainerIterator& operator=(ValueContainerIterator
const&) =
default;
441 ValueContainerIterator& operator=(ValueContainerIterator&&) =
default;
442 ~ValueContainerIterator() =
default;
444 operator ValueContainerIterator<ValueConstPtr>()
const {
445 return ValueContainerIterator<ValueConstPtr>{underlying_};
448 reference operator*()
const {
449 return underlying_.item();
452 pointer operator->()
const {
453 return std::pointer_traits<pointer>::pointer_to(**
this);
456 ValueContainerIterator& operator++() {
457 underlying_.advance();
461 ValueContainerIterator operator++(
int) {
467 bool operator==(ValueContainerIterator<ValueConstPtr>
const& rhs)
const {
468 return underlying_ == rhs.underlying_;
470 bool operator!=(ValueContainerIterator<ValueConstPtr>
const& rhs)
const {
471 return !(*
this ==
rhs);
475 ItemIter underlying_;
477 explicit ValueContainerIterator(ItemIter
const& underlying)
478 : underlying_{underlying} {}
480 template <
typename K,
typename M,
typename H,
typename E,
typename A>
481 friend class ValueContainerPolicy;
483 template <
typename P>
484 friend class ValueContainerIterator;
489 typename MappedTypeOrVoid,
490 typename HasherOrVoid,
491 typename KeyEqualOrVoid,
492 typename AllocOrVoid>
493 class ValueContainerPolicy :
public BasePolicy<
499 SetOrMapValueType<Key, MappedTypeOrVoid>> {
501 using Super = BasePolicy<
507 SetOrMapValueType<Key, MappedTypeOrVoid>>;
508 using Alloc =
typename Super::Alloc;
509 using AllocTraits =
typename Super::AllocTraits;
510 using Item =
typename Super::Item;
511 using ItemIter =
typename Super::ItemIter;
515 using ByteAlloc =
typename Super::ByteAlloc;
520 using ConstIter = ValueContainerIterator<typename AllocTraits::const_pointer>;
521 using Iter = std::conditional_t<
523 ValueContainerIterator<typename AllocTraits::pointer>,
528 static constexpr
bool prefetchBeforeRehash() {
532 static constexpr
bool prefetchBeforeCopy() {
536 static constexpr
bool prefetchBeforeDestroy() {
540 static constexpr
bool destroyItemOnClear() {
548 void swapPolicy(ValueContainerPolicy& rhs) {
549 this->swapBasePolicy(rhs);
552 using Super::keyForValue;
555 "Item and Value should be the same type for ValueContainerPolicy.");
557 std::size_t computeItemHash(Item
const& item)
const {
558 return this->computeKeyHash(keyForValue(item));
561 template <
typename K>
562 bool keyMatchesItem(K
const& key, Item
const& item)
const {
563 return this->keyEqual()(key, keyForValue(item));
566 Value const& buildArgForItem(Item
const& item)
const& {
571 decltype(
auto) buildArgForItem(Item& item) && {
572 return Super::moveValue(item);
575 Value&& valueAtItemForExtract(Item& item) {
579 template <
typename...
Args>
581 constructValueAtItem(std::size_t , Item* itemAddr,
Args&&... args) {
590 assume(itemAddr !=
nullptr);
591 AllocTraits::construct(a, itemAddr, std::forward<Args>(args)...);
594 template <
typename T>
596 complainUnlessNothrowMove() {}
598 template <
typename T>
600 "use F14NodeMap/Set or mark key and mapped type move constructor nothrow")]]
std:: 602 complainUnlessNothrowMove() {}
604 void moveItemDuringRehash(Item* itemAddr, Item& src) {
605 complainUnlessNothrowMove<Key>();
606 complainUnlessNothrowMove<lift_unit_t<MappedTypeOrVoid>>();
608 constructValueAtItem(0, itemAddr, Super::moveValue(src));
609 if (destroyItemOnClear()) {
617 destroyItem(*
launder(std::addressof(src)));
624 void destroyItem(Item& item) {
625 Alloc& a = this->alloc();
626 auto ptr = std::addressof(item);
628 this->afterDestroyWithoutDeallocate(
ptr, 1);
631 template <
typename V>
632 void visitPolicyAllocationClasses(
633 std::size_t chunkAllocSize,
637 if (chunkAllocSize > 0) {
639 allocationBytesForOverAligned<ByteAlloc, kRequiredVectorAlignment>(
647 Iter makeIter(ItemIter
const& underlying)
const {
648 return Iter{underlying};
650 ConstIter makeConstIter(ItemIter
const& underlying)
const {
651 return ConstIter{underlying};
653 ItemIter
const& unwrapIter(ConstIter
const& iter)
const {
654 return iter.underlying_;
663 typename HasherOrVoid,
664 typename KeyEqualOrVoid,
665 typename AllocOrVoid>
666 class NodeContainerPolicy;
668 template <
typename ValuePtr>
669 class NodeContainerIterator :
public BaseIter<ValuePtr, NonConstPtr<ValuePtr>> {
670 using Super = BaseIter<ValuePtr, NonConstPtr<ValuePtr>>;
671 using ItemIter =
typename Super::ItemIter;
672 using ValueConstPtr =
typename Super::ValueConstPtr;
675 using pointer =
typename Super::pointer;
676 using reference =
typename Super::reference;
677 using value_type =
typename Super::value_type;
679 NodeContainerIterator() =
default;
680 NodeContainerIterator(NodeContainerIterator
const&) =
default;
681 NodeContainerIterator(NodeContainerIterator&&) =
default;
682 NodeContainerIterator& operator=(NodeContainerIterator
const&) =
default;
683 NodeContainerIterator& operator=(NodeContainerIterator&&) =
default;
684 ~NodeContainerIterator() =
default;
686 operator NodeContainerIterator<ValueConstPtr>()
const {
687 return NodeContainerIterator<ValueConstPtr>{underlying_};
690 reference operator*()
const {
691 return *underlying_.item();
694 pointer operator->()
const {
695 return std::pointer_traits<pointer>::pointer_to(**
this);
698 NodeContainerIterator& operator++() {
699 underlying_.advance();
703 NodeContainerIterator operator++(
int) {
709 bool operator==(NodeContainerIterator<ValueConstPtr>
const& rhs)
const {
710 return underlying_ == rhs.underlying_;
712 bool operator!=(NodeContainerIterator<ValueConstPtr>
const& rhs)
const {
713 return !(*
this ==
rhs);
717 ItemIter underlying_;
719 explicit NodeContainerIterator(ItemIter
const& underlying)
720 : underlying_{underlying} {}
722 template <
typename K,
typename M,
typename H,
typename E,
typename A>
723 friend class NodeContainerPolicy;
725 template <
typename P>
726 friend class NodeContainerIterator;
731 typename MappedTypeOrVoid,
732 typename HasherOrVoid,
733 typename KeyEqualOrVoid,
734 typename AllocOrVoid>
735 class NodeContainerPolicy
742 typename std::allocator_traits<Defaulted<
744 DefaultAlloc<std::conditional_t<
745 std::is_void<MappedTypeOrVoid>::value,
747 MapValueType<Key, MappedTypeOrVoid>>>>>::pointer> {
749 using Super = BasePolicy<
755 typename std::allocator_traits<Defaulted<
760 MapValueType<Key, MappedTypeOrVoid>>>>>::pointer>;
761 using Alloc =
typename Super::Alloc;
762 using AllocTraits =
typename Super::AllocTraits;
763 using Item =
typename Super::Item;
764 using ItemIter =
typename Super::ItemIter;
768 using ByteAlloc =
typename Super::ByteAlloc;
773 using ConstIter = NodeContainerIterator<typename AllocTraits::const_pointer>;
774 using Iter = std::conditional_t<
776 NodeContainerIterator<typename AllocTraits::pointer>,
781 static constexpr
bool prefetchBeforeRehash() {
785 static constexpr
bool prefetchBeforeCopy() {
789 static constexpr
bool prefetchBeforeDestroy() {
793 static constexpr
bool destroyItemOnClear() {
800 void swapPolicy(NodeContainerPolicy& rhs) {
801 this->swapBasePolicy(rhs);
804 using Super::keyForValue;
806 std::size_t computeItemHash(Item
const& item)
const {
807 return this->computeKeyHash(keyForValue(*item));
810 template <
typename K>
811 bool keyMatchesItem(K
const& key, Item
const& item)
const {
812 return this->keyEqual()(key, keyForValue(*item));
815 Value const& buildArgForItem(Item
const& item)
const& {
820 decltype(
auto) buildArgForItem(Item& item) && {
821 return Super::moveValue(*item);
824 Value&& valueAtItemForExtract(Item& item) {
828 template <
typename...
Args>
830 constructValueAtItem(std::size_t , Item* itemAddr,
Args&&... args) {
831 Alloc& a = this->alloc();
833 assume(itemAddr !=
nullptr);
834 new (itemAddr) Item{AllocTraits::allocate(a, 1)};
835 auto p = std::addressof(**itemAddr);
838 AllocTraits::construct(a, p, std::forward<Args>(args)...);
841 void moveItemDuringRehash(Item* itemAddr, Item& src) {
845 assume(itemAddr !=
nullptr);
851 void prefetchValue(Item
const& item)
const {
852 prefetchAddr(std::addressof(*item));
855 void destroyItem(Item& item) {
856 if (item !=
nullptr) {
857 Alloc& a = this->alloc();
859 AllocTraits::deallocate(a, item, 1);
864 template <
typename V>
865 void visitPolicyAllocationClasses(
866 std::size_t chunkAllocSize,
870 if (chunkAllocSize > 0) {
872 allocationBytesForOverAligned<ByteAlloc, kRequiredVectorAlignment>(
877 visitor(
sizeof(
Value), size);
883 Iter makeIter(ItemIter
const& underlying)
const {
884 return Iter{underlying};
886 ConstIter makeConstIter(ItemIter
const& underlying)
const {
887 return Iter{underlying};
889 ItemIter
const& unwrapIter(ConstIter
const& iter)
const {
890 return iter.underlying_;
898 typename MappedTypeOrVoid,
899 typename HasherOrVoid,
900 typename KeyEqualOrVoid,
901 typename AllocOrVoid>
902 class VectorContainerPolicy;
904 template <
typename ValuePtr>
905 class VectorContainerIterator :
public BaseIter<ValuePtr, uint32_t> {
906 using Super = BaseIter<ValuePtr, uint32_t>;
907 using ValueConstPtr =
typename Super::ValueConstPtr;
910 using pointer =
typename Super::pointer;
911 using reference =
typename Super::reference;
912 using value_type =
typename Super::value_type;
914 VectorContainerIterator() =
default;
915 VectorContainerIterator(VectorContainerIterator
const&) =
default;
916 VectorContainerIterator(VectorContainerIterator&&) =
default;
917 VectorContainerIterator& operator=(VectorContainerIterator
const&) =
default;
918 VectorContainerIterator& operator=(VectorContainerIterator&&) =
default;
919 ~VectorContainerIterator() =
default;
921 operator VectorContainerIterator<ValueConstPtr>()
const {
922 return VectorContainerIterator<ValueConstPtr>{
current_, lowest_};
925 reference operator*()
const {
929 pointer operator->()
const {
933 VectorContainerIterator& operator++() {
942 VectorContainerIterator operator++(
int) {
948 bool operator==(VectorContainerIterator<ValueConstPtr>
const& rhs)
const {
951 bool operator!=(VectorContainerIterator<ValueConstPtr>
const& rhs)
const {
952 return !(*
this ==
rhs);
959 explicit VectorContainerIterator(ValuePtr
current, ValuePtr lowest)
960 : current_(current), lowest_(lowest) {}
962 std::size_t index()
const {
963 return current_ - lowest_;
966 template <
typename K,
typename M,
typename H,
typename E,
typename A>
967 friend class VectorContainerPolicy;
969 template <
typename P>
970 friend class VectorContainerIterator;
973 struct VectorContainerIndexSearch {
979 typename MappedTypeOrVoid,
980 typename HasherOrVoid,
981 typename KeyEqualOrVoid,
982 typename AllocOrVoid>
983 class VectorContainerPolicy :
public BasePolicy<
991 using Super = BasePolicy<
998 using Alloc =
typename Super::Alloc;
999 using AllocTraits =
typename Super::AllocTraits;
1000 using ByteAlloc =
typename Super::ByteAlloc;
1001 using ByteAllocTraits =
typename Super::ByteAllocTraits;
1002 using BytePtr =
typename Super::BytePtr;
1003 using Hasher =
typename Super::Hasher;
1004 using Item =
typename Super::Item;
1005 using ItemIter =
typename Super::ItemIter;
1006 using KeyEqual =
typename Super::KeyEqual;
1009 using Super::kAllocIsAlwaysEqual;
1012 using Super::kIsMap;
1015 static constexpr
bool kEnableItemIteration =
false;
1017 using InternalSizeType = Item;
1020 VectorContainerIterator<typename AllocTraits::const_pointer>;
1021 using Iter = std::conditional_t<
1023 VectorContainerIterator<typename AllocTraits::pointer>,
1025 using ConstReverseIter =
typename AllocTraits::const_pointer;
1026 using ReverseIter = std::
1027 conditional_t<kIsMap, typename AllocTraits::pointer, ConstReverseIter>;
1029 using ValuePtr =
typename AllocTraits::pointer;
1033 static constexpr
bool prefetchBeforeRehash() {
1037 static constexpr
bool prefetchBeforeCopy() {
1041 static constexpr
bool prefetchBeforeDestroy() {
1045 static constexpr
bool destroyItemOnClear() {
1050 static constexpr
bool valueIsTriviallyCopyable() {
1057 VectorContainerPolicy(
1058 Hasher
const& hasher,
1059 KeyEqual
const& keyEqual,
1061 : Super{hasher, keyEqual, alloc} {}
1063 VectorContainerPolicy(VectorContainerPolicy
const& rhs) : Super{rhs} {
1067 VectorContainerPolicy(VectorContainerPolicy
const& rhs,
Alloc const& alloc)
1068 : Super{
rhs, alloc} {
1072 VectorContainerPolicy(VectorContainerPolicy&& rhs) noexcept
1073 : Super{
std::move(rhs)}, values_{rhs.values_} {
1074 rhs.values_ =
nullptr;
1077 VectorContainerPolicy(
1078 VectorContainerPolicy&& rhs,
1079 Alloc const& alloc) noexcept
1081 if (kAllocIsAlwaysEqual || this->alloc() == rhs.alloc()) {
1083 values_ = rhs.values_;
1084 rhs.values_ =
nullptr;
1091 VectorContainerPolicy& operator=(VectorContainerPolicy
const& rhs) {
1094 Super::operator=(rhs);
1099 VectorContainerPolicy& operator=(VectorContainerPolicy&& rhs) noexcept {
1104 kAllocIsAlwaysEqual || this->alloc() == rhs.alloc();
1107 values_ = rhs.values_;
1108 rhs.values_ =
nullptr;
1114 void swapPolicy(VectorContainerPolicy& rhs) {
1116 this->swapBasePolicy(rhs);
1117 swap(values_, rhs.values_);
1120 template <
typename K>
1121 std::size_t computeKeyHash(K
const& key)
const {
1125 return this->hasher()(key);
1128 std::size_t computeKeyHash(VectorContainerIndexSearch
const& key)
const {
1129 return computeItemHash(key.index_);
1132 using Super::keyForValue;
1134 std::size_t computeItemHash(Item
const& item)
const {
1135 return this->computeKeyHash(keyForValue(values_[item]));
1138 bool keyMatchesItem(VectorContainerIndexSearch
const& key, Item
const& item)
1140 return key.index_ == item;
1143 template <
typename K>
1144 bool keyMatchesItem(K
const& key, Item
const& item)
const {
1145 return this->keyEqual()(key, keyForValue(values_[item]));
1148 Key
const& keyForValue(VectorContainerIndexSearch
const& arg)
const {
1149 return keyForValue(values_[arg.index_]);
1152 VectorContainerIndexSearch buildArgForItem(Item
const& item)
const {
1156 Value&& valueAtItemForExtract(Item& item) {
1160 void constructValueAtItem(
1163 VectorContainerIndexSearch arg) {
1164 *itemAddr = arg.index_;
1167 template <
typename...
Args>
1168 void constructValueAtItem(std::size_t size, Item* itemAddr,
Args&&... args) {
1169 Alloc& a = this->alloc();
1171 *itemAddr =
static_cast<InternalSizeType
>(
size);
1172 auto dst = std::addressof(values_[size]);
1175 AllocTraits::construct(a, dst, std::forward<Args>(args)...);
1178 void moveItemDuringRehash(Item* itemAddr, Item& src) {
1182 void prefetchValue(Item
const& item)
const {
1183 prefetchAddr(std::addressof(values_[item]));
1186 void destroyItem(Item&) {}
1188 template <
typename T>
1190 complainUnlessNothrowMove() {}
1192 template <
typename T>
1194 "use F14NodeMap/Set or mark key and mapped type move constructor nothrow")]]
std:: 1196 complainUnlessNothrowMove() {}
1199 complainUnlessNothrowMove<Key>();
1200 complainUnlessNothrowMove<lift_unit_t<MappedTypeOrVoid>>();
1203 if (valueIsTriviallyCopyable()) {
1204 std::memcpy(static_cast<void*>(dst), src, n *
sizeof(
Value));
1206 for (std::size_t
i = 0;
i < n; ++
i, ++src, ++dst) {
1209 AllocTraits::construct(a, dst, Super::moveValue(*src));
1217 this->afterDestroyWithoutDeallocate(origSrc, n);
1220 template <
typename P,
typename V>
1221 bool beforeBuildImpl(std::size_t size, P&& rhs, V
const& constructorArgFor) {
1222 Alloc& a = this->alloc();
1226 auto src = std::addressof(rhs.values_[0]);
1227 Value* dst = std::addressof(values_[0]);
1229 if (valueIsTriviallyCopyable()) {
1230 std::memcpy(dst, src, size *
sizeof(
Value));
1232 for (std::size_t
i = 0;
i <
size; ++
i, ++src, ++dst) {
1236 AllocTraits::construct(a, dst, constructorArgFor(*src));
1252 VectorContainerPolicy
const& rhs) {
1253 return beforeBuildImpl(size, rhs, [](
Value const&
v) {
return v; });
1259 VectorContainerPolicy&& rhs) {
1260 return beforeBuildImpl(
1261 size, rhs, [](
Value&
v) {
return Super::moveValue(v); });
1264 template <
typename P>
1281 static std::size_t valuesOffset(std::size_t prefixBytes) {
1283 if (
alignof(
Value) > 8) {
1284 prefixBytes = -(-prefixBytes & ~(
alignof(
Value) - 1));
1292 static std::size_t allocSize(
1293 std::size_t prefixBytes,
1294 std::size_t valueCapacity) {
1295 return valuesOffset(prefixBytes) +
sizeof(
Value) * valueCapacity;
1299 ValuePtr beforeRehash(
1301 std::size_t oldCapacity,
1302 std::size_t newCapacity,
1303 std::size_t chunkAllocSize,
1304 BytePtr& outChunkAllocation) {
1306 size <= oldCapacity && ((values_ ==
nullptr) == (oldCapacity == 0)) &&
1311 outChunkAllocation =
1312 allocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
1313 ByteAlloc{Super::alloc()}, allocSize(chunkAllocSize, newCapacity));
1315 ValuePtr before = values_;
1316 ValuePtr after = std::pointer_traits<ValuePtr>::pointer_to(
1317 *static_cast<Value*>(static_cast<void*>(
1318 &*outChunkAllocation + valuesOffset(chunkAllocSize))));
1321 Alloc& a{this->alloc()};
1322 transfer(a, std::addressof(before[0]), std::addressof(after[0]), size);
1331 Alloc& a = this->alloc();
1333 transfer(a, std::addressof(values_[0]), std::addressof(state[0]), size);
1342 std::size_t oldCapacity,
1343 std::size_t newCapacity,
1344 BytePtr chunkAllocation,
1345 std::size_t chunkAllocSize) {
1347 afterFailedRehash(state, size);
1352 if (chunkAllocation !=
nullptr) {
1353 deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
1354 ByteAlloc{Super::alloc()},
1356 allocSize(chunkAllocSize, (success ? oldCapacity : newCapacity)));
1360 void beforeClear(std::size_t size, std::size_t capacity) {
1362 size <= capacity && ((values_ ==
nullptr) == (capacity == 0)),
"");
1363 Alloc& a = this->alloc();
1364 for (std::size_t
i = 0;
i <
size; ++
i) {
1369 void beforeReset(std::size_t size, std::size_t capacity) {
1370 beforeClear(size, capacity);
1375 std::size_t capacity,
1376 BytePtr chunkAllocation,
1377 std::size_t chunkAllocSize) {
1378 if (chunkAllocation !=
nullptr) {
1379 deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
1380 ByteAlloc{Super::alloc()},
1382 allocSize(chunkAllocSize, capacity));
1387 template <
typename V>
1388 void visitPolicyAllocationClasses(
1389 std::size_t chunkAllocSize,
1391 std::size_t capacity,
1392 V&& visitor)
const {
1394 if (chunkAllocSize > 0) {
1396 allocationBytesForOverAligned<ByteAlloc, kRequiredVectorAlignment>(
1397 allocSize(chunkAllocSize, capacity)),
1404 Iter linearBegin(std::size_t size)
const {
1405 return Iter{(size > 0 ? values_ + size - 1 :
nullptr), values_};
1408 Iter linearEnd()
const {
1409 return Iter{
nullptr,
nullptr};
1414 Iter makeIter(ItemIter
const& underlying)
const {
1415 if (underlying.atEnd()) {
1418 assume(values_ + underlying.item() !=
nullptr);
1419 assume(values_ !=
nullptr);
1420 return Iter{values_ + underlying.item(), values_};
1424 ConstIter makeConstIter(ItemIter
const& underlying)
const {
1425 return makeIter(underlying);
1428 Item iterToIndex(ConstIter
const& iter)
const {
1429 auto n = iter.index();
1431 return static_cast<Item
>(n);
1434 Iter indexToIter(Item index)
const {
1435 return Iter{values_ + index, values_};
1438 Iter iter(ReverseIter it) {
1439 return Iter{it, values_};
1442 ConstIter iter(ConstReverseIter it)
const {
1443 return ConstIter{it, values_};
1446 ReverseIter riter(
Iter it) {
1450 ConstReverseIter riter(ConstIter it)
const {
1454 ValuePtr values_{
nullptr};
1458 template <
typename,
typename,
typename,
typename,
typename>
class Policy,
1464 using MapPolicyWithDefaults = Policy<
1467 VoidDefault<Hasher, DefaultHasher<Key>>,
1468 VoidDefault<KeyEqual, DefaultKeyEqual<Key>>,
1469 VoidDefault<Alloc, DefaultAlloc<std::pair<Key const, Mapped>>>>;
1472 template <
typename,
typename,
typename,
typename,
typename>
class Policy,
1477 using SetPolicyWithDefaults = Policy<
1480 VoidDefault<Hasher, DefaultHasher<Key>>,
1481 VoidDefault<KeyEqual, DefaultKeyEqual<Key>>,
1482 VoidDefault<Alloc, DefaultAlloc<Key>>>;
1488 #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE impl::Inherit_< List > Inherit
bool operator!=(SwapTrackingAlloc< T1 > const &, SwapTrackingAlloc< T2 > const &)
constexpr detail::Map< Move > move
internal::KeyMatcher< M > Key(M inner_matcher)
constexpr bool kIsSanitizeAddress
internal::ArgsMatcher< InnerMatcher > Args(const InnerMatcher &matcher)
—— Concurrent Priority Queue Implementation ——
requires E e noexcept(noexcept(s.error(std::move(e))))
std::allocator< T > DefaultAlloc
FOLLY_PUSH_WARNING RHS rhs
constexpr auto size(C const &c) -> decltype(c.size())
def Iter(n, format, sep='')
bool Value(const T &value, M matcher)
static const char *const value
uint64_t value(const typename LockFreeRingBuffer< T, Atom >::Cursor &rbcursor)
FOLLY_NODISCARD T * launder(T *in) noexcept
void swap(SwapTrackingAlloc< T > &, SwapTrackingAlloc< T > &)
FOLLY_ALWAYS_INLINE void assume(bool cond)
ThreadPoolListHook * addr
#define FOLLY_SAFE_DCHECK(expr, msg)
bool operator==(SwapTrackingAlloc< T1 > const &, SwapTrackingAlloc< T2 > const &)