F14Policy.h 43 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487
  1. /*
  2. * Copyright 2017-present Facebook, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #pragma once
  17. #include <memory>
  18. #include <type_traits>
  19. #include <utility>
  20. #include <folly/Memory.h>
  21. #include <folly/Portability.h>
  22. #include <folly/Unit.h>
  23. #include <folly/container/detail/F14Table.h>
  24. #include <folly/hash/Hash.h>
  25. #include <folly/lang/Align.h>
  26. #include <folly/lang/SafeAssert.h>
  27. #include <folly/memory/Malloc.h>
  28. #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
  29. namespace folly {
  30. namespace f14 {
  31. namespace detail {
  32. template <typename Ptr>
  33. using NonConstPtr = typename std::pointer_traits<Ptr>::template rebind<
  34. std::remove_const_t<typename std::pointer_traits<Ptr>::element_type>>;
  35. template <typename KeyType, typename MappedType>
  36. using MapValueType = std::pair<KeyType const, MappedType>;
  37. template <typename KeyType, typename MappedTypeOrVoid>
  38. using SetOrMapValueType = std::conditional_t<
  39. std::is_same<MappedTypeOrVoid, void>::value,
  40. KeyType,
  41. MapValueType<KeyType, MappedTypeOrVoid>>;
  42. // Used to enable EBO for Hasher, KeyEqual, and Alloc. std::tuple of
  43. // all empty objects is empty in libstdc++ but not libc++.
  44. template <
  45. char Tag,
  46. typename T,
  47. bool Inherit = std::is_empty<T>::value && !std::is_final<T>::value>
  48. struct ObjectHolder {
  49. T value_;
  50. template <typename... Args>
  51. ObjectHolder(Args&&... args) : value_{std::forward<Args>(args)...} {}
  52. T& operator*() {
  53. return value_;
  54. }
  55. T const& operator*() const {
  56. return value_;
  57. }
  58. };
  59. template <char Tag, typename T>
  60. struct ObjectHolder<Tag, T, true> : private T {
  61. template <typename... Args>
  62. ObjectHolder(Args&&... args) : T{std::forward<Args>(args)...} {}
  63. T& operator*() {
  64. return *this;
  65. }
  66. T const& operator*() const {
  67. return *this;
  68. }
  69. };
  70. // Policy provides the functionality of hasher, key_equal, and
  71. // allocator_type. In addition, it can add indirection to the values
  72. // contained in the base table by defining a non-trivial value() method.
  73. //
  74. // To facilitate stateful implementations it is guaranteed that there
  75. // will be a 1:1 relationship between BaseTable and Policy instance:
  76. // policies will only be copied when their owning table is copied, and
  77. // they will only be moved when their owning table is moved.
  78. //
  79. // Key equality will have the user-supplied search key as its first
  80. // argument and the table contents as its second. Heterogeneous lookup
  81. // should be handled on the first argument.
  82. //
  83. // Item is the data stored inline in the hash table's chunks. The policy
  84. // controls how this is mapped to the corresponding Value.
  85. //
  86. // The policies defined in this file work for either set or map types.
  87. // Most of the functionality is identical. A few methods detect the
  88. // collection type by checking to see if MappedType is void, and then use
  89. // SFINAE to select the appropriate implementation.
  90. template <
  91. typename KeyType,
  92. typename MappedTypeOrVoid,
  93. typename HasherOrVoid,
  94. typename KeyEqualOrVoid,
  95. typename AllocOrVoid,
  96. typename ItemType>
  97. struct BasePolicy
  98. : private ObjectHolder<
  99. 'H',
  100. Defaulted<HasherOrVoid, DefaultHasher<KeyType>>>,
  101. private ObjectHolder<
  102. 'E',
  103. Defaulted<KeyEqualOrVoid, DefaultKeyEqual<KeyType>>>,
  104. private ObjectHolder<
  105. 'A',
  106. Defaulted<
  107. AllocOrVoid,
  108. DefaultAlloc<SetOrMapValueType<KeyType, MappedTypeOrVoid>>>> {
  109. //////// user-supplied types
  110. using Key = KeyType;
  111. using Mapped = MappedTypeOrVoid;
  112. using Value = SetOrMapValueType<Key, Mapped>;
  113. using Item = ItemType;
  114. using Hasher = Defaulted<HasherOrVoid, DefaultHasher<Key>>;
  115. using KeyEqual = Defaulted<KeyEqualOrVoid, DefaultKeyEqual<Key>>;
  116. using Alloc = Defaulted<AllocOrVoid, DefaultAlloc<Value>>;
  117. using AllocTraits = std::allocator_traits<Alloc>;
  118. using ByteAlloc = typename AllocTraits::template rebind_alloc<uint8_t>;
  119. using ByteAllocTraits = typename std::allocator_traits<ByteAlloc>;
  120. using BytePtr = typename ByteAllocTraits::pointer;
  121. //////// info about user-supplied types
  122. static_assert(
  123. std::is_same<typename AllocTraits::value_type, Value>::value,
  124. "wrong allocator value_type");
  125. private:
  126. using HasherHolder = ObjectHolder<'H', Hasher>;
  127. using KeyEqualHolder = ObjectHolder<'E', KeyEqual>;
  128. using AllocHolder = ObjectHolder<'A', Alloc>;
  129. // emulate c++17's std::allocator_traits<A>::is_always_equal
  130. template <typename A, typename = void>
  131. struct AllocIsAlwaysEqual : std::is_empty<A> {};
  132. template <typename A>
  133. struct AllocIsAlwaysEqual<A, typename A::is_always_equal>
  134. : A::is_always_equal {};
  135. // emulate c++17 has std::is_nothrow_swappable
  136. template <typename T>
  137. static constexpr bool isNothrowSwap() {
  138. using std::swap;
  139. return noexcept(swap(std::declval<T&>(), std::declval<T&>()));
  140. }
  141. public:
  142. static constexpr bool kAllocIsAlwaysEqual = AllocIsAlwaysEqual<Alloc>::value;
  143. static constexpr bool kDefaultConstructIsNoexcept =
  144. std::is_nothrow_default_constructible<Hasher>::value &&
  145. std::is_nothrow_default_constructible<KeyEqual>::value &&
  146. std::is_nothrow_default_constructible<Alloc>::value;
  147. static constexpr bool kSwapIsNoexcept = kAllocIsAlwaysEqual &&
  148. isNothrowSwap<Hasher>() && isNothrowSwap<KeyEqual>();
  149. static constexpr bool isAvalanchingHasher() {
  150. return IsAvalanchingHasher<Hasher, Key>::value;
  151. }
  152. //////// internal types and constants
  153. using InternalSizeType = std::size_t;
  154. // if false, F14Table will be smaller but F14Table::begin() won't work
  155. static constexpr bool kEnableItemIteration = true;
  156. using Chunk = F14Chunk<Item>;
  157. using ChunkPtr = typename std::pointer_traits<
  158. typename AllocTraits::pointer>::template rebind<Chunk>;
  159. using ItemIter = F14ItemIter<ChunkPtr>;
  160. static constexpr bool kIsMap = !std::is_same<Key, Value>::value;
  161. static_assert(
  162. kIsMap == !std::is_void<MappedTypeOrVoid>::value,
  163. "Assumption for the kIsMap check violated.");
  164. using MappedOrBool = std::conditional_t<kIsMap, Mapped, bool>;
  165. //////// methods
  166. BasePolicy(Hasher const& hasher, KeyEqual const& keyEqual, Alloc const& alloc)
  167. : HasherHolder{hasher}, KeyEqualHolder{keyEqual}, AllocHolder{alloc} {}
  168. BasePolicy(BasePolicy const& rhs)
  169. : HasherHolder{rhs.hasher()},
  170. KeyEqualHolder{rhs.keyEqual()},
  171. AllocHolder{
  172. AllocTraits::select_on_container_copy_construction(rhs.alloc())} {}
  173. BasePolicy(BasePolicy const& rhs, Alloc const& alloc)
  174. : HasherHolder{rhs.hasher()},
  175. KeyEqualHolder{rhs.keyEqual()},
  176. AllocHolder{alloc} {}
  177. BasePolicy(BasePolicy&& rhs) noexcept
  178. : HasherHolder{std::move(rhs.hasher())},
  179. KeyEqualHolder{std::move(rhs.keyEqual())},
  180. AllocHolder{std::move(rhs.alloc())} {}
  181. BasePolicy(BasePolicy&& rhs, Alloc const& alloc) noexcept
  182. : HasherHolder{std::move(rhs.hasher())},
  183. KeyEqualHolder{std::move(rhs.keyEqual())},
  184. AllocHolder{alloc} {}
  185. BasePolicy& operator=(BasePolicy const& rhs) {
  186. hasher() = rhs.hasher();
  187. keyEqual() = rhs.keyEqual();
  188. if (AllocTraits::propagate_on_container_copy_assignment::value) {
  189. alloc() = rhs.alloc();
  190. }
  191. return *this;
  192. }
  193. BasePolicy& operator=(BasePolicy&& rhs) noexcept {
  194. hasher() = std::move(rhs.hasher());
  195. keyEqual() = std::move(rhs.keyEqual());
  196. if (AllocTraits::propagate_on_container_move_assignment::value) {
  197. alloc() = std::move(rhs.alloc());
  198. }
  199. return *this;
  200. }
  201. void swapBasePolicy(BasePolicy& rhs) {
  202. using std::swap;
  203. swap(hasher(), rhs.hasher());
  204. swap(keyEqual(), rhs.keyEqual());
  205. if (AllocTraits::propagate_on_container_swap::value) {
  206. swap(alloc(), rhs.alloc());
  207. }
  208. }
  209. Hasher& hasher() {
  210. return *static_cast<HasherHolder&>(*this);
  211. }
  212. Hasher const& hasher() const {
  213. return *static_cast<HasherHolder const&>(*this);
  214. }
  215. KeyEqual& keyEqual() {
  216. return *static_cast<KeyEqualHolder&>(*this);
  217. }
  218. KeyEqual const& keyEqual() const {
  219. return *static_cast<KeyEqualHolder const&>(*this);
  220. }
  221. Alloc& alloc() {
  222. return *static_cast<AllocHolder&>(*this);
  223. }
  224. Alloc const& alloc() const {
  225. return *static_cast<AllocHolder const&>(*this);
  226. }
  227. template <typename K>
  228. std::size_t computeKeyHash(K const& key) const {
  229. static_assert(
  230. isAvalanchingHasher() == IsAvalanchingHasher<Hasher, K>::value, "");
  231. static_assert(
  232. !isAvalanchingHasher() ||
  233. sizeof(decltype(hasher()(key))) >= sizeof(std::size_t),
  234. "hasher is not avalanching if it doesn't return enough bits");
  235. return hasher()(key);
  236. }
  237. Key const& keyForValue(Key const& v) const {
  238. return v;
  239. }
  240. Key const& keyForValue(std::pair<Key const, MappedOrBool> const& p) const {
  241. return p.first;
  242. }
  243. Key const& keyForValue(std::pair<Key&&, MappedOrBool&&> const& p) const {
  244. return p.first;
  245. }
  246. // map's choice of pair<K const, T> as value_type is unfortunate,
  247. // because it means we either need a proxy iterator, a pointless key
  248. // copy when moving items during rehash, or some sort of UB hack.
  249. //
  250. // This code implements the hack. Use moveValue(v) instead of
  251. // std::move(v) as the source of a move construction. enable_if_t is
  252. // used so that this works for maps while being a no-op for sets.
  253. template <typename Dummy = int>
  254. static std::pair<Key&&, MappedOrBool&&> moveValue(
  255. std::pair<Key const, MappedOrBool>& value,
  256. std::enable_if_t<kIsMap, Dummy> = 0) {
  257. return {std::move(const_cast<Key&>(value.first)), std::move(value.second)};
  258. }
  259. template <typename Dummy = int>
  260. static Value&& moveValue(Value& value, std::enable_if_t<!kIsMap, Dummy> = 0) {
  261. return std::move(value);
  262. }
  263. template <typename P>
  264. bool
  265. beforeBuild(std::size_t /*size*/, std::size_t /*capacity*/, P&& /*rhs*/) {
  266. return false;
  267. }
  268. template <typename P>
  269. void afterBuild(
  270. bool /*undoState*/,
  271. bool /*success*/,
  272. std::size_t /*size*/,
  273. std::size_t /*capacity*/,
  274. P&& /*rhs*/) {}
  275. std::size_t alignedAllocSize(std::size_t n) const {
  276. if (kRequiredVectorAlignment <= alignof(max_align_t) ||
  277. std::is_same<ByteAlloc, std::allocator<uint8_t>>::value) {
  278. return n;
  279. } else {
  280. return n + kRequiredVectorAlignment;
  281. }
  282. }
  283. bool beforeRehash(
  284. std::size_t /*size*/,
  285. std::size_t /*oldCapacity*/,
  286. std::size_t /*newCapacity*/,
  287. std::size_t chunkAllocSize,
  288. BytePtr& outChunkAllocation) {
  289. outChunkAllocation =
  290. allocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  291. ByteAlloc{alloc()}, chunkAllocSize);
  292. return false;
  293. }
  294. void afterRehash(
  295. bool /*undoState*/,
  296. bool /*success*/,
  297. std::size_t /*size*/,
  298. std::size_t /*oldCapacity*/,
  299. std::size_t /*newCapacity*/,
  300. BytePtr chunkAllocation,
  301. std::size_t chunkAllocSize) {
  302. // on success, this will be the old allocation, on failure the new one
  303. if (chunkAllocation != nullptr) {
  304. deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  305. ByteAlloc{alloc()}, chunkAllocation, chunkAllocSize);
  306. }
  307. }
  308. void beforeClear(std::size_t /*size*/, std::size_t /*capacity*/) {}
  309. void afterClear(std::size_t /*size*/, std::size_t /*capacity*/) {}
  310. void beforeReset(std::size_t /*size*/, std::size_t /*capacity*/) {}
  311. void afterReset(
  312. std::size_t /*size*/,
  313. std::size_t /*capacity*/,
  314. BytePtr chunkAllocation,
  315. std::size_t chunkAllocSize) {
  316. deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  317. ByteAlloc{alloc()}, chunkAllocation, chunkAllocSize);
  318. }
  319. void prefetchValue(Item const&) const {
  320. // Subclass should disable with prefetchBeforeRehash(),
  321. // prefetchBeforeCopy(), and prefetchBeforeDestroy(). if they don't
  322. // override this method, because neither gcc nor clang can figure
  323. // out that DenseMaskIter with an empty body can be elided.
  324. FOLLY_SAFE_DCHECK(false, "should be disabled");
  325. }
  326. void afterDestroyWithoutDeallocate(Value* addr, std::size_t n) {
  327. if (kIsSanitizeAddress) {
  328. memset(static_cast<void*>(addr), 0x66, sizeof(Value) * n);
  329. }
  330. }
  331. };
  332. // BaseIter is a convenience for concrete set and map implementations
  333. template <typename ValuePtr, typename Item>
  334. class BaseIter : public std::iterator<
  335. std::forward_iterator_tag,
  336. std::remove_const_t<
  337. typename std::pointer_traits<ValuePtr>::element_type>,
  338. std::ptrdiff_t,
  339. ValuePtr,
  340. decltype(*std::declval<ValuePtr>())> {
  341. protected:
  342. using Chunk = F14Chunk<Item>;
  343. using ChunkPtr =
  344. typename std::pointer_traits<ValuePtr>::template rebind<Chunk>;
  345. using ItemIter = F14ItemIter<ChunkPtr>;
  346. using ValueConstPtr = typename std::pointer_traits<ValuePtr>::template rebind<
  347. std::add_const_t<typename std::pointer_traits<ValuePtr>::element_type>>;
  348. };
  349. //////// ValueContainer
  350. template <
  351. typename Key,
  352. typename Mapped,
  353. typename HasherOrVoid,
  354. typename KeyEqualOrVoid,
  355. typename AllocOrVoid>
  356. class ValueContainerPolicy;
  357. template <typename ValuePtr>
  358. using ValueContainerIteratorBase = BaseIter<
  359. ValuePtr,
  360. std::remove_const_t<typename std::pointer_traits<ValuePtr>::element_type>>;
  361. template <typename ValuePtr>
  362. class ValueContainerIterator : public ValueContainerIteratorBase<ValuePtr> {
  363. using Super = ValueContainerIteratorBase<ValuePtr>;
  364. using ItemIter = typename Super::ItemIter;
  365. using ValueConstPtr = typename Super::ValueConstPtr;
  366. public:
  367. using pointer = typename Super::pointer;
  368. using reference = typename Super::reference;
  369. using value_type = typename Super::value_type;
  370. ValueContainerIterator() = default;
  371. ValueContainerIterator(ValueContainerIterator const&) = default;
  372. ValueContainerIterator(ValueContainerIterator&&) = default;
  373. ValueContainerIterator& operator=(ValueContainerIterator const&) = default;
  374. ValueContainerIterator& operator=(ValueContainerIterator&&) = default;
  375. ~ValueContainerIterator() = default;
  376. /*implicit*/ operator ValueContainerIterator<ValueConstPtr>() const {
  377. return ValueContainerIterator<ValueConstPtr>{underlying_};
  378. }
  379. reference operator*() const {
  380. return underlying_.item();
  381. }
  382. pointer operator->() const {
  383. return std::pointer_traits<pointer>::pointer_to(**this);
  384. }
  385. ValueContainerIterator& operator++() {
  386. underlying_.advance();
  387. return *this;
  388. }
  389. ValueContainerIterator operator++(int) {
  390. auto cur = *this;
  391. ++*this;
  392. return cur;
  393. }
  394. bool operator==(ValueContainerIterator<ValueConstPtr> const& rhs) const {
  395. return underlying_ == rhs.underlying_;
  396. }
  397. bool operator!=(ValueContainerIterator<ValueConstPtr> const& rhs) const {
  398. return !(*this == rhs);
  399. }
  400. private:
  401. ItemIter underlying_;
  402. explicit ValueContainerIterator(ItemIter const& underlying)
  403. : underlying_{underlying} {}
  404. template <typename K, typename M, typename H, typename E, typename A>
  405. friend class ValueContainerPolicy;
  406. template <typename P>
  407. friend class ValueContainerIterator;
  408. };
  409. template <
  410. typename Key,
  411. typename MappedTypeOrVoid,
  412. typename HasherOrVoid,
  413. typename KeyEqualOrVoid,
  414. typename AllocOrVoid>
  415. class ValueContainerPolicy : public BasePolicy<
  416. Key,
  417. MappedTypeOrVoid,
  418. HasherOrVoid,
  419. KeyEqualOrVoid,
  420. AllocOrVoid,
  421. SetOrMapValueType<Key, MappedTypeOrVoid>> {
  422. public:
  423. using Super = BasePolicy<
  424. Key,
  425. MappedTypeOrVoid,
  426. HasherOrVoid,
  427. KeyEqualOrVoid,
  428. AllocOrVoid,
  429. SetOrMapValueType<Key, MappedTypeOrVoid>>;
  430. using Alloc = typename Super::Alloc;
  431. using AllocTraits = typename Super::AllocTraits;
  432. using Item = typename Super::Item;
  433. using ItemIter = typename Super::ItemIter;
  434. using Value = typename Super::Value;
  435. private:
  436. using ByteAlloc = typename Super::ByteAlloc;
  437. using Super::kIsMap;
  438. public:
  439. using ConstIter = ValueContainerIterator<typename AllocTraits::const_pointer>;
  440. using Iter = std::conditional_t<
  441. kIsMap,
  442. ValueContainerIterator<typename AllocTraits::pointer>,
  443. ConstIter>;
  444. //////// F14Table policy
  445. static constexpr bool prefetchBeforeRehash() {
  446. return false;
  447. }
  448. static constexpr bool prefetchBeforeCopy() {
  449. return false;
  450. }
  451. static constexpr bool prefetchBeforeDestroy() {
  452. return false;
  453. }
  454. static constexpr bool destroyItemOnClear() {
  455. return !std::is_trivially_destructible<Item>::value ||
  456. !AllocatorHasDefaultObjectDestroy<Alloc, Item>::value;
  457. }
  458. // inherit constructors
  459. using Super::Super;
  460. void swapPolicy(ValueContainerPolicy& rhs) {
  461. this->swapBasePolicy(rhs);
  462. }
  463. using Super::keyForValue;
  464. static_assert(
  465. std::is_same<Item, Value>::value,
  466. "Item and Value should be the same type for ValueContainerPolicy.");
  467. std::size_t computeItemHash(Item const& item) const {
  468. return this->computeKeyHash(keyForValue(item));
  469. }
  470. template <typename K>
  471. bool keyMatchesItem(K const& key, Item const& item) const {
  472. return this->keyEqual()(key, keyForValue(item));
  473. }
  474. Value const& buildArgForItem(Item const& item) const& {
  475. return item;
  476. }
  477. // buildArgForItem(Item&)&& is used when moving between unequal allocators
  478. decltype(auto) buildArgForItem(Item& item) && {
  479. return Super::moveValue(item);
  480. }
  481. Value&& valueAtItemForExtract(Item& item) {
  482. return std::move(item);
  483. }
  484. template <typename... Args>
  485. void
  486. constructValueAtItem(std::size_t /*size*/, Item* itemAddr, Args&&... args) {
  487. Alloc& a = this->alloc();
  488. // GCC < 6 doesn't use the fact that itemAddr came from a reference
  489. // to avoid a null-check in the placement new. folly::assume-ing it
  490. // here gets rid of that branch. The branch is very predictable,
  491. // but spoils some further optimizations. All clang versions that
  492. // compile folly seem to be okay.
  493. //
  494. // TODO(T31574848): clean up assume-s used to optimize placement new
  495. assume(itemAddr != nullptr);
  496. AllocTraits::construct(a, itemAddr, std::forward<Args>(args)...);
  497. }
  498. template <typename T>
  499. std::enable_if_t<std::is_nothrow_move_constructible<T>::value>
  500. complainUnlessNothrowMove() {}
  501. template <typename T>
  502. [[deprecated(
  503. "use F14NodeMap/Set or mark key and mapped type move constructor nothrow")]] std::
  504. enable_if_t<!std::is_nothrow_move_constructible<T>::value>
  505. complainUnlessNothrowMove() {}
  506. void moveItemDuringRehash(Item* itemAddr, Item& src) {
  507. complainUnlessNothrowMove<Key>();
  508. complainUnlessNothrowMove<lift_unit_t<MappedTypeOrVoid>>();
  509. constructValueAtItem(0, itemAddr, Super::moveValue(src));
  510. if (destroyItemOnClear()) {
  511. if (kIsMap) {
  512. // Laundering in the standard is only described as a solution
  513. // for changes to const fields due to the creation of a new
  514. // object lifetime (destroy and then placement new in the same
  515. // location), but it seems highly likely that it will also cause
  516. // the compiler to drop such assumptions that are violated due
  517. // to our UB const_cast in moveValue.
  518. destroyItem(*launder(std::addressof(src)));
  519. } else {
  520. destroyItem(src);
  521. }
  522. }
  523. }
  524. void destroyItem(Item& item) {
  525. Alloc& a = this->alloc();
  526. auto ptr = std::addressof(item);
  527. AllocTraits::destroy(a, ptr);
  528. this->afterDestroyWithoutDeallocate(ptr, 1);
  529. }
  530. template <typename V>
  531. void visitPolicyAllocationClasses(
  532. std::size_t chunkAllocSize,
  533. std::size_t /*size*/,
  534. std::size_t /*capacity*/,
  535. V&& visitor) const {
  536. if (chunkAllocSize > 0) {
  537. visitor(
  538. allocationBytesForOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  539. chunkAllocSize),
  540. 1);
  541. }
  542. }
  543. //////// F14BasicMap/Set policy
  544. Iter makeIter(ItemIter const& underlying) const {
  545. return Iter{underlying};
  546. }
  547. ConstIter makeConstIter(ItemIter const& underlying) const {
  548. return ConstIter{underlying};
  549. }
  550. ItemIter const& unwrapIter(ConstIter const& iter) const {
  551. return iter.underlying_;
  552. }
  553. };
  554. //////// NodeContainer
  555. template <
  556. typename Key,
  557. typename Mapped,
  558. typename HasherOrVoid,
  559. typename KeyEqualOrVoid,
  560. typename AllocOrVoid>
  561. class NodeContainerPolicy;
  562. template <typename ValuePtr>
  563. class NodeContainerIterator : public BaseIter<ValuePtr, NonConstPtr<ValuePtr>> {
  564. using Super = BaseIter<ValuePtr, NonConstPtr<ValuePtr>>;
  565. using ItemIter = typename Super::ItemIter;
  566. using ValueConstPtr = typename Super::ValueConstPtr;
  567. public:
  568. using pointer = typename Super::pointer;
  569. using reference = typename Super::reference;
  570. using value_type = typename Super::value_type;
  571. NodeContainerIterator() = default;
  572. NodeContainerIterator(NodeContainerIterator const&) = default;
  573. NodeContainerIterator(NodeContainerIterator&&) = default;
  574. NodeContainerIterator& operator=(NodeContainerIterator const&) = default;
  575. NodeContainerIterator& operator=(NodeContainerIterator&&) = default;
  576. ~NodeContainerIterator() = default;
  577. /*implicit*/ operator NodeContainerIterator<ValueConstPtr>() const {
  578. return NodeContainerIterator<ValueConstPtr>{underlying_};
  579. }
  580. reference operator*() const {
  581. return *underlying_.item();
  582. }
  583. pointer operator->() const {
  584. return std::pointer_traits<pointer>::pointer_to(**this);
  585. }
  586. NodeContainerIterator& operator++() {
  587. underlying_.advance();
  588. return *this;
  589. }
  590. NodeContainerIterator operator++(int) {
  591. auto cur = *this;
  592. ++*this;
  593. return cur;
  594. }
  595. bool operator==(NodeContainerIterator<ValueConstPtr> const& rhs) const {
  596. return underlying_ == rhs.underlying_;
  597. }
  598. bool operator!=(NodeContainerIterator<ValueConstPtr> const& rhs) const {
  599. return !(*this == rhs);
  600. }
  601. private:
  602. ItemIter underlying_;
  603. explicit NodeContainerIterator(ItemIter const& underlying)
  604. : underlying_{underlying} {}
  605. template <typename K, typename M, typename H, typename E, typename A>
  606. friend class NodeContainerPolicy;
  607. template <typename P>
  608. friend class NodeContainerIterator;
  609. };
  610. template <
  611. typename Key,
  612. typename MappedTypeOrVoid,
  613. typename HasherOrVoid,
  614. typename KeyEqualOrVoid,
  615. typename AllocOrVoid>
  616. class NodeContainerPolicy
  617. : public BasePolicy<
  618. Key,
  619. MappedTypeOrVoid,
  620. HasherOrVoid,
  621. KeyEqualOrVoid,
  622. AllocOrVoid,
  623. typename std::allocator_traits<Defaulted<
  624. AllocOrVoid,
  625. DefaultAlloc<std::conditional_t<
  626. std::is_void<MappedTypeOrVoid>::value,
  627. Key,
  628. MapValueType<Key, MappedTypeOrVoid>>>>>::pointer> {
  629. public:
  630. using Super = BasePolicy<
  631. Key,
  632. MappedTypeOrVoid,
  633. HasherOrVoid,
  634. KeyEqualOrVoid,
  635. AllocOrVoid,
  636. typename std::allocator_traits<Defaulted<
  637. AllocOrVoid,
  638. DefaultAlloc<std::conditional_t<
  639. std::is_void<MappedTypeOrVoid>::value,
  640. Key,
  641. MapValueType<Key, MappedTypeOrVoid>>>>>::pointer>;
  642. using Alloc = typename Super::Alloc;
  643. using AllocTraits = typename Super::AllocTraits;
  644. using Item = typename Super::Item;
  645. using ItemIter = typename Super::ItemIter;
  646. using Value = typename Super::Value;
  647. private:
  648. using ByteAlloc = typename Super::ByteAlloc;
  649. using Super::kIsMap;
  650. public:
  651. using ConstIter = NodeContainerIterator<typename AllocTraits::const_pointer>;
  652. using Iter = std::conditional_t<
  653. kIsMap,
  654. NodeContainerIterator<typename AllocTraits::pointer>,
  655. ConstIter>;
  656. //////// F14Table policy
  657. static constexpr bool prefetchBeforeRehash() {
  658. return true;
  659. }
  660. static constexpr bool prefetchBeforeCopy() {
  661. return true;
  662. }
  663. static constexpr bool prefetchBeforeDestroy() {
  664. return !std::is_trivially_destructible<Value>::value;
  665. }
  666. static constexpr bool destroyItemOnClear() {
  667. return true;
  668. }
  669. // inherit constructors
  670. using Super::Super;
  671. void swapPolicy(NodeContainerPolicy& rhs) {
  672. this->swapBasePolicy(rhs);
  673. }
  674. using Super::keyForValue;
  675. std::size_t computeItemHash(Item const& item) const {
  676. return this->computeKeyHash(keyForValue(*item));
  677. }
  678. template <typename K>
  679. bool keyMatchesItem(K const& key, Item const& item) const {
  680. return this->keyEqual()(key, keyForValue(*item));
  681. }
  682. Value const& buildArgForItem(Item const& item) const& {
  683. return *item;
  684. }
  685. // buildArgForItem(Item&)&& is used when moving between unequal allocators
  686. decltype(auto) buildArgForItem(Item& item) && {
  687. return Super::moveValue(*item);
  688. }
  689. Value&& valueAtItemForExtract(Item& item) {
  690. return std::move(*item);
  691. }
  692. template <typename... Args>
  693. void
  694. constructValueAtItem(std::size_t /*size*/, Item* itemAddr, Args&&... args) {
  695. Alloc& a = this->alloc();
  696. // TODO(T31574848): clean up assume-s used to optimize placement new
  697. assume(itemAddr != nullptr);
  698. new (itemAddr) Item{AllocTraits::allocate(a, 1)};
  699. auto p = std::addressof(**itemAddr);
  700. // TODO(T31574848): clean up assume-s used to optimize placement new
  701. assume(p != nullptr);
  702. AllocTraits::construct(a, p, std::forward<Args>(args)...);
  703. }
  704. void moveItemDuringRehash(Item* itemAddr, Item& src) {
  705. // This is basically *itemAddr = src; src = nullptr, but allowing
  706. // for fancy pointers.
  707. // TODO(T31574848): clean up assume-s used to optimize placement new
  708. assume(itemAddr != nullptr);
  709. new (itemAddr) Item{std::move(src)};
  710. src = nullptr;
  711. src.~Item();
  712. }
  713. void prefetchValue(Item const& item) const {
  714. prefetchAddr(std::addressof(*item));
  715. }
  716. void destroyItem(Item& item) {
  717. if (item != nullptr) {
  718. Alloc& a = this->alloc();
  719. AllocTraits::destroy(a, std::addressof(*item));
  720. AllocTraits::deallocate(a, item, 1);
  721. }
  722. item.~Item();
  723. }
  724. template <typename V>
  725. void visitPolicyAllocationClasses(
  726. std::size_t chunkAllocSize,
  727. std::size_t size,
  728. std::size_t /*capacity*/,
  729. V&& visitor) const {
  730. if (chunkAllocSize > 0) {
  731. visitor(
  732. allocationBytesForOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  733. chunkAllocSize),
  734. 1);
  735. }
  736. if (size > 0) {
  737. visitor(sizeof(Value), size);
  738. }
  739. }
  740. //////// F14BasicMap/Set policy
  741. Iter makeIter(ItemIter const& underlying) const {
  742. return Iter{underlying};
  743. }
  744. ConstIter makeConstIter(ItemIter const& underlying) const {
  745. return Iter{underlying};
  746. }
  747. ItemIter const& unwrapIter(ConstIter const& iter) const {
  748. return iter.underlying_;
  749. }
  750. };
  751. //////// VectorContainer
  752. template <
  753. typename Key,
  754. typename MappedTypeOrVoid,
  755. typename HasherOrVoid,
  756. typename KeyEqualOrVoid,
  757. typename AllocOrVoid>
  758. class VectorContainerPolicy;
  759. template <typename ValuePtr>
  760. class VectorContainerIterator : public BaseIter<ValuePtr, uint32_t> {
  761. using Super = BaseIter<ValuePtr, uint32_t>;
  762. using ValueConstPtr = typename Super::ValueConstPtr;
  763. public:
  764. using pointer = typename Super::pointer;
  765. using reference = typename Super::reference;
  766. using value_type = typename Super::value_type;
  767. VectorContainerIterator() = default;
  768. VectorContainerIterator(VectorContainerIterator const&) = default;
  769. VectorContainerIterator(VectorContainerIterator&&) = default;
  770. VectorContainerIterator& operator=(VectorContainerIterator const&) = default;
  771. VectorContainerIterator& operator=(VectorContainerIterator&&) = default;
  772. ~VectorContainerIterator() = default;
  773. /*implicit*/ operator VectorContainerIterator<ValueConstPtr>() const {
  774. return VectorContainerIterator<ValueConstPtr>{current_, lowest_};
  775. }
  776. reference operator*() const {
  777. return *current_;
  778. }
  779. pointer operator->() const {
  780. return current_;
  781. }
  782. VectorContainerIterator& operator++() {
  783. if (UNLIKELY(current_ == lowest_)) {
  784. current_ = nullptr;
  785. } else {
  786. --current_;
  787. }
  788. return *this;
  789. }
  790. VectorContainerIterator operator++(int) {
  791. auto cur = *this;
  792. ++*this;
  793. return cur;
  794. }
  795. bool operator==(VectorContainerIterator<ValueConstPtr> const& rhs) const {
  796. return current_ == rhs.current_;
  797. }
  798. bool operator!=(VectorContainerIterator<ValueConstPtr> const& rhs) const {
  799. return !(*this == rhs);
  800. }
  801. private:
  802. ValuePtr current_;
  803. ValuePtr lowest_;
  804. explicit VectorContainerIterator(ValuePtr current, ValuePtr lowest)
  805. : current_(current), lowest_(lowest) {}
  806. std::size_t index() const {
  807. return current_ - lowest_;
  808. }
  809. template <typename K, typename M, typename H, typename E, typename A>
  810. friend class VectorContainerPolicy;
  811. template <typename P>
  812. friend class VectorContainerIterator;
  813. };
  814. struct VectorContainerIndexSearch {
  815. uint32_t index_;
  816. };
  817. template <
  818. typename Key,
  819. typename MappedTypeOrVoid,
  820. typename HasherOrVoid,
  821. typename KeyEqualOrVoid,
  822. typename AllocOrVoid>
  823. class VectorContainerPolicy : public BasePolicy<
  824. Key,
  825. MappedTypeOrVoid,
  826. HasherOrVoid,
  827. KeyEqualOrVoid,
  828. AllocOrVoid,
  829. uint32_t> {
  830. public:
  831. using Super = BasePolicy<
  832. Key,
  833. MappedTypeOrVoid,
  834. HasherOrVoid,
  835. KeyEqualOrVoid,
  836. AllocOrVoid,
  837. uint32_t>;
  838. using Alloc = typename Super::Alloc;
  839. using AllocTraits = typename Super::AllocTraits;
  840. using ByteAlloc = typename Super::ByteAlloc;
  841. using ByteAllocTraits = typename Super::ByteAllocTraits;
  842. using BytePtr = typename Super::BytePtr;
  843. using Hasher = typename Super::Hasher;
  844. using Item = typename Super::Item;
  845. using ItemIter = typename Super::ItemIter;
  846. using KeyEqual = typename Super::KeyEqual;
  847. using Value = typename Super::Value;
  848. using Super::kAllocIsAlwaysEqual;
  849. private:
  850. using Super::kIsMap;
  851. public:
  852. static constexpr bool kEnableItemIteration = false;
  853. using InternalSizeType = Item;
  854. using ConstIter =
  855. VectorContainerIterator<typename AllocTraits::const_pointer>;
  856. using Iter = std::conditional_t<
  857. kIsMap,
  858. VectorContainerIterator<typename AllocTraits::pointer>,
  859. ConstIter>;
  860. using ConstReverseIter = typename AllocTraits::const_pointer;
  861. using ReverseIter = std::
  862. conditional_t<kIsMap, typename AllocTraits::pointer, ConstReverseIter>;
  863. using ValuePtr = typename AllocTraits::pointer;
  864. //////// F14Table policy
  865. static constexpr bool prefetchBeforeRehash() {
  866. return true;
  867. }
  868. static constexpr bool prefetchBeforeCopy() {
  869. return false;
  870. }
  871. static constexpr bool prefetchBeforeDestroy() {
  872. return false;
  873. }
  874. static constexpr bool destroyItemOnClear() {
  875. return false;
  876. }
  877. private:
  878. static constexpr bool valueIsTriviallyCopyable() {
  879. return AllocatorHasDefaultObjectConstruct<Alloc, Value, Value>::value &&
  880. AllocatorHasDefaultObjectDestroy<Alloc, Value>::value &&
  881. is_trivially_copyable<Value>::value;
  882. }
  883. public:
  884. VectorContainerPolicy(
  885. Hasher const& hasher,
  886. KeyEqual const& keyEqual,
  887. Alloc const& alloc)
  888. : Super{hasher, keyEqual, alloc} {}
  889. VectorContainerPolicy(VectorContainerPolicy const& rhs) : Super{rhs} {
  890. // values_ will get allocated later to do the copy
  891. }
  892. VectorContainerPolicy(VectorContainerPolicy const& rhs, Alloc const& alloc)
  893. : Super{rhs, alloc} {
  894. // values_ will get allocated later to do the copy
  895. }
  896. VectorContainerPolicy(VectorContainerPolicy&& rhs) noexcept
  897. : Super{std::move(rhs)}, values_{rhs.values_} {
  898. rhs.values_ = nullptr;
  899. }
  900. VectorContainerPolicy(
  901. VectorContainerPolicy&& rhs,
  902. Alloc const& alloc) noexcept
  903. : Super{std::move(rhs), alloc} {
  904. if (kAllocIsAlwaysEqual || this->alloc() == rhs.alloc()) {
  905. // common case
  906. values_ = rhs.values_;
  907. rhs.values_ = nullptr;
  908. } else {
  909. // table must be constructed in new memory
  910. values_ = nullptr;
  911. }
  912. }
  913. VectorContainerPolicy& operator=(VectorContainerPolicy const& rhs) {
  914. if (this != &rhs) {
  915. FOLLY_SAFE_DCHECK(values_ == nullptr, "");
  916. Super::operator=(rhs);
  917. }
  918. return *this;
  919. }
  920. VectorContainerPolicy& operator=(VectorContainerPolicy&& rhs) noexcept {
  921. if (this != &rhs) {
  922. FOLLY_SAFE_DCHECK(values_ == nullptr, "");
  923. bool transfer =
  924. AllocTraits::propagate_on_container_move_assignment::value ||
  925. kAllocIsAlwaysEqual || this->alloc() == rhs.alloc();
  926. Super::operator=(std::move(rhs));
  927. if (transfer) {
  928. values_ = rhs.values_;
  929. rhs.values_ = nullptr;
  930. }
  931. }
  932. return *this;
  933. }
  934. void swapPolicy(VectorContainerPolicy& rhs) {
  935. using std::swap;
  936. this->swapBasePolicy(rhs);
  937. swap(values_, rhs.values_);
  938. }
  939. template <typename K>
  940. std::size_t computeKeyHash(K const& key) const {
  941. static_assert(
  942. Super::isAvalanchingHasher() == IsAvalanchingHasher<Hasher, K>::value,
  943. "");
  944. return this->hasher()(key);
  945. }
  946. std::size_t computeKeyHash(VectorContainerIndexSearch const& key) const {
  947. return computeItemHash(key.index_);
  948. }
  949. using Super::keyForValue;
  950. std::size_t computeItemHash(Item const& item) const {
  951. return this->computeKeyHash(keyForValue(values_[item]));
  952. }
  953. bool keyMatchesItem(VectorContainerIndexSearch const& key, Item const& item)
  954. const {
  955. return key.index_ == item;
  956. }
  957. template <typename K>
  958. bool keyMatchesItem(K const& key, Item const& item) const {
  959. return this->keyEqual()(key, keyForValue(values_[item]));
  960. }
  961. Key const& keyForValue(VectorContainerIndexSearch const& arg) const {
  962. return keyForValue(values_[arg.index_]);
  963. }
  964. VectorContainerIndexSearch buildArgForItem(Item const& item) const {
  965. return {item};
  966. }
  967. Value&& valueAtItemForExtract(Item& item) {
  968. return std::move(values_[item]);
  969. }
  970. void constructValueAtItem(
  971. std::size_t /*size*/,
  972. Item* itemAddr,
  973. VectorContainerIndexSearch arg) {
  974. *itemAddr = arg.index_;
  975. }
  976. template <typename... Args>
  977. void constructValueAtItem(std::size_t size, Item* itemAddr, Args&&... args) {
  978. Alloc& a = this->alloc();
  979. FOLLY_SAFE_DCHECK(size < std::numeric_limits<InternalSizeType>::max(), "");
  980. *itemAddr = static_cast<InternalSizeType>(size);
  981. auto dst = std::addressof(values_[size]);
  982. // TODO(T31574848): clean up assume-s used to optimize placement new
  983. assume(dst != nullptr);
  984. AllocTraits::construct(a, dst, std::forward<Args>(args)...);
  985. }
  986. void moveItemDuringRehash(Item* itemAddr, Item& src) {
  987. *itemAddr = src;
  988. }
  989. void prefetchValue(Item const& item) const {
  990. prefetchAddr(std::addressof(values_[item]));
  991. }
  992. void destroyItem(Item&) {}
  993. template <typename T>
  994. std::enable_if_t<std::is_nothrow_move_constructible<T>::value>
  995. complainUnlessNothrowMove() {}
  996. template <typename T>
  997. [[deprecated(
  998. "use F14NodeMap/Set or mark key and mapped type move constructor nothrow")]] std::
  999. enable_if_t<!std::is_nothrow_move_constructible<T>::value>
  1000. complainUnlessNothrowMove() {}
  1001. void transfer(Alloc& a, Value* src, Value* dst, std::size_t n) {
  1002. complainUnlessNothrowMove<Key>();
  1003. complainUnlessNothrowMove<lift_unit_t<MappedTypeOrVoid>>();
  1004. auto origSrc = src;
  1005. if (valueIsTriviallyCopyable()) {
  1006. std::memcpy(static_cast<void*>(dst), src, n * sizeof(Value));
  1007. } else {
  1008. for (std::size_t i = 0; i < n; ++i, ++src, ++dst) {
  1009. // TODO(T31574848): clean up assume-s used to optimize placement new
  1010. assume(dst != nullptr);
  1011. AllocTraits::construct(a, dst, Super::moveValue(*src));
  1012. if (kIsMap) {
  1013. AllocTraits::destroy(a, launder(src));
  1014. } else {
  1015. AllocTraits::destroy(a, src);
  1016. }
  1017. }
  1018. }
  1019. this->afterDestroyWithoutDeallocate(origSrc, n);
  1020. }
  1021. template <typename P, typename V>
  1022. bool beforeBuildImpl(std::size_t size, P&& rhs, V const& constructorArgFor) {
  1023. Alloc& a = this->alloc();
  1024. FOLLY_SAFE_DCHECK(values_ != nullptr, "");
  1025. auto src = std::addressof(rhs.values_[0]);
  1026. Value* dst = std::addressof(values_[0]);
  1027. if (valueIsTriviallyCopyable()) {
  1028. std::memcpy(dst, src, size * sizeof(Value));
  1029. } else {
  1030. for (std::size_t i = 0; i < size; ++i, ++src, ++dst) {
  1031. try {
  1032. // TODO(T31574848): clean up assume-s used to optimize placement new
  1033. assume(dst != nullptr);
  1034. AllocTraits::construct(a, dst, constructorArgFor(*src));
  1035. } catch (...) {
  1036. for (Value* cleanup = std::addressof(values_[0]); cleanup != dst;
  1037. ++cleanup) {
  1038. AllocTraits::destroy(a, cleanup);
  1039. }
  1040. throw;
  1041. }
  1042. }
  1043. }
  1044. return true;
  1045. }
  1046. bool beforeBuild(
  1047. std::size_t size,
  1048. std::size_t /*capacity*/,
  1049. VectorContainerPolicy const& rhs) {
  1050. return beforeBuildImpl(size, rhs, [](Value const& v) { return v; });
  1051. }
  1052. bool beforeBuild(
  1053. std::size_t size,
  1054. std::size_t /*capacity*/,
  1055. VectorContainerPolicy&& rhs) {
  1056. return beforeBuildImpl(
  1057. size, rhs, [](Value& v) { return Super::moveValue(v); });
  1058. }
  1059. template <typename P>
  1060. void afterBuild(
  1061. bool /*undoState*/,
  1062. bool success,
  1063. std::size_t /*size*/,
  1064. std::size_t /*capacity*/,
  1065. P&& /*rhs*/) {
  1066. // buildArgForItem can be used to construct a new item trivially,
  1067. // so no failure between beforeBuild and afterBuild should be possible
  1068. FOLLY_SAFE_DCHECK(success, "");
  1069. }
  1070. private:
  1071. // Returns the byte offset of the first Value in a unified allocation
  1072. // that first holds prefixBytes of data, where prefixBytes comes from
  1073. // Chunk storage and hence must be at least 8-byte aligned (sub-Chunk
  1074. // allocations always have an even capacity and sizeof(Item) == 4).
  1075. static std::size_t valuesOffset(std::size_t prefixBytes) {
  1076. FOLLY_SAFE_DCHECK((prefixBytes % 8) == 0, "");
  1077. if (alignof(Value) > 8) {
  1078. prefixBytes = -(-prefixBytes & ~(alignof(Value) - 1));
  1079. }
  1080. FOLLY_SAFE_DCHECK((prefixBytes % alignof(Value)) == 0, "");
  1081. return prefixBytes;
  1082. }
  1083. // Returns the total number of bytes that should be allocated to store
  1084. // prefixBytes of Chunks and valueCapacity values.
  1085. static std::size_t allocSize(
  1086. std::size_t prefixBytes,
  1087. std::size_t valueCapacity) {
  1088. return valuesOffset(prefixBytes) + sizeof(Value) * valueCapacity;
  1089. }
  1090. public:
  1091. ValuePtr beforeRehash(
  1092. std::size_t size,
  1093. std::size_t oldCapacity,
  1094. std::size_t newCapacity,
  1095. std::size_t chunkAllocSize,
  1096. BytePtr& outChunkAllocation) {
  1097. FOLLY_SAFE_DCHECK(
  1098. size <= oldCapacity && ((values_ == nullptr) == (oldCapacity == 0)) &&
  1099. newCapacity > 0 &&
  1100. newCapacity <= (std::numeric_limits<Item>::max)(),
  1101. "");
  1102. outChunkAllocation =
  1103. allocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  1104. ByteAlloc{Super::alloc()}, allocSize(chunkAllocSize, newCapacity));
  1105. ValuePtr before = values_;
  1106. ValuePtr after = std::pointer_traits<ValuePtr>::pointer_to(
  1107. *static_cast<Value*>(static_cast<void*>(
  1108. &*outChunkAllocation + valuesOffset(chunkAllocSize))));
  1109. if (size > 0) {
  1110. Alloc& a{this->alloc()};
  1111. transfer(a, std::addressof(before[0]), std::addressof(after[0]), size);
  1112. }
  1113. values_ = after;
  1114. return before;
  1115. }
  1116. FOLLY_NOINLINE void afterFailedRehash(ValuePtr state, std::size_t size) {
  1117. // state holds the old storage
  1118. Alloc& a = this->alloc();
  1119. if (size > 0) {
  1120. transfer(a, std::addressof(values_[0]), std::addressof(state[0]), size);
  1121. }
  1122. values_ = state;
  1123. }
  1124. void afterRehash(
  1125. ValuePtr state,
  1126. bool success,
  1127. std::size_t size,
  1128. std::size_t oldCapacity,
  1129. std::size_t newCapacity,
  1130. BytePtr chunkAllocation,
  1131. std::size_t chunkAllocSize) {
  1132. if (!success) {
  1133. afterFailedRehash(state, size);
  1134. }
  1135. // on success, chunkAllocation is the old allocation, on failure it is the
  1136. // new one
  1137. if (chunkAllocation != nullptr) {
  1138. deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  1139. ByteAlloc{Super::alloc()},
  1140. chunkAllocation,
  1141. allocSize(chunkAllocSize, (success ? oldCapacity : newCapacity)));
  1142. }
  1143. }
  1144. void beforeClear(std::size_t size, std::size_t capacity) {
  1145. FOLLY_SAFE_DCHECK(
  1146. size <= capacity && ((values_ == nullptr) == (capacity == 0)), "");
  1147. Alloc& a = this->alloc();
  1148. for (std::size_t i = 0; i < size; ++i) {
  1149. AllocTraits::destroy(a, std::addressof(values_[i]));
  1150. }
  1151. }
  1152. void beforeReset(std::size_t size, std::size_t capacity) {
  1153. beforeClear(size, capacity);
  1154. }
  1155. void afterReset(
  1156. std::size_t /*size*/,
  1157. std::size_t capacity,
  1158. BytePtr chunkAllocation,
  1159. std::size_t chunkAllocSize) {
  1160. if (chunkAllocation != nullptr) {
  1161. deallocateOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  1162. ByteAlloc{Super::alloc()},
  1163. chunkAllocation,
  1164. allocSize(chunkAllocSize, capacity));
  1165. values_ = nullptr;
  1166. }
  1167. }
  1168. template <typename V>
  1169. void visitPolicyAllocationClasses(
  1170. std::size_t chunkAllocSize,
  1171. std::size_t /*size*/,
  1172. std::size_t capacity,
  1173. V&& visitor) const {
  1174. FOLLY_SAFE_DCHECK((chunkAllocSize == 0) == (capacity == 0), "");
  1175. if (chunkAllocSize > 0) {
  1176. visitor(
  1177. allocationBytesForOverAligned<ByteAlloc, kRequiredVectorAlignment>(
  1178. allocSize(chunkAllocSize, capacity)),
  1179. 1);
  1180. }
  1181. }
  1182. // Iterator stuff
  1183. Iter linearBegin(std::size_t size) const {
  1184. return Iter{(size > 0 ? values_ + size - 1 : nullptr), values_};
  1185. }
  1186. Iter linearEnd() const {
  1187. return Iter{nullptr, nullptr};
  1188. }
  1189. //////// F14BasicMap/Set policy
  1190. Iter makeIter(ItemIter const& underlying) const {
  1191. if (underlying.atEnd()) {
  1192. return linearEnd();
  1193. } else {
  1194. assume(values_ + underlying.item() != nullptr);
  1195. assume(values_ != nullptr);
  1196. return Iter{values_ + underlying.item(), values_};
  1197. }
  1198. }
  1199. ConstIter makeConstIter(ItemIter const& underlying) const {
  1200. return makeIter(underlying);
  1201. }
  1202. Item iterToIndex(ConstIter const& iter) const {
  1203. auto n = iter.index();
  1204. assume(n <= std::numeric_limits<Item>::max());
  1205. return static_cast<Item>(n);
  1206. }
  1207. Iter indexToIter(Item index) const {
  1208. return Iter{values_ + index, values_};
  1209. }
  1210. Iter iter(ReverseIter it) {
  1211. return Iter{it, values_};
  1212. }
  1213. ConstIter iter(ConstReverseIter it) const {
  1214. return ConstIter{it, values_};
  1215. }
  1216. ReverseIter riter(Iter it) {
  1217. return it.current_;
  1218. }
  1219. ConstReverseIter riter(ConstIter it) const {
  1220. return it.current_;
  1221. }
  1222. ValuePtr values_{nullptr};
  1223. };
  1224. template <
  1225. template <typename, typename, typename, typename, typename> class Policy,
  1226. typename Key,
  1227. typename Mapped,
  1228. typename Hasher,
  1229. typename KeyEqual,
  1230. typename Alloc>
  1231. using MapPolicyWithDefaults = Policy<
  1232. Key,
  1233. Mapped,
  1234. VoidDefault<Hasher, DefaultHasher<Key>>,
  1235. VoidDefault<KeyEqual, DefaultKeyEqual<Key>>,
  1236. VoidDefault<Alloc, DefaultAlloc<std::pair<Key const, Mapped>>>>;
  1237. template <
  1238. template <typename, typename, typename, typename, typename> class Policy,
  1239. typename Key,
  1240. typename Hasher,
  1241. typename KeyEqual,
  1242. typename Alloc>
  1243. using SetPolicyWithDefaults = Policy<
  1244. Key,
  1245. void,
  1246. VoidDefault<Hasher, DefaultHasher<Key>>,
  1247. VoidDefault<KeyEqual, DefaultKeyEqual<Key>>,
  1248. VoidDefault<Alloc, DefaultAlloc<Key>>>;
  1249. } // namespace detail
  1250. } // namespace f14
  1251. } // namespace folly
  1252. #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE