react-native-windows 0.84.0 → 0.84.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (923) hide show
  1. package/Directory.Build.props +2 -17
  2. package/Folly/ThreadNameStub.cpp +4 -6
  3. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +1 -1
  4. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -7
  5. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -3
  6. package/PropertySheets/CIBuildOptimizations.props +2 -2
  7. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  8. package/PropertySheets/JSEngine.props +1 -1
  9. package/PropertySheets/NuGet.LockFile.props +10 -1
  10. package/PropertySheets/React.Cpp.props +3 -3
  11. package/PropertySheets/WinUI.props +2 -1
  12. package/ReactCommon/ReactCommon.vcxproj +0 -5
  13. package/Scripts/EnableInternalWinAppSDKFeed.ps1 +12 -5
  14. package/Scripts/NuGetRestoreForceEvaluateAllSolutions.ps1 +61 -6
  15. package/Scripts/Tfs/Layout-Desktop-Headers.ps1 +4 -37
  16. package/Scripts/UpdateNightlyDependencies.ps1 +47 -0
  17. package/Scripts/creaternwapp.cmd +5 -8
  18. package/Scripts/creaternwlib.cmd +10 -23
  19. package/Shared/Shared.vcxitems +2 -0
  20. package/{Folly → external}/.clang-format +0 -1
  21. package/external/External.vcxitems +10 -0
  22. package/external/fast-float/.syncignore +10 -0
  23. package/external/fast-float/LICENSE-APACHE +190 -0
  24. package/external/fast-float/LICENSE-BOOST +23 -0
  25. package/external/fast-float/LICENSE-MIT +27 -0
  26. package/external/fast-float/README.md +545 -0
  27. package/external/fast-float/cgmanifest.json +15 -0
  28. package/external/fast-float/fast-float.vcxitems +14 -0
  29. package/external/fast-float/include/fast_float/ascii_number.h +588 -0
  30. package/external/fast-float/include/fast_float/bigint.h +638 -0
  31. package/external/fast-float/include/fast_float/constexpr_feature_detect.h +46 -0
  32. package/external/fast-float/include/fast_float/decimal_to_binary.h +212 -0
  33. package/external/fast-float/include/fast_float/digit_comparison.h +457 -0
  34. package/external/fast-float/include/fast_float/fast_float.h +59 -0
  35. package/external/fast-float/include/fast_float/fast_table.h +708 -0
  36. package/external/fast-float/include/fast_float/float_common.h +1240 -0
  37. package/external/fast-float/include/fast_float/parse_number.h +399 -0
  38. package/external/fast-float/sync-config.json +8 -0
  39. package/external/fmt/.syncignore +10 -0
  40. package/external/fmt/CONTRIBUTING.md +20 -0
  41. package/external/fmt/LICENSE +27 -0
  42. package/external/fmt/README.md +484 -0
  43. package/external/fmt/doc/ChangeLog-old.md +3290 -0
  44. package/external/fmt/doc/api.md +650 -0
  45. package/external/fmt/doc/fmt.css +61 -0
  46. package/external/fmt/doc/fmt.js +4 -0
  47. package/external/fmt/doc/get-started.md +222 -0
  48. package/external/fmt/doc/index.md +151 -0
  49. package/external/fmt/doc/perf.svg +1 -0
  50. package/external/fmt/doc/python-license.txt +290 -0
  51. package/external/fmt/doc/syntax.md +887 -0
  52. package/external/fmt/fmt.vcxitems +28 -0
  53. package/external/fmt/include/fmt/args.h +228 -0
  54. package/external/fmt/include/fmt/base.h +3077 -0
  55. package/external/fmt/include/fmt/chrono.h +2432 -0
  56. package/external/fmt/include/fmt/color.h +612 -0
  57. package/external/fmt/include/fmt/compile.h +529 -0
  58. package/external/fmt/include/fmt/core.h +5 -0
  59. package/external/fmt/include/fmt/format-inl.h +1928 -0
  60. package/external/fmt/include/fmt/format.h +4427 -0
  61. package/external/fmt/include/fmt/os.h +439 -0
  62. package/external/fmt/include/fmt/ostream.h +211 -0
  63. package/external/fmt/include/fmt/printf.h +656 -0
  64. package/external/fmt/include/fmt/ranges.h +882 -0
  65. package/external/fmt/include/fmt/std.h +699 -0
  66. package/external/fmt/include/fmt/xchar.h +322 -0
  67. package/external/fmt/src/fmt.cc +135 -0
  68. package/external/fmt/src/format.cc +43 -0
  69. package/external/fmt/src/os.cc +403 -0
  70. package/external/fmt/sync-config.json +8 -0
  71. package/external/folly/.syncignore +60 -0
  72. package/external/folly/LICENSE +200 -0
  73. package/external/folly/README.md +263 -0
  74. package/{fmt → external/folly/folly}/.clang-format +0 -1
  75. package/external/folly/folly/AtomicHashArray-inl.h +546 -0
  76. package/external/folly/folly/AtomicHashArray.h +431 -0
  77. package/external/folly/folly/AtomicHashMap-inl.h +653 -0
  78. package/external/folly/folly/AtomicHashMap.h +484 -0
  79. package/external/folly/folly/AtomicIntrusiveLinkedList.h +206 -0
  80. package/external/folly/folly/AtomicLinkedList.h +110 -0
  81. package/external/folly/folly/AtomicUnorderedMap.h +522 -0
  82. package/external/folly/folly/BUCK +1631 -0
  83. package/external/folly/folly/BUILD_MODE.bzl +72 -0
  84. package/external/folly/folly/Benchmark.cpp +986 -0
  85. package/external/folly/folly/Benchmark.h +680 -0
  86. package/external/folly/folly/BenchmarkUtil.h +47 -0
  87. package/external/folly/folly/Bits.h +17 -0
  88. package/external/folly/folly/CMakeLists.txt +110 -0
  89. package/external/folly/folly/CPortability.h +338 -0
  90. package/external/folly/folly/CancellationToken-inl.h +449 -0
  91. package/external/folly/folly/CancellationToken.cpp +250 -0
  92. package/external/folly/folly/CancellationToken.h +365 -0
  93. package/external/folly/folly/Chrono.h +132 -0
  94. package/external/folly/folly/ClockGettimeWrappers.cpp +93 -0
  95. package/external/folly/folly/ClockGettimeWrappers.h +29 -0
  96. package/external/folly/folly/ConcurrentBitSet.h +157 -0
  97. package/external/folly/folly/ConcurrentLazy.h +74 -0
  98. package/external/folly/folly/ConcurrentSkipList-inl.h +341 -0
  99. package/external/folly/folly/ConcurrentSkipList.h +824 -0
  100. package/external/folly/folly/ConstructorCallbackList.h +158 -0
  101. package/external/folly/folly/Conv.h +2026 -0
  102. package/external/folly/folly/CppAttributes.h +170 -0
  103. package/external/folly/folly/CpuId.h +297 -0
  104. package/external/folly/folly/DefaultKeepAliveExecutor.h +172 -0
  105. package/external/folly/folly/Demangle.cpp +255 -0
  106. package/external/folly/folly/Demangle.h +73 -0
  107. package/external/folly/folly/DiscriminatedPtr.h +236 -0
  108. package/external/folly/folly/DynamicConverter.h +17 -0
  109. package/external/folly/folly/Exception.h +150 -0
  110. package/external/folly/folly/ExceptionString.cpp +51 -0
  111. package/external/folly/folly/ExceptionString.h +33 -0
  112. package/external/folly/folly/ExceptionWrapper-inl.h +264 -0
  113. package/external/folly/folly/ExceptionWrapper.cpp +37 -0
  114. package/external/folly/folly/ExceptionWrapper.h +377 -0
  115. package/external/folly/folly/Executor.cpp +111 -0
  116. package/external/folly/folly/Executor.h +351 -0
  117. package/external/folly/folly/Expected.h +1725 -0
  118. package/external/folly/folly/FBString.h +2888 -0
  119. package/external/folly/folly/FBVector.h +17 -0
  120. package/external/folly/folly/File.cpp +180 -0
  121. package/external/folly/folly/File.h +177 -0
  122. package/external/folly/folly/FileUtil.cpp +378 -0
  123. package/external/folly/folly/FileUtil.h +332 -0
  124. package/external/folly/folly/Fingerprint.cpp +135 -0
  125. package/external/folly/folly/Fingerprint.h +289 -0
  126. package/external/folly/folly/FixedString.h +2965 -0
  127. package/external/folly/folly/FollyMemcpy.cpp +30 -0
  128. package/external/folly/folly/FollyMemcpy.h +23 -0
  129. package/external/folly/folly/FollyMemset.cpp +29 -0
  130. package/external/folly/folly/FollyMemset.h +25 -0
  131. package/external/folly/folly/Format-inl.h +1152 -0
  132. package/external/folly/folly/Format.cpp +429 -0
  133. package/external/folly/folly/Format.h +463 -0
  134. package/external/folly/folly/FormatArg.h +285 -0
  135. package/external/folly/folly/FormatTraits.h +65 -0
  136. package/external/folly/folly/Function.h +1159 -0
  137. package/external/folly/folly/GLog.h +85 -0
  138. package/external/folly/folly/GroupVarint.cpp +153 -0
  139. package/external/folly/folly/GroupVarint.h +630 -0
  140. package/external/folly/folly/Hash.h +20 -0
  141. package/external/folly/folly/IPAddress.cpp +490 -0
  142. package/external/folly/folly/IPAddress.h +667 -0
  143. package/external/folly/folly/IPAddressException.h +82 -0
  144. package/external/folly/folly/IPAddressV4.cpp +305 -0
  145. package/external/folly/folly/IPAddressV4.h +495 -0
  146. package/external/folly/folly/IPAddressV6.cpp +541 -0
  147. package/external/folly/folly/IPAddressV6.h +627 -0
  148. package/external/folly/folly/Indestructible.h +164 -0
  149. package/external/folly/folly/IndexedMemPool.h +550 -0
  150. package/external/folly/folly/IntrusiveList.h +17 -0
  151. package/external/folly/folly/Lazy.h +142 -0
  152. package/external/folly/folly/Likely.h +76 -0
  153. package/external/folly/folly/MPMCPipeline.h +280 -0
  154. package/external/folly/folly/MPMCQueue.h +1556 -0
  155. package/external/folly/folly/MacAddress.cpp +188 -0
  156. package/external/folly/folly/MacAddress.h +260 -0
  157. package/external/folly/folly/MapUtil.h +17 -0
  158. package/external/folly/folly/Math.h +258 -0
  159. package/external/folly/folly/MaybeManagedPtr.h +120 -0
  160. package/external/folly/folly/Memory.h +900 -0
  161. package/external/folly/folly/MicroLock.cpp +76 -0
  162. package/external/folly/folly/MicroLock.h +354 -0
  163. package/external/folly/folly/MicroSpinLock.h +17 -0
  164. package/external/folly/folly/MoveWrapper.h +76 -0
  165. package/external/folly/folly/ObserverContainer.h +1026 -0
  166. package/external/folly/folly/Optional.h +743 -0
  167. package/external/folly/folly/Overload.h +325 -0
  168. package/external/folly/folly/PackedSyncPtr.h +147 -0
  169. package/external/folly/folly/Padded.h +464 -0
  170. package/external/folly/folly/Poly-inl.h +230 -0
  171. package/external/folly/folly/Poly.h +1095 -0
  172. package/external/folly/folly/PolyException.h +43 -0
  173. package/external/folly/folly/Portability.h +644 -0
  174. package/external/folly/folly/Preprocessor.h +236 -0
  175. package/external/folly/folly/ProducerConsumerQueue.h +182 -0
  176. package/external/folly/folly/RWSpinLock.h +17 -0
  177. package/external/folly/folly/Random-inl.h +86 -0
  178. package/external/folly/folly/Random.cpp +184 -0
  179. package/external/folly/folly/Random.h +434 -0
  180. package/external/folly/folly/Range.h +1772 -0
  181. package/external/folly/folly/Replaceable.h +636 -0
  182. package/external/folly/folly/ScopeGuard.cpp +29 -0
  183. package/external/folly/folly/ScopeGuard.h +420 -0
  184. package/external/folly/folly/SharedMutex.cpp +81 -0
  185. package/external/folly/folly/SharedMutex.h +1751 -0
  186. package/external/folly/folly/Singleton-inl.h +332 -0
  187. package/external/folly/folly/Singleton.cpp +512 -0
  188. package/external/folly/folly/Singleton.h +891 -0
  189. package/external/folly/folly/SingletonThreadLocal.cpp +53 -0
  190. package/external/folly/folly/SingletonThreadLocal.h +263 -0
  191. package/external/folly/folly/SocketAddress.cpp +786 -0
  192. package/external/folly/folly/SocketAddress.h +768 -0
  193. package/external/folly/folly/SpinLock.h +55 -0
  194. package/external/folly/folly/String-inl.h +668 -0
  195. package/external/folly/folly/String.cpp +777 -0
  196. package/external/folly/folly/String.h +767 -0
  197. package/external/folly/folly/Subprocess.cpp +1142 -0
  198. package/external/folly/folly/Subprocess.h +1055 -0
  199. package/external/folly/folly/Synchronized.h +1833 -0
  200. package/external/folly/folly/SynchronizedPtr.h +106 -0
  201. package/external/folly/folly/ThreadCachedInt.h +175 -0
  202. package/external/folly/folly/ThreadLocal.h +478 -0
  203. package/external/folly/folly/TimeoutQueue.cpp +78 -0
  204. package/external/folly/folly/TimeoutQueue.h +123 -0
  205. package/external/folly/folly/TokenBucket.h +673 -0
  206. package/external/folly/folly/Traits.h +1442 -0
  207. package/external/folly/folly/Try-inl.h +372 -0
  208. package/external/folly/folly/Try.cpp +23 -0
  209. package/external/folly/folly/Try.h +728 -0
  210. package/external/folly/folly/UTF8String.h +56 -0
  211. package/external/folly/folly/Unicode.cpp +201 -0
  212. package/external/folly/folly/Unicode.h +94 -0
  213. package/external/folly/folly/Unit.h +65 -0
  214. package/external/folly/folly/Uri-inl.h +101 -0
  215. package/external/folly/folly/Uri.cpp +190 -0
  216. package/external/folly/folly/Uri.h +142 -0
  217. package/external/folly/folly/Utility.h +932 -0
  218. package/external/folly/folly/VERSION +1 -0
  219. package/external/folly/folly/Varint.h +230 -0
  220. package/external/folly/folly/VirtualExecutor.h +17 -0
  221. package/external/folly/folly/algorithm/simd/BUCK +47 -0
  222. package/external/folly/folly/algorithm/simd/Contains.cpp +42 -0
  223. package/external/folly/folly/algorithm/simd/Contains.h +116 -0
  224. package/external/folly/folly/algorithm/simd/FindFixed.h +301 -0
  225. package/external/folly/folly/algorithm/simd/Ignore.h +52 -0
  226. package/external/folly/folly/algorithm/simd/Movemask.h +207 -0
  227. package/external/folly/folly/algorithm/simd/detail/BUCK +70 -0
  228. package/external/folly/folly/algorithm/simd/detail/ContainsImpl.h +91 -0
  229. package/external/folly/folly/algorithm/simd/detail/SimdAnyOf.h +83 -0
  230. package/external/folly/folly/algorithm/simd/detail/SimdForEach.h +209 -0
  231. package/external/folly/folly/algorithm/simd/detail/SimdPlatform.h +445 -0
  232. package/external/folly/folly/algorithm/simd/detail/Traits.h +125 -0
  233. package/external/folly/folly/algorithm/simd/detail/UnrollUtils.h +126 -0
  234. package/external/folly/folly/base64.h +264 -0
  235. package/external/folly/folly/chrono/BUCK +29 -0
  236. package/external/folly/folly/chrono/Clock.h +65 -0
  237. package/external/folly/folly/chrono/Conv.h +712 -0
  238. package/external/folly/folly/chrono/test/BUCK +26 -0
  239. package/external/folly/folly/chrono/test/ClockTest.cpp +68 -0
  240. package/external/folly/folly/chrono/test/ConvTest.cpp +652 -0
  241. package/external/folly/folly/concurrency/AtomicSharedPtr.h +387 -0
  242. package/external/folly/folly/concurrency/BUCK +170 -0
  243. package/external/folly/folly/concurrency/CacheLocality.h +460 -0
  244. package/external/folly/folly/concurrency/ConcurrentHashMap.h +822 -0
  245. package/external/folly/folly/concurrency/CoreCachedSharedPtr.h +232 -0
  246. package/external/folly/folly/concurrency/DeadlockDetector.cpp +27 -0
  247. package/external/folly/folly/concurrency/DeadlockDetector.h +44 -0
  248. package/external/folly/folly/concurrency/DynamicBoundedQueue.h +751 -0
  249. package/external/folly/folly/concurrency/PriorityUnboundedQueueSet.h +207 -0
  250. package/external/folly/folly/concurrency/ProcessLocalUniqueId.cpp +46 -0
  251. package/external/folly/folly/concurrency/ProcessLocalUniqueId.h +38 -0
  252. package/external/folly/folly/concurrency/SingletonRelaxedCounter.h +325 -0
  253. package/external/folly/folly/concurrency/ThreadCachedSynchronized.h +227 -0
  254. package/external/folly/folly/concurrency/UnboundedQueue.h +891 -0
  255. package/external/folly/folly/concurrency/container/BUCK +77 -0
  256. package/external/folly/folly/concurrency/container/FlatCombiningPriorityQueue.h +426 -0
  257. package/external/folly/folly/concurrency/container/LockFreeRingBuffer.h +306 -0
  258. package/external/folly/folly/concurrency/container/RelaxedConcurrentPriorityQueue.h +1212 -0
  259. package/external/folly/folly/concurrency/container/SingleWriterFixedHashMap.h +322 -0
  260. package/external/folly/folly/concurrency/container/atomic_grow_array.h +564 -0
  261. package/external/folly/folly/concurrency/container/test/BUCK +75 -0
  262. package/external/folly/folly/concurrency/container/test/FlatCombiningPriorityQueueTest.cpp +570 -0
  263. package/external/folly/folly/concurrency/container/test/LockFreeRingBufferTest.cpp +276 -0
  264. package/external/folly/folly/concurrency/container/test/RelaxedConcurrentPriorityQueueTest.cpp +1570 -0
  265. package/external/folly/folly/concurrency/container/test/SingleWriterFixedHashMapTest.cpp +401 -0
  266. package/external/folly/folly/concurrency/container/test/atomic_grow_array_test.cpp +187 -0
  267. package/external/folly/folly/concurrency/detail/AtomicSharedPtr-detail.h +212 -0
  268. package/external/folly/folly/concurrency/detail/ConcurrentHashMap-detail.h +1911 -0
  269. package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.cpp +43 -0
  270. package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.h +190 -0
  271. package/external/folly/folly/concurrency/memory/BUCK +53 -0
  272. package/external/folly/folly/concurrency/memory/PrimaryPtr.h +338 -0
  273. package/external/folly/folly/concurrency/memory/ReadMostlySharedPtr.h +511 -0
  274. package/external/folly/folly/concurrency/memory/TLRefCount.h +228 -0
  275. package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrBenchmark.cpp +56 -0
  276. package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrTest.cpp +454 -0
  277. package/external/folly/folly/concurrency/memory/test/BUCK +95 -0
  278. package/external/folly/folly/concurrency/memory/test/PrimaryPtrTest.cpp +303 -0
  279. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrBenchmark.cpp +138 -0
  280. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrStressTest.cpp +75 -0
  281. package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrTest.cpp +378 -0
  282. package/external/folly/folly/concurrency/memory/test/RefCountBenchmark.cpp +90 -0
  283. package/external/folly/folly/concurrency/memory/test/RefCountTest.cpp +168 -0
  284. package/external/folly/folly/concurrency/test/AtomicSharedPtrCounted.h +156 -0
  285. package/external/folly/folly/concurrency/test/AtomicSharedPtrPerformance.cpp +255 -0
  286. package/external/folly/folly/concurrency/test/AtomicSharedPtrTest.cpp +257 -0
  287. package/external/folly/folly/concurrency/test/BUCK +229 -0
  288. package/external/folly/folly/concurrency/test/CacheLocalityBenchmark.cpp +392 -0
  289. package/external/folly/folly/concurrency/test/CacheLocalityTest.cpp +1229 -0
  290. package/external/folly/folly/concurrency/test/ConcurrentHashMapBench.cpp +260 -0
  291. package/external/folly/folly/concurrency/test/ConcurrentHashMapTest.cpp +1242 -0
  292. package/external/folly/folly/concurrency/test/CoreCachedSharedPtrTest.cpp +408 -0
  293. package/external/folly/folly/concurrency/test/DynamicBoundedQueueTest.cpp +984 -0
  294. package/external/folly/folly/concurrency/test/PriorityUnboundedQueueSetTest.cpp +73 -0
  295. package/external/folly/folly/concurrency/test/ProcessLocalUniqueIdTest.cpp +66 -0
  296. package/external/folly/folly/concurrency/test/SingletonRelaxedCounterBench.cpp +101 -0
  297. package/external/folly/folly/concurrency/test/SingletonRelaxedCounterTest.cpp +185 -0
  298. package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedBench.cpp +76 -0
  299. package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedTest.cpp +93 -0
  300. package/external/folly/folly/concurrency/test/UnboundedQueueTest.cpp +1302 -0
  301. package/external/folly/folly/container/Access.h +57 -0
  302. package/external/folly/folly/container/Array.h +87 -0
  303. package/external/folly/folly/container/BUCK +353 -0
  304. package/external/folly/folly/container/BitIterator.h +203 -0
  305. package/external/folly/folly/container/Enumerate.h +162 -0
  306. package/external/folly/folly/container/EvictingCacheMap.h +730 -0
  307. package/external/folly/folly/container/F14.md +300 -0
  308. package/external/folly/folly/container/F14Map-fwd.h +113 -0
  309. package/external/folly/folly/container/F14Map.h +2108 -0
  310. package/external/folly/folly/container/F14Set-fwd.h +95 -0
  311. package/external/folly/folly/container/F14Set.h +1603 -0
  312. package/external/folly/folly/container/FBVector.h +1711 -0
  313. package/external/folly/folly/container/Foreach-inl.h +316 -0
  314. package/external/folly/folly/container/Foreach.h +209 -0
  315. package/external/folly/folly/container/HeterogeneousAccess-fwd.h +33 -0
  316. package/external/folly/folly/container/HeterogeneousAccess.h +171 -0
  317. package/external/folly/folly/container/IntrusiveHeap.h +268 -0
  318. package/external/folly/folly/container/IntrusiveList.h +131 -0
  319. package/external/folly/folly/container/Iterator.h +843 -0
  320. package/external/folly/folly/container/MapUtil.h +376 -0
  321. package/external/folly/folly/container/Merge.h +90 -0
  322. package/external/folly/folly/container/RegexMatchCache.cpp +521 -0
  323. package/external/folly/folly/container/RegexMatchCache.h +699 -0
  324. package/external/folly/folly/container/Reserve.h +109 -0
  325. package/external/folly/folly/container/SparseByteSet.h +123 -0
  326. package/external/folly/folly/container/View.h +81 -0
  327. package/external/folly/folly/container/WeightedEvictingCacheMap.h +651 -0
  328. package/external/folly/folly/container/detail/BUCK +115 -0
  329. package/external/folly/folly/container/detail/BitIteratorDetail.h +87 -0
  330. package/external/folly/folly/container/detail/F14Defaults.h +34 -0
  331. package/external/folly/folly/container/detail/F14IntrinsicsAvailability.h +67 -0
  332. package/external/folly/folly/container/detail/F14MapFallback.h +717 -0
  333. package/external/folly/folly/container/detail/F14Mask.h +235 -0
  334. package/external/folly/folly/container/detail/F14Policy.h +1523 -0
  335. package/external/folly/folly/container/detail/F14SetFallback.h +528 -0
  336. package/external/folly/folly/container/detail/F14Table.cpp +71 -0
  337. package/external/folly/folly/container/detail/F14Table.h +2680 -0
  338. package/external/folly/folly/container/detail/Util.h +303 -0
  339. package/external/folly/folly/container/detail/tape_detail.h +135 -0
  340. package/external/folly/folly/container/detail/test/BUCK +14 -0
  341. package/external/folly/folly/container/detail/test/F14DetailTest.cpp +47 -0
  342. package/external/folly/folly/container/heap_vector_types.h +1683 -0
  343. package/external/folly/folly/container/range_traits.h +81 -0
  344. package/external/folly/folly/container/small_vector.h +1476 -0
  345. package/external/folly/folly/container/sorted_vector_types.h +1652 -0
  346. package/external/folly/folly/container/span.h +408 -0
  347. package/external/folly/folly/container/tape.h +608 -0
  348. package/external/folly/folly/container/test/.clang-tidy +12 -0
  349. package/external/folly/folly/container/test/AccessTest.cpp +138 -0
  350. package/external/folly/folly/container/test/ArrayTest.cpp +84 -0
  351. package/external/folly/folly/container/test/BUCK +568 -0
  352. package/external/folly/folly/container/test/BitIteratorBench.cpp +112 -0
  353. package/external/folly/folly/container/test/BitIteratorTest.cpp +109 -0
  354. package/external/folly/folly/container/test/EnumerateTest.cpp +294 -0
  355. package/external/folly/folly/container/test/EvictingCacheMapBench.cpp +80 -0
  356. package/external/folly/folly/container/test/EvictingCacheMapTest.cpp +842 -0
  357. package/external/folly/folly/container/test/F14AsanSupportTest.cpp +143 -0
  358. package/external/folly/folly/container/test/F14FwdTest.cpp +37 -0
  359. package/external/folly/folly/container/test/F14InterprocessTest.cpp +404 -0
  360. package/external/folly/folly/container/test/F14MapTest.cpp +2543 -0
  361. package/external/folly/folly/container/test/F14PolicyTest.cpp +49 -0
  362. package/external/folly/folly/container/test/F14SetTest.cpp +1738 -0
  363. package/external/folly/folly/container/test/F14SmallOverheads.cpp +215 -0
  364. package/external/folly/folly/container/test/F14TestUtil.h +117 -0
  365. package/external/folly/folly/container/test/FBVectorBenchmark.cpp +380 -0
  366. package/external/folly/folly/container/test/FBVectorBenchmarks.cpp.h +100 -0
  367. package/external/folly/folly/container/test/FBVectorTest.cpp +326 -0
  368. package/external/folly/folly/container/test/FBVectorTests.cpp.h +304 -0
  369. package/external/folly/folly/container/test/ForeachBenchmark.cpp +388 -0
  370. package/external/folly/folly/container/test/ForeachTest.cpp +338 -0
  371. package/external/folly/folly/container/test/HashMapsBench.cpp +458 -0
  372. package/external/folly/folly/container/test/HeterogeneousAccessTest.cpp +242 -0
  373. package/external/folly/folly/container/test/IntrusiveHeapTest.cpp +262 -0
  374. package/external/folly/folly/container/test/IteratorTest.cpp +989 -0
  375. package/external/folly/folly/container/test/MapUtilTest.cpp +365 -0
  376. package/external/folly/folly/container/test/MergeTest.cpp +66 -0
  377. package/external/folly/folly/container/test/RegexMatchCacheTest.cpp +634 -0
  378. package/external/folly/folly/container/test/ReserveTest.cpp +173 -0
  379. package/external/folly/folly/container/test/SparseByteSetBenchmark.cpp +153 -0
  380. package/external/folly/folly/container/test/SparseByteSetTest.cpp +117 -0
  381. package/external/folly/folly/container/test/TrackingTypes.h +584 -0
  382. package/external/folly/folly/container/test/UtilTest.cpp +609 -0
  383. package/external/folly/folly/container/test/WeightedEvictingCacheMapTest.cpp +800 -0
  384. package/external/folly/folly/container/test/heap_vector_types_test.cpp +1774 -0
  385. package/external/folly/folly/container/test/range_traits_test.cpp +59 -0
  386. package/external/folly/folly/container/test/small_vector_test.cpp +1571 -0
  387. package/external/folly/folly/container/test/sorted_vector_test.cpp +1589 -0
  388. package/external/folly/folly/container/test/span_test.cpp +520 -0
  389. package/external/folly/folly/container/test/tape_bench.cpp +200 -0
  390. package/external/folly/folly/container/test/tape_test.cpp +590 -0
  391. package/external/folly/folly/defs.bzl +238 -0
  392. package/external/folly/folly/detail/AsyncTrace.cpp +36 -0
  393. package/external/folly/folly/detail/AsyncTrace.h +44 -0
  394. package/external/folly/folly/detail/AtomicHashUtils.h +42 -0
  395. package/external/folly/folly/detail/AtomicUnorderedMapUtils.h +80 -0
  396. package/external/folly/folly/detail/BUCK +406 -0
  397. package/external/folly/folly/detail/DiscriminatedPtrDetail.h +172 -0
  398. package/external/folly/folly/detail/FileUtilDetail.cpp +63 -0
  399. package/external/folly/folly/detail/FileUtilDetail.h +85 -0
  400. package/external/folly/folly/detail/FileUtilVectorDetail.h +81 -0
  401. package/external/folly/folly/detail/FingerprintPolynomial.h +132 -0
  402. package/external/folly/folly/detail/Futex-inl.h +123 -0
  403. package/external/folly/folly/detail/Futex.cpp +273 -0
  404. package/external/folly/folly/detail/Futex.h +109 -0
  405. package/external/folly/folly/detail/GroupVarintDetail.h +101 -0
  406. package/external/folly/folly/detail/IPAddress.cpp +37 -0
  407. package/external/folly/folly/detail/IPAddress.h +57 -0
  408. package/external/folly/folly/detail/IPAddressSource.h +278 -0
  409. package/external/folly/folly/detail/Iterators.h +156 -0
  410. package/external/folly/folly/detail/MPMCPipelineDetail.h +122 -0
  411. package/external/folly/folly/detail/MemoryIdler.cpp +233 -0
  412. package/external/folly/folly/detail/MemoryIdler.h +216 -0
  413. package/external/folly/folly/detail/PerfScoped.cpp +112 -0
  414. package/external/folly/folly/detail/PerfScoped.h +70 -0
  415. package/external/folly/folly/detail/PolyDetail.h +921 -0
  416. package/external/folly/folly/detail/RangeCommon.cpp +55 -0
  417. package/external/folly/folly/detail/RangeCommon.h +93 -0
  418. package/external/folly/folly/detail/RangeSse42.cpp +198 -0
  419. package/external/folly/folly/detail/RangeSse42.h +30 -0
  420. package/external/folly/folly/detail/SimpleSimdStringUtils.cpp +31 -0
  421. package/external/folly/folly/detail/SimpleSimdStringUtils.h +27 -0
  422. package/external/folly/folly/detail/SimpleSimdStringUtilsImpl.h +63 -0
  423. package/external/folly/folly/detail/Singleton.h +34 -0
  424. package/external/folly/folly/detail/SlowFingerprint.h +90 -0
  425. package/external/folly/folly/detail/SocketFastOpen.cpp +175 -0
  426. package/external/folly/folly/detail/SocketFastOpen.h +89 -0
  427. package/external/folly/folly/detail/SplitStringSimd.cpp +84 -0
  428. package/external/folly/folly/detail/SplitStringSimd.h +151 -0
  429. package/external/folly/folly/detail/SplitStringSimdImpl.h +149 -0
  430. package/external/folly/folly/detail/Sse.cpp +35 -0
  431. package/external/folly/folly/detail/Sse.h +45 -0
  432. package/external/folly/folly/detail/StaticSingletonManager.cpp +119 -0
  433. package/external/folly/folly/detail/StaticSingletonManager.h +298 -0
  434. package/external/folly/folly/detail/ThreadLocalDetail.cpp +492 -0
  435. package/external/folly/folly/detail/ThreadLocalDetail.h +800 -0
  436. package/external/folly/folly/detail/TrapOnAvx512.cpp +41 -0
  437. package/external/folly/folly/detail/TrapOnAvx512.h +21 -0
  438. package/external/folly/folly/detail/TurnSequencer.h +295 -0
  439. package/external/folly/folly/detail/TypeList.h +551 -0
  440. package/external/folly/folly/detail/UniqueInstance.cpp +136 -0
  441. package/external/folly/folly/detail/UniqueInstance.h +68 -0
  442. package/external/folly/folly/detail/base64_detail/BUCK +102 -0
  443. package/external/folly/folly/detail/base64_detail/Base64Api.cpp +40 -0
  444. package/external/folly/folly/detail/base64_detail/Base64Api.h +101 -0
  445. package/external/folly/folly/detail/base64_detail/Base64Common.h +80 -0
  446. package/external/folly/folly/detail/base64_detail/Base64Constants.h +79 -0
  447. package/external/folly/folly/detail/base64_detail/Base64HiddenConstants.h +129 -0
  448. package/external/folly/folly/detail/base64_detail/Base64SWAR.cpp +161 -0
  449. package/external/folly/folly/detail/base64_detail/Base64SWAR.h +32 -0
  450. package/external/folly/folly/detail/base64_detail/Base64Scalar.h +262 -0
  451. package/external/folly/folly/detail/base64_detail/Base64Simd.h +102 -0
  452. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.cpp +42 -0
  453. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.h +33 -0
  454. package/external/folly/folly/detail/base64_detail/Base64_SSE4_2_Platform.h +167 -0
  455. package/external/folly/folly/detail/base64_detail/README.md +392 -0
  456. package/external/folly/folly/detail/base64_detail/tests/BUCK +36 -0
  457. package/external/folly/folly/detail/base64_detail/tests/Base64AgainstScalarTest.cpp +141 -0
  458. package/external/folly/folly/detail/base64_detail/tests/Base64PlatformTest.cpp +273 -0
  459. package/external/folly/folly/detail/base64_detail/tests/Base64SpecialCasesTest.cpp +555 -0
  460. package/external/folly/folly/detail/test/AsyncTraceTest.cpp +43 -0
  461. package/external/folly/folly/detail/test/BUCK +118 -0
  462. package/external/folly/folly/detail/test/FileUtilDetailTest.cpp +56 -0
  463. package/external/folly/folly/detail/test/PerfScopedTest.cpp +107 -0
  464. package/external/folly/folly/detail/test/SimpleSimdStringUtilsTest.cpp +92 -0
  465. package/external/folly/folly/detail/test/SplitStringSimdTest.cpp +242 -0
  466. package/external/folly/folly/detail/test/StaticSingletonManagerTest.cpp +121 -0
  467. package/external/folly/folly/detail/test/ThreadLocalBenchmark.cpp +116 -0
  468. package/external/folly/folly/detail/test/ThreadLocalDetailTest.cpp +194 -0
  469. package/external/folly/folly/detail/test/TrapOnAvx512TestNegative.cpp +29 -0
  470. package/external/folly/folly/detail/test/UniqueInstanceTest.cpp +60 -0
  471. package/external/folly/folly/detail/thread_local_globals.cpp +69 -0
  472. package/external/folly/folly/detail/thread_local_globals.h +36 -0
  473. package/external/folly/folly/docs/AtomicHashMap.md +134 -0
  474. package/external/folly/folly/docs/Benchmark.md +310 -0
  475. package/external/folly/folly/docs/Conv.md +291 -0
  476. package/external/folly/folly/docs/Dynamic.md +220 -0
  477. package/external/folly/folly/docs/DynamicConverter.md +71 -0
  478. package/external/folly/folly/docs/Executors.md +63 -0
  479. package/external/folly/folly/docs/FBString.md +46 -0
  480. package/external/folly/folly/docs/FBVector.md +200 -0
  481. package/external/folly/folly/docs/Fbvector--graphical_solutions.png +0 -0
  482. package/external/folly/folly/docs/Format.md +177 -0
  483. package/external/folly/folly/docs/Function.md +92 -0
  484. package/external/folly/folly/docs/Futures.md +263 -0
  485. package/external/folly/folly/docs/GroupVarint.md +46 -0
  486. package/external/folly/folly/docs/Histogram.md +104 -0
  487. package/external/folly/folly/docs/MapUtils.md +80 -0
  488. package/external/folly/folly/docs/Overview.md +263 -0
  489. package/external/folly/folly/docs/PackedSyncPtr.md +77 -0
  490. package/external/folly/folly/docs/Poly.md +500 -0
  491. package/external/folly/folly/docs/ProducerConsumerQueue.md +82 -0
  492. package/external/folly/folly/docs/Rcu.md +218 -0
  493. package/external/folly/folly/docs/SmallLocks.md +24 -0
  494. package/external/folly/folly/docs/Synchronized.md +793 -0
  495. package/external/folly/folly/docs/ThreadCachedInt.md +98 -0
  496. package/external/folly/folly/docs/ThreadLocal.md +105 -0
  497. package/external/folly/folly/docs/Traits.md +161 -0
  498. package/external/folly/folly/docs/small_vector.md +64 -0
  499. package/external/folly/folly/docs/style.css +23 -0
  500. package/external/folly/folly/dynamic-inl.h +17 -0
  501. package/external/folly/folly/dynamic.h +17 -0
  502. package/external/folly/folly/folly_extended_library.bzl +28 -0
  503. package/external/folly/folly/functional/ApplyTuple.h +204 -0
  504. package/external/folly/folly/functional/BUCK +57 -0
  505. package/external/folly/folly/functional/Invoke.h +880 -0
  506. package/external/folly/folly/functional/Partial.h +130 -0
  507. package/external/folly/folly/functional/protocol.h +203 -0
  508. package/external/folly/folly/functional/test/ApplyTupleTest.cpp +549 -0
  509. package/external/folly/folly/functional/test/BUCK +57 -0
  510. package/external/folly/folly/functional/test/InvokeTest.cpp +483 -0
  511. package/external/folly/folly/functional/test/PartialTest.cpp +141 -0
  512. package/external/folly/folly/functional/test/protocol_test.cpp +177 -0
  513. package/external/folly/folly/functional/test/traits_test.cpp +551 -0
  514. package/external/folly/folly/functional/traits.h +675 -0
  515. package/external/folly/folly/hash/BUCK +86 -0
  516. package/external/folly/folly/hash/Checksum.cpp +275 -0
  517. package/external/folly/folly/hash/Checksum.h +94 -0
  518. package/external/folly/folly/hash/FarmHash.h +46 -0
  519. package/external/folly/folly/hash/Hash.h +1045 -0
  520. package/external/folly/folly/hash/MurmurHash.h +86 -0
  521. package/external/folly/folly/hash/SpookyHashV1.cpp +391 -0
  522. package/external/folly/folly/hash/SpookyHashV1.h +307 -0
  523. package/external/folly/folly/hash/SpookyHashV2.cpp +392 -0
  524. package/external/folly/folly/hash/SpookyHashV2.h +339 -0
  525. package/external/folly/folly/hash/detail/BUCK +26 -0
  526. package/external/folly/folly/hash/detail/ChecksumDetail.cpp +296 -0
  527. package/external/folly/folly/hash/detail/ChecksumDetail.h +137 -0
  528. package/external/folly/folly/hash/detail/Crc32CombineDetail.cpp +191 -0
  529. package/external/folly/folly/hash/detail/Crc32cDetail.cpp +303 -0
  530. package/external/folly/folly/hash/test/BUCK +132 -0
  531. package/external/folly/folly/hash/test/ChecksumBenchmark.cpp +91 -0
  532. package/external/folly/folly/hash/test/ChecksumTest.cpp +587 -0
  533. package/external/folly/folly/hash/test/FarmHashTest.cpp +41 -0
  534. package/external/folly/folly/hash/test/HashBenchmark.cpp +238 -0
  535. package/external/folly/folly/hash/test/HashTest.cpp +997 -0
  536. package/external/folly/folly/hash/test/MurmurHashTest.cpp +76 -0
  537. package/external/folly/folly/hash/test/SpookyHashV1Test.cpp +559 -0
  538. package/external/folly/folly/hash/test/SpookyHashV2Test.cpp +549 -0
  539. package/external/folly/folly/hash/test/traits_test.cpp +69 -0
  540. package/external/folly/folly/hash/traits.h +115 -0
  541. package/external/folly/folly/json/BUCK +155 -0
  542. package/external/folly/folly/json/DynamicConverter.h +464 -0
  543. package/external/folly/folly/json/DynamicParser-inl.h +316 -0
  544. package/external/folly/folly/json/DynamicParser.cpp +198 -0
  545. package/external/folly/folly/json/DynamicParser.h +394 -0
  546. package/external/folly/folly/json/JSONSchema.cpp +1030 -0
  547. package/external/folly/folly/json/JSONSchema.h +73 -0
  548. package/external/folly/folly/json/JsonMockUtil.h +73 -0
  549. package/external/folly/folly/json/JsonTestUtil.cpp +167 -0
  550. package/external/folly/folly/json/JsonTestUtil.h +88 -0
  551. package/external/folly/folly/json/bser/BUCK +24 -0
  552. package/external/folly/folly/json/bser/Bser.h +107 -0
  553. package/external/folly/folly/json/bser/Dump.cpp +253 -0
  554. package/external/folly/folly/json/bser/Load.cpp +246 -0
  555. package/external/folly/folly/json/bser/test/BUCK +14 -0
  556. package/external/folly/folly/json/bser/test/BserTest.cpp +149 -0
  557. package/external/folly/folly/json/dynamic.cpp +552 -0
  558. package/external/folly/folly/json/dynamic.h +1346 -0
  559. package/external/folly/folly/json/json.h +238 -0
  560. package/external/folly/folly/json/json_patch.cpp +325 -0
  561. package/external/folly/folly/json/json_patch.h +126 -0
  562. package/external/folly/folly/json/json_pointer.cpp +114 -0
  563. package/external/folly/folly/json/json_pointer.h +87 -0
  564. package/external/folly/folly/json/test/BUCK +147 -0
  565. package/external/folly/folly/json/test/DynamicBenchmark.cpp +146 -0
  566. package/external/folly/folly/json/test/DynamicConverterTest.cpp +518 -0
  567. package/external/folly/folly/json/test/DynamicOtherTest.cpp +344 -0
  568. package/external/folly/folly/json/test/DynamicParserTest.cpp +443 -0
  569. package/external/folly/folly/json/test/DynamicTest.cpp +1647 -0
  570. package/external/folly/folly/json/test/JSONSchemaTest.cpp +450 -0
  571. package/external/folly/folly/json/test/JsonBenchmark.cpp +264 -0
  572. package/external/folly/folly/json/test/JsonOtherTest.cpp +51 -0
  573. package/external/folly/folly/json/test/JsonTest.cpp +1153 -0
  574. package/external/folly/folly/json/test/JsonTestUtilTest.cpp +97 -0
  575. package/external/folly/folly/json/test/json_patch_test.cpp +361 -0
  576. package/external/folly/folly/json/test/json_pointer_test.cpp +58 -0
  577. package/external/folly/folly/json/tool/BUCK +13 -0
  578. package/external/folly/folly/json/tool/JSONSchemaTester.cpp +58 -0
  579. package/external/folly/folly/json.h +17 -0
  580. package/external/folly/folly/json_patch.h +17 -0
  581. package/external/folly/folly/json_pointer.h +17 -0
  582. package/external/folly/folly/lang/Access.h +29 -0
  583. package/external/folly/folly/lang/Align.h +240 -0
  584. package/external/folly/folly/lang/Aligned.h +92 -0
  585. package/external/folly/folly/lang/Assume.h +82 -0
  586. package/external/folly/folly/lang/BUCK +287 -0
  587. package/external/folly/folly/lang/Badge.h +108 -0
  588. package/external/folly/folly/lang/Bits.h +570 -0
  589. package/external/folly/folly/lang/BitsClass.h +312 -0
  590. package/external/folly/folly/lang/Builtin.h +74 -0
  591. package/external/folly/folly/lang/CArray.h +34 -0
  592. package/external/folly/folly/lang/CString.cpp +86 -0
  593. package/external/folly/folly/lang/CString.h +55 -0
  594. package/external/folly/folly/lang/Cast.h +51 -0
  595. package/external/folly/folly/lang/CheckedMath.h +253 -0
  596. package/external/folly/folly/lang/CustomizationPoint.h +58 -0
  597. package/external/folly/folly/lang/Exception.cpp +822 -0
  598. package/external/folly/folly/lang/Exception.h +716 -0
  599. package/external/folly/folly/lang/Extern.h +55 -0
  600. package/external/folly/folly/lang/Hint-inl.h +144 -0
  601. package/external/folly/folly/lang/Hint.h +238 -0
  602. package/external/folly/folly/lang/Keep.h +98 -0
  603. package/external/folly/folly/lang/New.h +124 -0
  604. package/external/folly/folly/lang/Ordering.h +140 -0
  605. package/external/folly/folly/lang/Pretty.h +159 -0
  606. package/external/folly/folly/lang/PropagateConst.h +413 -0
  607. package/external/folly/folly/lang/RValueReferenceWrapper.h +152 -0
  608. package/external/folly/folly/lang/SafeAssert.cpp +589 -0
  609. package/external/folly/folly/lang/StaticConst.h +33 -0
  610. package/external/folly/folly/lang/Thunk.h +100 -0
  611. package/external/folly/folly/lang/TypeInfo.h +58 -0
  612. package/external/folly/folly/lang/UncaughtExceptions.cpp +17 -0
  613. package/external/folly/folly/lang/UncaughtExceptions.h +19 -0
  614. package/external/folly/folly/lang/test/AlignTest.cpp +87 -0
  615. package/external/folly/folly/lang/test/AlignedTest.cpp +130 -0
  616. package/external/folly/folly/lang/test/BUCK +258 -0
  617. package/external/folly/folly/lang/test/BadgeTest.cpp +89 -0
  618. package/external/folly/folly/lang/test/BitsBenchmark.cpp +164 -0
  619. package/external/folly/folly/lang/test/BitsClassBenchmark.cpp +122 -0
  620. package/external/folly/folly/lang/test/BitsClassTest.cpp +379 -0
  621. package/external/folly/folly/lang/test/BitsTest.cpp +577 -0
  622. package/external/folly/folly/lang/test/CStringTest.cpp +60 -0
  623. package/external/folly/folly/lang/test/CastTest.cpp +47 -0
  624. package/external/folly/folly/lang/test/CheckedMathTest.cpp +394 -0
  625. package/external/folly/folly/lang/test/ExceptionBench.cpp +427 -0
  626. package/external/folly/folly/lang/test/ExceptionTest.cpp +413 -0
  627. package/external/folly/folly/lang/test/ExternTest.cpp +39 -0
  628. package/external/folly/folly/lang/test/HintTest.cpp +100 -0
  629. package/external/folly/folly/lang/test/NewTest.cpp +38 -0
  630. package/external/folly/folly/lang/test/OrderingTest.cpp +105 -0
  631. package/external/folly/folly/lang/test/PrettyTest.cpp +44 -0
  632. package/external/folly/folly/lang/test/PropagateConstTest.cpp +356 -0
  633. package/external/folly/folly/lang/test/RValueReferenceWrapperTest.cpp +85 -0
  634. package/external/folly/folly/lang/test/SafeAssertTest.cpp +75 -0
  635. package/external/folly/folly/lang/test/ThunkTest.cpp +105 -0
  636. package/external/folly/folly/lang/test/ToAsciiBench.cpp +466 -0
  637. package/external/folly/folly/lang/test/ToAsciiTest.cpp +266 -0
  638. package/external/folly/folly/lang/test/TypeInfoTest.cpp +56 -0
  639. package/external/folly/folly/memcpy.S +292 -0
  640. package/external/folly/folly/memcpy_select_aarch64.cpp +145 -0
  641. package/external/folly/folly/memory/Arena-inl.h +83 -0
  642. package/external/folly/folly/memory/Arena.h +325 -0
  643. package/external/folly/folly/memory/BUCK +191 -0
  644. package/external/folly/folly/memory/JemallocHugePageAllocator.cpp +449 -0
  645. package/external/folly/folly/memory/JemallocHugePageAllocator.h +105 -0
  646. package/external/folly/folly/memory/JemallocHugePageAllocatorTest.cpp +341 -0
  647. package/external/folly/folly/memory/JemallocNodumpAllocator.cpp +176 -0
  648. package/external/folly/folly/memory/JemallocNodumpAllocator.h +119 -0
  649. package/external/folly/folly/memory/JemallocNodumpAllocatorTest.cpp +61 -0
  650. package/external/folly/folly/memory/MallctlHelper.cpp +37 -0
  651. package/external/folly/folly/memory/MallctlHelper.h +167 -0
  652. package/external/folly/folly/memory/Malloc.h +551 -0
  653. package/external/folly/folly/memory/MemoryResource.h +57 -0
  654. package/external/folly/folly/memory/ReentrantAllocator.cpp +162 -0
  655. package/external/folly/folly/memory/ReentrantAllocator.h +261 -0
  656. package/external/folly/folly/memory/SanitizeAddress.cpp +75 -0
  657. package/external/folly/folly/memory/SanitizeAddress.h +117 -0
  658. package/external/folly/folly/memory/SanitizeLeak.cpp +119 -0
  659. package/external/folly/folly/memory/SanitizeLeak.h +108 -0
  660. package/external/folly/folly/memory/ThreadCachedArena.cpp +53 -0
  661. package/external/folly/folly/memory/ThreadCachedArena.h +90 -0
  662. package/external/folly/folly/memory/UninitializedMemoryHacks.h +426 -0
  663. package/external/folly/folly/memory/detail/BUCK +10 -0
  664. package/external/folly/folly/memory/detail/MallocImpl.cpp +52 -0
  665. package/external/folly/folly/memory/detail/MallocImpl.h +97 -0
  666. package/external/folly/folly/memory/not_null-inl.h +522 -0
  667. package/external/folly/folly/memory/not_null.h +449 -0
  668. package/external/folly/folly/memory/test/ArenaTest.cpp +354 -0
  669. package/external/folly/folly/memory/test/BUCK +146 -0
  670. package/external/folly/folly/memory/test/MallctlHelperTest.cpp +169 -0
  671. package/external/folly/folly/memory/test/MallocBenchmark.cpp +91 -0
  672. package/external/folly/folly/memory/test/MallocTest.cpp +78 -0
  673. package/external/folly/folly/memory/test/MemoryResourceTest.cpp +31 -0
  674. package/external/folly/folly/memory/test/ReentrantAllocatorTest.cpp +144 -0
  675. package/external/folly/folly/memory/test/SanitizeAddressTest.cpp +67 -0
  676. package/external/folly/folly/memory/test/SanitizeLeakTest.cpp +139 -0
  677. package/external/folly/folly/memory/test/ThreadCachedArenaTest.cpp +276 -0
  678. package/external/folly/folly/memory/test/UninitializedMemoryHacksODR.cpp +21 -0
  679. package/external/folly/folly/memory/test/UninitializedMemoryHacksTest.cpp +327 -0
  680. package/external/folly/folly/memory/test/not_null_test.cpp +608 -0
  681. package/external/folly/folly/memset.S +245 -0
  682. package/external/folly/folly/memset_select_aarch64.cpp +72 -0
  683. package/external/folly/folly/portability/Asm.h +50 -0
  684. package/external/folly/folly/portability/Atomic.h +31 -0
  685. package/external/folly/folly/portability/BUCK +456 -0
  686. package/external/folly/folly/portability/Builtins.cpp +31 -0
  687. package/external/folly/folly/portability/Builtins.h +161 -0
  688. package/external/folly/folly/portability/Config.h +43 -0
  689. package/external/folly/folly/portability/Constexpr.h +145 -0
  690. package/external/folly/folly/portability/Dirent.cpp +140 -0
  691. package/external/folly/folly/portability/Dirent.h +41 -0
  692. package/external/folly/folly/portability/Event.h +44 -0
  693. package/external/folly/folly/portability/Fcntl.cpp +120 -0
  694. package/external/folly/folly/portability/Fcntl.h +67 -0
  695. package/external/folly/folly/portability/Filesystem.cpp +67 -0
  696. package/external/folly/folly/portability/Filesystem.h +114 -0
  697. package/external/folly/folly/portability/FmtCompile.h +40 -0
  698. package/external/folly/folly/portability/GFlags.h +139 -0
  699. package/external/folly/folly/portability/GMock.h +35 -0
  700. package/external/folly/folly/portability/GTest.h +35 -0
  701. package/external/folly/folly/portability/IOVec.h +34 -0
  702. package/external/folly/folly/portability/Libgen.cpp +59 -0
  703. package/external/folly/folly/portability/Libgen.h +29 -0
  704. package/external/folly/folly/portability/Libunwind.h +21 -0
  705. package/external/folly/folly/portability/Malloc.cpp +31 -0
  706. package/external/folly/folly/portability/Malloc.h +53 -0
  707. package/external/folly/folly/portability/Math.h +90 -0
  708. package/external/folly/folly/portability/Memory.h +26 -0
  709. package/external/folly/folly/portability/OpenSSL.cpp +17 -0
  710. package/external/folly/folly/portability/OpenSSL.h +102 -0
  711. package/external/folly/folly/portability/PThread.cpp +697 -0
  712. package/external/folly/folly/portability/PThread.h +148 -0
  713. package/external/folly/folly/portability/README.md +21 -0
  714. package/external/folly/folly/portability/Sched.cpp +41 -0
  715. package/external/folly/folly/portability/Sched.h +45 -0
  716. package/external/folly/folly/portability/Sockets.cpp +245 -0
  717. package/external/folly/folly/portability/Sockets.h +155 -0
  718. package/external/folly/folly/portability/SourceLocation.h +49 -0
  719. package/external/folly/folly/portability/Stdio.cpp +77 -0
  720. package/external/folly/folly/portability/Stdio.h +32 -0
  721. package/external/folly/folly/portability/Stdlib.cpp +172 -0
  722. package/external/folly/folly/portability/Stdlib.h +64 -0
  723. package/external/folly/folly/portability/String.cpp +53 -0
  724. package/external/folly/folly/portability/String.h +39 -0
  725. package/external/folly/folly/portability/SysFile.cpp +46 -0
  726. package/external/folly/folly/portability/SysFile.h +27 -0
  727. package/external/folly/folly/portability/SysMembarrier.cpp +104 -0
  728. package/external/folly/folly/portability/SysMembarrier.h +26 -0
  729. package/external/folly/folly/portability/SysMman.cpp +242 -0
  730. package/external/folly/folly/portability/SysMman.h +68 -0
  731. package/external/folly/folly/portability/SysResource.cpp +108 -0
  732. package/external/folly/folly/portability/SysResource.h +71 -0
  733. package/external/folly/folly/portability/SysStat.cpp +66 -0
  734. package/external/folly/folly/portability/SysStat.h +52 -0
  735. package/external/folly/folly/portability/SysSyscall.h +73 -0
  736. package/external/folly/folly/portability/SysTime.cpp +62 -0
  737. package/external/folly/folly/portability/SysTime.h +50 -0
  738. package/external/folly/folly/portability/SysTypes.h +44 -0
  739. package/external/folly/folly/portability/SysUio.cpp +179 -0
  740. package/external/folly/folly/portability/SysUio.h +51 -0
  741. package/external/folly/folly/portability/Syslog.h +39 -0
  742. package/external/folly/folly/portability/Time.cpp +357 -0
  743. package/external/folly/folly/portability/Time.h +74 -0
  744. package/external/folly/folly/portability/Unistd.h +111 -0
  745. package/external/folly/folly/portability/Windows.h +108 -0
  746. package/external/folly/folly/portability/openat2.c +30 -0
  747. package/external/folly/folly/portability/openat2.h +39 -0
  748. package/external/folly/folly/portability/test/BUCK +59 -0
  749. package/external/folly/folly/portability/test/ConstexprTest.cpp +102 -0
  750. package/external/folly/folly/portability/test/FilesystemTest.cpp +35 -0
  751. package/external/folly/folly/portability/test/LibgenTest.cpp +35 -0
  752. package/external/folly/folly/portability/test/OpenSSLPortabilityTest.cpp +108 -0
  753. package/external/folly/folly/portability/test/PThreadTest.cpp +80 -0
  754. package/external/folly/folly/portability/test/TimeTest.cpp +90 -0
  755. package/external/folly/folly/small_vector.h +17 -0
  756. package/external/folly/folly/somerge_defs.bzl +399 -0
  757. package/external/folly/folly/sorted_vector_types.h +17 -0
  758. package/external/folly/folly/stop_watch.h +317 -0
  759. package/external/folly/folly/synchronization/AsymmetricThreadFence.cpp +91 -0
  760. package/external/folly/folly/synchronization/AsymmetricThreadFence.h +60 -0
  761. package/external/folly/folly/synchronization/AtomicNotification-inl.h +146 -0
  762. package/external/folly/folly/synchronization/AtomicNotification.cpp +34 -0
  763. package/external/folly/folly/synchronization/AtomicNotification.h +117 -0
  764. package/external/folly/folly/synchronization/AtomicRef.h +181 -0
  765. package/external/folly/folly/synchronization/AtomicStruct.h +150 -0
  766. package/external/folly/folly/synchronization/AtomicUtil-inl.h +482 -0
  767. package/external/folly/folly/synchronization/AtomicUtil.h +179 -0
  768. package/external/folly/folly/synchronization/BUCK +418 -0
  769. package/external/folly/folly/synchronization/Baton.h +419 -0
  770. package/external/folly/folly/synchronization/CallOnce.h +263 -0
  771. package/external/folly/folly/synchronization/DelayedInit.h +179 -0
  772. package/external/folly/folly/synchronization/DistributedMutex-inl.h +1744 -0
  773. package/external/folly/folly/synchronization/DistributedMutex.cpp +27 -0
  774. package/external/folly/folly/synchronization/DistributedMutex.h +342 -0
  775. package/external/folly/folly/synchronization/EventCount.h +200 -0
  776. package/external/folly/folly/synchronization/FlatCombining.h +629 -0
  777. package/external/folly/folly/synchronization/Hazptr-fwd.h +217 -0
  778. package/external/folly/folly/synchronization/Hazptr.cpp +36 -0
  779. package/external/folly/folly/synchronization/Hazptr.h +209 -0
  780. package/external/folly/folly/synchronization/HazptrDomain.cpp +68 -0
  781. package/external/folly/folly/synchronization/HazptrDomain.h +832 -0
  782. package/external/folly/folly/synchronization/HazptrHolder.h +431 -0
  783. package/external/folly/folly/synchronization/HazptrObj.h +533 -0
  784. package/external/folly/folly/synchronization/HazptrObjLinked.h +315 -0
  785. package/external/folly/folly/synchronization/HazptrRec.h +68 -0
  786. package/external/folly/folly/synchronization/HazptrThrLocal.h +180 -0
  787. package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.cpp +46 -0
  788. package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.h +25 -0
  789. package/external/folly/folly/synchronization/Latch.h +160 -0
  790. package/external/folly/folly/synchronization/LifoSem.h +767 -0
  791. package/external/folly/folly/synchronization/Lock.h +887 -0
  792. package/external/folly/folly/synchronization/MicroSpinLock.h +154 -0
  793. package/external/folly/folly/synchronization/NativeSemaphore.h +187 -0
  794. package/external/folly/folly/synchronization/ParkingLot.cpp +37 -0
  795. package/external/folly/folly/synchronization/ParkingLot.h +330 -0
  796. package/external/folly/folly/synchronization/PicoSpinLock.h +167 -0
  797. package/external/folly/folly/synchronization/RWSpinLock.h +549 -0
  798. package/external/folly/folly/synchronization/Rcu.cpp +26 -0
  799. package/external/folly/folly/synchronization/Rcu.h +553 -0
  800. package/external/folly/folly/synchronization/RelaxedAtomic.h +336 -0
  801. package/external/folly/folly/synchronization/SanitizeThread.cpp +141 -0
  802. package/external/folly/folly/synchronization/SanitizeThread.h +166 -0
  803. package/external/folly/folly/synchronization/SaturatingSemaphore.h +324 -0
  804. package/external/folly/folly/synchronization/SmallLocks.h +36 -0
  805. package/external/folly/folly/synchronization/ThrottledLifoSem.h +362 -0
  806. package/external/folly/folly/synchronization/WaitOptions.cpp +25 -0
  807. package/external/folly/folly/synchronization/WaitOptions.h +75 -0
  808. package/external/folly/folly/synchronization/detail/AtomicUtils.h +59 -0
  809. package/external/folly/folly/synchronization/detail/BUCK +104 -0
  810. package/external/folly/folly/synchronization/detail/Hardware.cpp +192 -0
  811. package/external/folly/folly/synchronization/detail/Hardware.h +75 -0
  812. package/external/folly/folly/synchronization/detail/HazptrUtils.h +339 -0
  813. package/external/folly/folly/synchronization/detail/InlineFunctionRef.h +229 -0
  814. package/external/folly/folly/synchronization/detail/Sleeper.cpp +27 -0
  815. package/external/folly/folly/synchronization/detail/Sleeper.h +62 -0
  816. package/external/folly/folly/synchronization/detail/Spin.h +96 -0
  817. package/external/folly/folly/synchronization/detail/ThreadCachedLists.h +174 -0
  818. package/external/folly/folly/synchronization/detail/ThreadCachedReaders.h +189 -0
  819. package/external/folly/folly/synchronization/detail/ThreadCachedTag.h +26 -0
  820. package/external/folly/folly/synchronization/detail/test/BUCK +28 -0
  821. package/external/folly/folly/synchronization/detail/test/HardwareTest.cpp +74 -0
  822. package/external/folly/folly/synchronization/detail/test/InlineFunctionRefTest.cpp +286 -0
  823. package/external/folly/folly/synchronization/example/BUCK +27 -0
  824. package/external/folly/folly/synchronization/example/HazptrLockFreeLIFO.h +88 -0
  825. package/external/folly/folly/synchronization/example/HazptrSWMRSet.h +133 -0
  826. package/external/folly/folly/synchronization/example/HazptrWideCAS.h +62 -0
  827. package/external/folly/folly/synchronization/test/AtomicNotificationTest.cpp +236 -0
  828. package/external/folly/folly/synchronization/test/AtomicRefTest.cpp +170 -0
  829. package/external/folly/folly/synchronization/test/AtomicStructTest.cpp +65 -0
  830. package/external/folly/folly/synchronization/test/AtomicUtilBench.cpp +457 -0
  831. package/external/folly/folly/synchronization/test/AtomicUtilTest.cpp +650 -0
  832. package/external/folly/folly/synchronization/test/BUCK +495 -0
  833. package/external/folly/folly/synchronization/test/Barrier.h +52 -0
  834. package/external/folly/folly/synchronization/test/BarrierTest.cpp +56 -0
  835. package/external/folly/folly/synchronization/test/BatonBenchmark.cpp +77 -0
  836. package/external/folly/folly/synchronization/test/BatonTest.cpp +164 -0
  837. package/external/folly/folly/synchronization/test/BatonTestHelpers.h +118 -0
  838. package/external/folly/folly/synchronization/test/CallOnceBenchmark.cpp +72 -0
  839. package/external/folly/folly/synchronization/test/CallOnceTest.cpp +153 -0
  840. package/external/folly/folly/synchronization/test/DelayedInitTest.cpp +281 -0
  841. package/external/folly/folly/synchronization/test/DistributedMutexTest.cpp +2074 -0
  842. package/external/folly/folly/synchronization/test/EventCountTest.cpp +124 -0
  843. package/external/folly/folly/synchronization/test/FlatCombiningBenchmark.cpp +1789 -0
  844. package/external/folly/folly/synchronization/test/FlatCombiningExamples.h +222 -0
  845. package/external/folly/folly/synchronization/test/FlatCombiningTest.cpp +121 -0
  846. package/external/folly/folly/synchronization/test/FlatCombiningTestHelpers.h +227 -0
  847. package/external/folly/folly/synchronization/test/HazptrTest.cpp +1689 -0
  848. package/external/folly/folly/synchronization/test/LatchTest.cpp +224 -0
  849. package/external/folly/folly/synchronization/test/LifoSemBench.cpp +185 -0
  850. package/external/folly/folly/synchronization/test/LifoSemTests.cpp +353 -0
  851. package/external/folly/folly/synchronization/test/LockTest.cpp +1239 -0
  852. package/external/folly/folly/synchronization/test/NativeSemaphoreTest.cpp +37 -0
  853. package/external/folly/folly/synchronization/test/ParkingLotBenchmark.cpp +239 -0
  854. package/external/folly/folly/synchronization/test/ParkingLotTest.cpp +170 -0
  855. package/external/folly/folly/synchronization/test/RWSpinLockTest.cpp +235 -0
  856. package/external/folly/folly/synchronization/test/RcuBench.cpp +66 -0
  857. package/external/folly/folly/synchronization/test/RcuTest.cpp +330 -0
  858. package/external/folly/folly/synchronization/test/RelaxedAtomicTest.cpp +389 -0
  859. package/external/folly/folly/synchronization/test/SaturatingSemaphoreTest.cpp +166 -0
  860. package/external/folly/folly/synchronization/test/Semaphore.h +242 -0
  861. package/external/folly/folly/synchronization/test/SemaphoreTest.cpp +271 -0
  862. package/external/folly/folly/synchronization/test/SmallLocksBenchmark.cpp +1296 -0
  863. package/external/folly/folly/synchronization/test/SmallLocksTest.cpp +510 -0
  864. package/external/folly/folly/synchronization/test/ThreadCachedEpochBench.h +67 -0
  865. package/external/folly/folly/synchronization/test/ThreadCachedReadersBench.cpp +42 -0
  866. package/external/folly/folly/synchronization/test/ThreadCachedReadersTest.cpp +52 -0
  867. package/external/folly/folly/synchronization/test/ThrottledLifoSemTest.cpp +243 -0
  868. package/external/folly/folly/system/AtFork.cpp +205 -0
  869. package/external/folly/folly/system/AtFork.h +116 -0
  870. package/external/folly/folly/system/AuxVector.h +198 -0
  871. package/external/folly/folly/system/BUCK +144 -0
  872. package/external/folly/folly/system/EnvUtil.cpp +93 -0
  873. package/external/folly/folly/system/EnvUtil.h +113 -0
  874. package/external/folly/folly/system/HardwareConcurrency.cpp +39 -0
  875. package/external/folly/folly/system/HardwareConcurrency.h +23 -0
  876. package/external/folly/folly/system/MemoryMapping.cpp +477 -0
  877. package/external/folly/folly/system/MemoryMapping.h +287 -0
  878. package/external/folly/folly/system/Pid.cpp +87 -0
  879. package/external/folly/folly/system/Pid.h +34 -0
  880. package/external/folly/folly/system/Shell.cpp +33 -0
  881. package/external/folly/folly/system/Shell.h +93 -0
  882. package/external/folly/folly/system/ThreadId.cpp +89 -0
  883. package/external/folly/folly/system/ThreadId.h +62 -0
  884. package/external/folly/folly/system/ThreadName.cpp +330 -0
  885. package/external/folly/folly/system/ThreadName.h +72 -0
  886. package/external/folly/folly/system/test/AtForkTest.cpp +309 -0
  887. package/external/folly/folly/system/test/AuxVectorTest.cpp +55 -0
  888. package/external/folly/folly/system/test/BUCK +120 -0
  889. package/external/folly/folly/system/test/EnvUtilSubprocess.cpp +26 -0
  890. package/external/folly/folly/system/test/EnvUtilTest.cpp +197 -0
  891. package/external/folly/folly/system/test/MemoryMappingTest.cpp +179 -0
  892. package/external/folly/folly/system/test/PidTest.cpp +46 -0
  893. package/external/folly/folly/system/test/ShellTest.cpp +66 -0
  894. package/external/folly/folly/system/test/ThreadIdTest.cpp +114 -0
  895. package/external/folly/folly/system/test/ThreadNameTest.cpp +85 -0
  896. package/external/folly/folly.vcxitems +164 -0
  897. package/external/folly/static/logo.svg +1 -0
  898. package/external/folly/sync-config.json +8 -0
  899. package/package.json +6 -6
  900. package/template/cpp-lib/proj/MyLib.sln +0 -33
  901. package/template/cs-lib/proj/MyLib.sln +0 -33
  902. package/templates/cpp-app/windows/MyApp.sln +0 -33
  903. package/templates/cpp-lib/example/metro.config.js +30 -4
  904. package/templates/cpp-lib/windows/MyLib.sln +0 -33
  905. package/Folly/Folly.vcxproj +0 -378
  906. package/Folly/Folly.vcxproj.filters +0 -558
  907. package/fmt/fmt.vcxproj +0 -153
  908. package/fmt/fmt.vcxproj.filters +0 -59
  909. package/fmt/pch.cpp +0 -4
  910. package/fmt/pch.h +0 -2
  911. /package/{fmt → external/fmt}/cgmanifest.json +0 -0
  912. /package/{Folly → external/folly}/Folly.natvis +0 -0
  913. /package/{Folly → external/folly}/cgmanifest.json +0 -0
  914. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/ConstexprMath.h +0 -0
  915. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/Conv.cpp +0 -0
  916. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/chrono/Hardware.h +0 -0
  917. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/concurrency/CacheLocality.cpp +0 -0
  918. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/dynamic-inl.h +0 -0
  919. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/json.cpp +0 -0
  920. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/SafeAssert.h +0 -0
  921. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.cpp +0 -0
  922. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.h +0 -0
  923. /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/portability/Unistd.cpp +0 -0
@@ -0,0 +1,2680 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
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
+
17
+ #pragma once
18
+
19
+ #include <cstddef>
20
+ #include <cstdint>
21
+ #include <cstring>
22
+
23
+ #include <array>
24
+ #include <iterator>
25
+ #include <limits>
26
+ #include <memory>
27
+ #include <new>
28
+ #include <string_view>
29
+ #include <type_traits>
30
+ #include <utility>
31
+ #include <vector>
32
+
33
+ #include <folly/Bits.h>
34
+ #include <folly/ConstexprMath.h>
35
+ #include <folly/Likely.h>
36
+ #include <folly/Memory.h>
37
+ #include <folly/Portability.h>
38
+ #include <folly/ScopeGuard.h>
39
+ #include <folly/Traits.h>
40
+ #include <folly/functional/Invoke.h>
41
+ #include <folly/lang/Align.h>
42
+ #include <folly/lang/Assume.h>
43
+ #include <folly/lang/Exception.h>
44
+ #include <folly/lang/Pretty.h>
45
+ #include <folly/lang/SafeAssert.h>
46
+ #include <folly/portability/Builtins.h>
47
+
48
+ #include <folly/container/HeterogeneousAccess.h>
49
+ #include <folly/container/detail/F14Defaults.h>
50
+ #include <folly/container/detail/F14IntrinsicsAvailability.h>
51
+ #include <folly/container/detail/F14Mask.h>
52
+
53
+ #if __has_include(<concepts>)
54
+ #include <concepts>
55
+ #endif
56
+
57
+ #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
58
+
59
+ #if FOLLY_F14_CRC_INTRINSIC_AVAILABLE
60
+ #if FOLLY_NEON
61
+ #include <arm_acle.h> // __crc32cd
62
+ #else
63
+ #include <nmmintrin.h> // _mm_crc32_u64
64
+ #endif
65
+ #else
66
+ #ifdef _WIN32
67
+ #include <intrin.h> // _mul128 in fallback bit mixer
68
+ #endif
69
+ #endif
70
+
71
+ #if FOLLY_NEON
72
+ #include <arm_neon.h> // uint8x16t intrinsics
73
+ #elif FOLLY_SSE >= 2 // SSE2
74
+ #include <emmintrin.h> // _mm_set1_epi8
75
+ #include <immintrin.h> // __m128i intrinsics
76
+ #include <xmmintrin.h> // _mm_prefetch
77
+ #endif
78
+
79
+ #ifndef FOLLY_F14_PERTURB_INSERTION_ORDER
80
+ #define FOLLY_F14_PERTURB_INSERTION_ORDER folly::kIsDebug
81
+ #endif
82
+
83
+ #else // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
84
+
85
+ #ifndef FOLLY_F14_PERTURB_INSERTION_ORDER
86
+ #define FOLLY_F14_PERTURB_INSERTION_ORDER false
87
+ #endif
88
+
89
+ #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
90
+
91
+ namespace folly {
92
+
93
+ struct F14TableStats {
94
+ char const* policy;
95
+ std::size_t size{0};
96
+ std::size_t valueSize{0};
97
+ std::size_t bucketCount{0};
98
+ std::size_t chunkCount{0};
99
+ std::vector<std::size_t> chunkOccupancyHisto;
100
+ std::vector<std::size_t> chunkOutboundOverflowHisto;
101
+ std::vector<std::size_t> chunkHostedOverflowHisto;
102
+ std::vector<std::size_t> keyProbeLengthHisto;
103
+ std::vector<std::size_t> missProbeLengthHisto;
104
+ std::size_t totalBytes{0};
105
+ std::size_t overheadBytes{0};
106
+
107
+ private:
108
+ template <typename T>
109
+ static auto computeHelper(T const* m) -> decltype(m->computeStats()) {
110
+ return m->computeStats();
111
+ }
112
+
113
+ static F14TableStats computeHelper(...) { return {}; }
114
+
115
+ public:
116
+ template <typename T>
117
+ static F14TableStats compute(T const& m) {
118
+ return computeHelper(&m);
119
+ }
120
+ };
121
+
122
+ namespace f14 {
123
+ namespace detail {
124
+
125
+ template <F14IntrinsicsMode>
126
+ struct F14LinkCheck {};
127
+
128
+ template <>
129
+ struct F14LinkCheck<getF14IntrinsicsMode()> {
130
+ // The purpose of this method is to trigger a link failure if
131
+ // compilation flags vary across compilation units. The definition
132
+ // is in F14Table.cpp, so only one of F14LinkCheck<None>::check,
133
+ // F14LinkCheck<Simd>::check, or F14LinkCheck<SimdAndCrc>::check will
134
+ // be available at link time.
135
+ //
136
+ // To cause a link failure the function must be invoked in code that
137
+ // is not optimized away, so we call it on a couple of cold paths
138
+ // (exception handling paths in copy construction and rehash). LTO may
139
+ // remove it entirely, but that's fine.
140
+ static void check() noexcept;
141
+ };
142
+
143
+ bool tlsPendingSafeInserts(std::ptrdiff_t delta = 0);
144
+ std::size_t tlsMinstdRand(std::size_t n);
145
+
146
+ #if defined(_LIBCPP_VERSION)
147
+
148
+ template <typename K, typename V, typename H>
149
+ struct StdNodeReplica {
150
+ void* next;
151
+ std::size_t hash;
152
+ V value;
153
+ };
154
+
155
+ #else
156
+
157
+ template <typename H>
158
+ struct StdIsFastHash : std::true_type {};
159
+ template <>
160
+ struct StdIsFastHash<std::hash<long double>> : std::false_type {};
161
+ template <typename... Args>
162
+ struct StdIsFastHash<std::hash<std::basic_string<Args...>>> : std::false_type {
163
+ };
164
+ template <typename... Args>
165
+ struct StdIsFastHash<std::hash<std::basic_string_view<Args...>>>
166
+ : std::false_type {};
167
+
168
+ // mimic internal node of unordered containers in STL to estimate the size
169
+ template <typename K, typename V, typename H, typename Enable = void>
170
+ struct StdNodeReplica {
171
+ void* next;
172
+ V value;
173
+ };
174
+ template <typename K, typename V, typename H>
175
+ struct StdNodeReplica<
176
+ K,
177
+ V,
178
+ H,
179
+ std::enable_if_t<
180
+ !StdIsFastHash<H>::value || !is_nothrow_invocable_v<H, K>>> {
181
+ void* next;
182
+ V value;
183
+ std::size_t hash;
184
+ };
185
+
186
+ #endif
187
+
188
+ template <class Container, class Predicate>
189
+ typename Container::size_type erase_if_impl(
190
+ Container& c, Predicate& predicate) {
191
+ auto const old_size = c.size();
192
+ for (auto i = c.begin(), last = c.end(); i != last;) {
193
+ auto prev = i++;
194
+ if (predicate(*prev)) {
195
+ c.erase(prev);
196
+ }
197
+ }
198
+ return old_size - c.size();
199
+ }
200
+
201
+ } // namespace detail
202
+ } // namespace f14
203
+
204
+ #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
205
+ namespace f14 {
206
+ namespace detail {
207
+ template <typename Policy>
208
+ class F14Table;
209
+ } // namespace detail
210
+ } // namespace f14
211
+
212
+ class F14HashToken final {
213
+ public:
214
+ constexpr F14HashToken() = default;
215
+
216
+ friend constexpr bool operator==(
217
+ F14HashToken const& a, F14HashToken const& b) noexcept {
218
+ return a.hp_.first == b.hp_.first; // processed hash but not tag
219
+ }
220
+ friend constexpr bool operator!=(
221
+ F14HashToken const& a, F14HashToken const& b) noexcept {
222
+ return !(a == b);
223
+ }
224
+
225
+ private:
226
+ using HashPair = std::pair<std::size_t, std::size_t>;
227
+
228
+ constexpr explicit F14HashToken(HashPair hp) noexcept : hp_(hp) {}
229
+ constexpr explicit operator HashPair() const noexcept { return hp_; }
230
+
231
+ HashPair hp_;
232
+
233
+ template <typename Policy>
234
+ friend class f14::detail::F14Table;
235
+
236
+ template <typename Key, typename Hasher>
237
+ friend class F14HashedKey;
238
+ };
239
+
240
+ #else
241
+ class F14HashToken final {
242
+ friend constexpr bool operator==(
243
+ F14HashToken const&, F14HashToken const&) noexcept {
244
+ return true;
245
+ }
246
+ friend constexpr bool operator!=(
247
+ F14HashToken const&, F14HashToken const&) noexcept {
248
+ return false;
249
+ }
250
+ };
251
+ #endif
252
+
253
+ #if __cpp_concepts && __has_include(<concepts>)
254
+ static_assert(std::regular<F14HashToken>);
255
+ #endif
256
+
257
+ namespace f14 {
258
+ namespace detail {
259
+
260
+ // Detection for folly_assume_32bit_hash
261
+
262
+ template <typename Hasher, typename Void = void>
263
+ struct ShouldAssume32BitHash : std::bool_constant<!require_sizeof<Hasher>> {};
264
+
265
+ template <typename Hasher>
266
+ struct ShouldAssume32BitHash<
267
+ Hasher,
268
+ void_t<typename Hasher::folly_assume_32bit_hash>>
269
+ : std::bool_constant<Hasher::folly_assume_32bit_hash::value> {};
270
+
271
+ //////// hash helpers
272
+
273
+ // Hash values are used to compute the desired position, which is the
274
+ // chunk index at which we would like to place a value (if there is no
275
+ // overflow), and the tag, which is an additional 7 bits of entropy.
276
+ //
277
+ // The standard's definition of hash function quality only refers to
278
+ // the probability of collisions of the entire hash value, not to the
279
+ // probability of collisions of the results of shifting or masking the
280
+ // hash value. Some hash functions, however, provide this stronger
281
+ // guarantee (not quite the same as the definition of avalanching,
282
+ // but similar).
283
+ //
284
+ // If the user-supplied hasher is an avalanching one (each bit of the
285
+ // hash value has a 50% chance of being the same for differing hash
286
+ // inputs), then we can just take 7 bits of the hash value for the tag
287
+ // and the rest for the desired position. Avalanching hashers also
288
+ // let us map hash value to array index position with just a bitmask
289
+ // without risking clumping. (Many hash tables just accept the risk
290
+ // and do it regardless.)
291
+ //
292
+ // std::hash<std::string> avalanches in all implementations we've
293
+ // examined: libstdc++-v3 uses MurmurHash2, and libc++ uses CityHash
294
+ // or MurmurHash2. The other std::hash specializations, however, do not
295
+ // have this property. std::hash for integral and pointer values is the
296
+ // identity function on libstdc++-v3 and libc++, in particular. In our
297
+ // experience it is also fairly common for user-defined specializations
298
+ // of std::hash to combine fields in an ad-hoc way that does not evenly
299
+ // distribute entropy among the bits of the result (a + 37 * b, for
300
+ // example, where a and b are integer fields).
301
+ //
302
+ // For hash functions we don't trust to avalanche, we repair things by
303
+ // applying a bit mixer to the user-supplied hash.
304
+
305
+ #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
306
+ #if FOLLY_X64 || FOLLY_AARCH64 || FOLLY_RISCV64
307
+ // 64-bit
308
+ template <typename Hasher, typename Key>
309
+ std::pair<std::size_t, std::size_t> splitHashImpl(std::size_t hash) {
310
+ static_assert(sizeof(std::size_t) == sizeof(uint64_t), "");
311
+ std::size_t tag;
312
+ if (!IsAvalanchingHasher<Hasher, Key>::value) {
313
+ #if FOLLY_F14_CRC_INTRINSIC_AVAILABLE
314
+ #if FOLLY_SSE_PREREQ(4, 2)
315
+ // SSE4.2 CRC
316
+ std::size_t c = _mm_crc32_u64(0, hash);
317
+ tag = (c >> 24) | 0x80;
318
+ hash += c;
319
+ #else
320
+ // CRC is optional on armv8 (-march=armv8-a+crc), standard on armv8.1
321
+ std::size_t c = __crc32cd(0, hash);
322
+ tag = (c >> 24) | 0x80;
323
+ hash += c;
324
+ #endif
325
+ #else
326
+ // The mixer below is not fully avalanching for all 64 bits of
327
+ // output, but looks quite good for bits 18..63 and puts plenty
328
+ // of entropy even lower when considering multiple bits together
329
+ // (like the tag). Importantly, when under register pressure it
330
+ // uses fewer registers, instructions, and immediate constants
331
+ // than the alternatives, resulting in compact code that is more
332
+ // easily inlinable. In one instantiation a modified Murmur mixer
333
+ // was 48 bytes of assembly (even after using the same multiplicand
334
+ // for both steps) and this one was 27 bytes, for example.
335
+ auto const kMul = 0xc4ceb9fe1a85ec53ULL;
336
+ #ifdef _WIN32
337
+ __int64 signedHi;
338
+ __int64 signedLo = _mul128(
339
+ static_cast<__int64>(hash), static_cast<__int64>(kMul), &signedHi);
340
+ auto hi = static_cast<uint64_t>(signedHi);
341
+ auto lo = static_cast<uint64_t>(signedLo);
342
+ #else
343
+ auto hi = static_cast<uint64_t>(
344
+ (static_cast<unsigned __int128>(hash) * kMul) >> 64);
345
+ auto lo = hash * kMul;
346
+ #endif
347
+ hash = hi ^ lo;
348
+ hash *= kMul;
349
+ tag = ((hash >> 15) & 0x7f) | 0x80;
350
+ hash >>= 22;
351
+ #endif
352
+ } else {
353
+ // F14 uses the bottom bits of the hash to form the index, so for maps
354
+ // with less than 16.7 million entries, it's safe to have a 32-bit hash,
355
+ // and use the bottom 24 bits for the index and leave the top 8 for the
356
+ // tag.
357
+ if (ShouldAssume32BitHash<Hasher>::value) {
358
+ // we don't trust the top bit
359
+ tag = ((hash >> 24) | 0x80) & 0xFF;
360
+ // Explicitly mask off the top 32-bits so that the compiler can
361
+ // optimize away whatever is populating the top 32-bits, which is likely
362
+ // just the lower 32-bits duplicated.
363
+ hash = hash & 0xFFFF'FFFF;
364
+ } else {
365
+ // we don't trust the top bit
366
+ tag = (hash >> 56) | 0x80;
367
+ }
368
+ }
369
+ return std::make_pair(hash, tag);
370
+ }
371
+ #else
372
+ // 32-bit
373
+ template <typename Hasher, typename Key>
374
+ std::pair<std::size_t, std::size_t> splitHashImpl(std::size_t hash) {
375
+ static_assert(sizeof(std::size_t) == sizeof(uint32_t), "");
376
+ uint8_t tag;
377
+ if (!IsAvalanchingHasher<Hasher, Key>::value) {
378
+ #if FOLLY_F14_CRC_INTRINSIC_AVAILABLE
379
+ #if FOLLY_SSE_PREREQ(4, 2)
380
+ // SSE4.2 CRC
381
+ auto c = _mm_crc32_u32(0, hash);
382
+ tag = static_cast<uint8_t>(~(c >> 25));
383
+ hash += c;
384
+ #else
385
+ auto c = __crc32cw(0, hash);
386
+ tag = static_cast<uint8_t>(~(c >> 25));
387
+ hash += c;
388
+ #endif
389
+ #else
390
+ // finalizer for 32-bit murmur2
391
+ hash ^= hash >> 13;
392
+ hash *= 0x5bd1e995;
393
+ hash ^= hash >> 15;
394
+ tag = static_cast<uint8_t>(~(hash >> 25));
395
+ #endif
396
+ } else {
397
+ // we don't trust the top bit
398
+ tag = (hash >> 24) | 0x80;
399
+ }
400
+ return std::make_pair(hash, tag);
401
+ }
402
+ #endif
403
+ #endif
404
+ } // namespace detail
405
+ } // namespace f14
406
+
407
+ template <typename TKeyType, typename Hasher = f14::DefaultHasher<TKeyType>>
408
+ class F14HashedKey final {
409
+ public:
410
+ #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
411
+ template <typename... Args>
412
+ explicit F14HashedKey(Args&&... args)
413
+ : key_(std::forward<Args>(args)...),
414
+ hash_(f14::detail::splitHashImpl<Hasher, TKeyType>(Hasher{}(key_))) {}
415
+ #else
416
+ F14HashedKey() = delete;
417
+ #endif
418
+
419
+ const TKeyType& getKey() const { return key_; }
420
+ const F14HashToken& getHashToken() const { return hash_; }
421
+ // We want the conversion to the key to be implicit - the hashed key should
422
+ // seamlessly behave as the key itself.
423
+ /* implicit */ operator const TKeyType&() const { return key_; }
424
+ explicit operator const F14HashToken&() const { return hash_; }
425
+
426
+ bool operator==(const F14HashedKey& other) const {
427
+ return key_ == other.key_;
428
+ }
429
+ bool operator==(const TKeyType& other) const { return key_ == other; }
430
+
431
+ private:
432
+ TKeyType key_;
433
+ F14HashToken hash_;
434
+ };
435
+
436
+ #if FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
437
+ namespace f14 {
438
+ namespace detail {
439
+
440
+ //// Defaults should be selected using void
441
+ template <typename Arg, typename Default>
442
+ using VoidDefault =
443
+ std::conditional_t<std::is_same<Arg, Default>::value, void, Arg>;
444
+
445
+ template <typename Arg, typename Default>
446
+ using Defaulted =
447
+ std::conditional_t<std::is_same<Arg, void>::value, Default, Arg>;
448
+
449
+ ////////////////
450
+
451
+ /// Prefetch the first cache line of the object at ptr.
452
+ template <typename T>
453
+ FOLLY_ALWAYS_INLINE static void prefetchAddr(T const* ptr) {
454
+ #ifndef _WIN32
455
+ __builtin_prefetch(static_cast<void const*>(ptr));
456
+ #elif FOLLY_NEON
457
+ __prefetch(static_cast<void const*>(ptr));
458
+ #elif FOLLY_SSE >= 2
459
+ _mm_prefetch(
460
+ static_cast<char const*>(static_cast<void const*>(ptr)), _MM_HINT_T0);
461
+ #endif
462
+ }
463
+
464
+ #if FOLLY_NEON
465
+ using TagVector = uint8x16_t;
466
+ #elif FOLLY_SSE >= 2
467
+ using TagVector = __m128i;
468
+ #elif FOLLY_HAVE_INT128_T
469
+ using TagVector = __uint128_t;
470
+ #endif
471
+
472
+ // We could use unaligned loads to relax this requirement, but that
473
+ // would be both a performance penalty and require a bulkier packed
474
+ // ItemIter format
475
+ constexpr std::size_t kRequiredVectorAlignment =
476
+ constexpr_max(std::size_t{16}, alignof(max_align_t));
477
+
478
+ struct alignas(kRequiredVectorAlignment) F14EmptyTagVector {
479
+ std::array<uint8_t, 15> bytes_{};
480
+ uint8_t marker_{255}; // coincides with outboundOverflowCount_
481
+ };
482
+
483
+ FOLLY_EXPORT inline F14EmptyTagVector& getF14EmptyTagVector() noexcept {
484
+ static constexpr F14EmptyTagVector instance;
485
+ auto const raw = reinterpret_cast<uintptr_t>(&instance);
486
+ FOLLY_SAFE_DCHECK(
487
+ (raw % kRequiredVectorAlignment) == 0,
488
+ raw,
489
+ " not aligned to ",
490
+ kRequiredVectorAlignment);
491
+ return const_cast<F14EmptyTagVector&>(instance);
492
+ }
493
+
494
+ template <typename ItemType>
495
+ struct alignas(kRequiredVectorAlignment) F14Chunk {
496
+ using Item = ItemType;
497
+
498
+ // For our 16 byte vector alignment (and assuming alignof(Item) >=
499
+ // 4) kCapacity of 14 is the most space efficient. Slightly smaller
500
+ // or larger capacities can help with cache alignment in a couple of
501
+ // cases without wasting too much space, but once the items are larger
502
+ // then we're unlikely to get much benefit anyway. The only case we
503
+ // optimize is using kCapacity of 12 for 4 byte items, which makes the
504
+ // chunk take exactly 1 cache line, and adding 16 bytes of padding for
505
+ // 16 byte items so that a chunk takes exactly 4 cache lines.
506
+ static constexpr unsigned kCapacity = sizeof(Item) == 4 ? 12 : 14;
507
+
508
+ static constexpr unsigned kDesiredCapacity = kCapacity - 2;
509
+
510
+ static constexpr unsigned kAllocatedCapacity =
511
+ kCapacity + (sizeof(Item) == 16 ? 1 : 0);
512
+
513
+ // If kCapacity == 12 then we get 16 bits of capacityScale by using
514
+ // tag 12 and 13, otherwise we only get 4 bits of control_
515
+ static constexpr std::size_t kCapacityScaleBits = kCapacity == 12 ? 16 : 4;
516
+ static constexpr std::size_t kCapacityScaleShift = kCapacityScaleBits - 4;
517
+
518
+ static constexpr MaskType kFullMask = FullMask<kCapacity>::value;
519
+
520
+ static constexpr std::uint8_t kOutboundOverflowMax = 254;
521
+ static constexpr std::uint8_t kOutboundOverflowEmpty = 255;
522
+
523
+ // Non-empty tags have their top bit set. tags_ array might be bigger
524
+ // than kCapacity to keep alignment of first item.
525
+ std::array<uint8_t, 14> tags_;
526
+
527
+ // Bits 0..3 of chunk 0 record the scaling factor between the number of
528
+ // chunks and the max size without rehash. Bits 4-7 in any chunk are a
529
+ // 4-bit counter of the number of values in this chunk that were placed
530
+ // because they overflowed their desired chunk (hostedOverflowCount).
531
+ uint8_t control_;
532
+
533
+ // The number of values that would have been placed into this chunk if
534
+ // there had been space, including values that also overflowed previous
535
+ // full chunks. This value saturates; once it becomes 254 it no longer
536
+ // increases nor decreases.
537
+ uint8_t outboundOverflowCount_;
538
+
539
+ std::array<aligned_storage_for_t<Item>, kAllocatedCapacity> rawItems_;
540
+
541
+ FOLLY_EXPORT static F14Chunk* getSomeEmptyInstance() noexcept {
542
+ return reinterpret_cast<F14Chunk*>(&getF14EmptyTagVector());
543
+ }
544
+
545
+ static bool isEmptyInstance(F14Chunk const* const chunk) noexcept {
546
+ auto const empty = reinterpret_cast<F14EmptyTagVector const*>(chunk);
547
+ return empty->marker_ == kOutboundOverflowEmpty;
548
+ }
549
+
550
+ void clear() {
551
+ // tags_ = {}; control_ = 0; outboundOverflowCount_ = 0;
552
+
553
+ // gcc < 6 doesn't exploit chunk alignment to generate the optimal
554
+ // SSE clear from memset. This is very hot code, so it is worth
555
+ // handling that case specially.
556
+ std::memset(&tags_[0], '\0', 16);
557
+ }
558
+
559
+ void copyOverflowInfoFrom(F14Chunk const& rhs) {
560
+ FOLLY_SAFE_DCHECK(!isEmptyInstance(&rhs));
561
+ FOLLY_SAFE_DCHECK(hostedOverflowCount() == 0, "");
562
+ control_ += static_cast<uint8_t>(rhs.control_ & 0xf0);
563
+ outboundOverflowCount_ = rhs.outboundOverflowCount_;
564
+ }
565
+
566
+ unsigned hostedOverflowCount() const { return control_ >> 4; }
567
+
568
+ static constexpr uint8_t kIncrHostedOverflowCount = 0x10;
569
+ static constexpr uint8_t kDecrHostedOverflowCount =
570
+ static_cast<uint8_t>(-0x10);
571
+
572
+ void adjustHostedOverflowCount(uint8_t op) { control_ += op; }
573
+
574
+ bool eof() const { return capacityScale(this) != 0; }
575
+
576
+ static std::size_t capacityScale(F14Chunk const* const chunk) {
577
+ auto const empty = reinterpret_cast<F14EmptyTagVector const*>(chunk);
578
+ if constexpr (kCapacityScaleBits == 4) {
579
+ return empty->bytes_[offsetof(F14Chunk, control_)] & 0xf;
580
+ } else {
581
+ uint16_t v;
582
+ std::memcpy(&v, &empty->bytes_[12], 2);
583
+ return v;
584
+ }
585
+ }
586
+
587
+ void setCapacityScale(std::size_t scale) {
588
+ FOLLY_SAFE_DCHECK(
589
+ !isEmptyInstance(this) && scale > 0 &&
590
+ scale < (std::size_t{1} << kCapacityScaleBits),
591
+ "");
592
+ if constexpr (kCapacityScaleBits == 4) {
593
+ control_ = static_cast<uint8_t>((control_ & ~0xf) | scale);
594
+ } else {
595
+ uint16_t v = static_cast<uint16_t>(scale);
596
+ std::memcpy(&tags_[12], &v, 2);
597
+ }
598
+ }
599
+
600
+ void markEof(std::size_t scale) {
601
+ folly::assume(control_ == 0);
602
+ setCapacityScale(scale);
603
+ }
604
+
605
+ unsigned outboundOverflowCount() const { return outboundOverflowCount_; }
606
+
607
+ void incrOutboundOverflowCount() {
608
+ if (outboundOverflowCount_ != kOutboundOverflowMax) {
609
+ ++outboundOverflowCount_;
610
+ }
611
+ }
612
+
613
+ void decrOutboundOverflowCount() {
614
+ FOLLY_SAFE_DCHECK(outboundOverflowCount_ != 0);
615
+ if (outboundOverflowCount_ != kOutboundOverflowMax) {
616
+ --outboundOverflowCount_;
617
+ }
618
+ }
619
+
620
+ std::size_t tag(std::size_t index) const { return tags_[index]; }
621
+
622
+ void setTag(std::size_t index, std::size_t tag) {
623
+ FOLLY_SAFE_DCHECK(!isEmptyInstance(this) && tag >= 0x80 && tag <= 0xff, "");
624
+ FOLLY_SAFE_CHECK(tags_[index] == 0, "");
625
+ tags_[index] = static_cast<uint8_t>(tag);
626
+ }
627
+
628
+ void clearTag(std::size_t index) {
629
+ FOLLY_SAFE_CHECK((tags_[index] & 0x80) != 0, "");
630
+ tags_[index] = 0;
631
+ }
632
+
633
+ #if FOLLY_NEON
634
+ ////////
635
+ // Tag filtering using NEON intrinsics
636
+
637
+ SparseMaskIter tagMatchIter(std::size_t needle) const {
638
+ FOLLY_SAFE_DCHECK(needle >= 0x80 && needle < 0x100, "");
639
+ uint8x16_t tagV = vld1q_u8(&tags_[0]);
640
+ auto needleV = vdupq_n_u8(static_cast<uint8_t>(needle));
641
+ auto eqV = vceqq_u8(tagV, needleV);
642
+ // get info from every byte into the bottom half of every uint16_t
643
+ // by shifting right 4, then round to get it into a 64-bit vector
644
+ uint8x8_t maskV = vshrn_n_u16(vreinterpretq_u16_u8(eqV), 4);
645
+ uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(maskV), 0) & kFullMask;
646
+ return SparseMaskIter(mask);
647
+ }
648
+
649
+ MaskType occupiedMask() const {
650
+ uint8x16_t tagV = vld1q_u8(&tags_[0]);
651
+ // signed shift extends top bit to all bits
652
+ auto occupiedV =
653
+ vreinterpretq_u8_s8(vshrq_n_s8(vreinterpretq_s8_u8(tagV), 7));
654
+ uint8x8_t maskV = vshrn_n_u16(vreinterpretq_u16_u8(occupiedV), 4);
655
+ return vget_lane_u64(vreinterpret_u64_u8(maskV), 0) & kFullMask;
656
+ }
657
+ #elif FOLLY_SSE >= 2
658
+ ////////
659
+ // Tag filtering using SSE2 intrinsics
660
+
661
+ TagVector const* tagVector() const {
662
+ return static_cast<TagVector const*>(static_cast<void const*>(&tags_[0]));
663
+ }
664
+
665
+ SparseMaskIter tagMatchIter(std::size_t needle) const {
666
+ FOLLY_SAFE_DCHECK(needle >= 0x80 && needle < 0x100, "");
667
+ auto tagV = _mm_load_si128(tagVector());
668
+
669
+ // TRICKY! It may seem strange to have a std::size_t needle and narrow
670
+ // it at the last moment, rather than making HashPair::second be a
671
+ // uint8_t, but the latter choice sometimes leads to a performance
672
+ // problem.
673
+ //
674
+ // On architectures with SSE2 but not AVX2, _mm_set1_epi8 expands
675
+ // to multiple instructions. One of those is a MOVD of either 4 or
676
+ // 8 byte width. Only the bottom byte of that move actually affects
677
+ // the result, but if a 1-byte needle has been spilled then this will
678
+ // be a 4 byte load. GCC 5.5 has been observed to reload needle
679
+ // (or perhaps fuse a reload and part of a previous static_cast)
680
+ // needle using a MOVZX with a 1 byte load in parallel with the MOVD.
681
+ // This combination causes a failure of store-to-load forwarding,
682
+ // which has a big performance penalty (60 nanoseconds per find on
683
+ // a microbenchmark). Keeping needle >= 4 bytes avoids the problem
684
+ // and also happens to result in slightly more compact assembly.
685
+ auto needleV = _mm_set1_epi8(static_cast<uint8_t>(needle));
686
+ auto eqV = _mm_cmpeq_epi8(tagV, needleV);
687
+ auto mask = _mm_movemask_epi8(eqV) & kFullMask;
688
+ return SparseMaskIter{mask};
689
+ }
690
+
691
+ MaskType occupiedMask() const {
692
+ auto tagV = _mm_load_si128(tagVector());
693
+ return _mm_movemask_epi8(tagV) & kFullMask;
694
+ }
695
+ #elif FOLLY_HAVE_INT128_T
696
+ ////////
697
+ // Tag filtering using plain C/C++
698
+
699
+ SparseMaskIter tagMatchIter(std::size_t needle) const {
700
+ FOLLY_SAFE_DCHECK(needle >= 0x80 && needle < 0x100, "");
701
+ auto tagV = static_cast<uint8_t const*>(&tags_[0]);
702
+ MaskType mask = 0;
703
+ #if defined(__GNUC__)
704
+ #pragma GCC unroll 16
705
+ #else
706
+ #pragma unroll 16
707
+ #endif
708
+ for (int i = 0; i < kCapacity; i++) {
709
+ mask |= ((tagV[i] == static_cast<uint8_t>(needle)) ? 1 : 0) << i;
710
+ }
711
+ return SparseMaskIter{mask & kFullMask};
712
+ }
713
+
714
+ MaskType occupiedMask() const {
715
+ auto tagV = static_cast<uint8_t const*>(&tags_[0]);
716
+ MaskType mask = 0;
717
+ #if defined(__GNUC__)
718
+ #pragma GCC unroll 16
719
+ #else
720
+ #pragma unroll 16
721
+ #endif
722
+ for (int i = 0; i < kCapacity; i++) {
723
+ mask |= ((tagV[i] & 0x80) ? 1 : 0) << i;
724
+ }
725
+ return mask & kFullMask;
726
+ }
727
+ #endif
728
+
729
+ DenseMaskIter occupiedIter() const {
730
+ return DenseMaskIter{&tags_[0], occupiedMask()};
731
+ }
732
+
733
+ MaskRangeIter occupiedRangeIter() const {
734
+ return MaskRangeIter{occupiedMask()};
735
+ }
736
+
737
+ LastOccupiedInMask lastOccupied() const {
738
+ return LastOccupiedInMask{occupiedMask()};
739
+ }
740
+
741
+ FirstEmptyInMask firstEmpty() const {
742
+ return FirstEmptyInMask{occupiedMask() ^ kFullMask};
743
+ }
744
+
745
+ bool occupied(std::size_t index) const {
746
+ FOLLY_SAFE_DCHECK(tags_[index] == 0 || (tags_[index] & 0x80) != 0, "");
747
+ return tags_[index] != 0;
748
+ }
749
+
750
+ Item* itemAddr(std::size_t i) const {
751
+ return static_cast<Item*>(
752
+ const_cast<void*>(static_cast<void const*>(&rawItems_[i])));
753
+ }
754
+
755
+ Item& item(std::size_t i) {
756
+ FOLLY_SAFE_DCHECK(this->occupied(i), "");
757
+ return *std::launder(itemAddr(i));
758
+ }
759
+
760
+ Item const& citem(std::size_t i) const {
761
+ FOLLY_SAFE_DCHECK(this->occupied(i), "");
762
+ return *std::launder(itemAddr(i));
763
+ }
764
+
765
+ static F14Chunk& owner(Item& item, std::size_t index) {
766
+ auto rawAddr =
767
+ static_cast<uint8_t*>(static_cast<void*>(std::addressof(item))) -
768
+ offsetof(F14Chunk, rawItems_) - index * sizeof(Item);
769
+ auto chunkAddr = static_cast<F14Chunk*>(static_cast<void*>(rawAddr));
770
+ FOLLY_SAFE_DCHECK(std::addressof(item) == chunkAddr->itemAddr(index), "");
771
+ return *chunkAddr;
772
+ }
773
+ };
774
+
775
+ ////////////////
776
+
777
+ // PackedChunkItemPtr points to an Item in an F14Chunk, allowing both the
778
+ // Item& and its index to be recovered. It sorts by the address of the
779
+ // item, and it only works for items that are in a properly-aligned chunk.
780
+
781
+ // generic form, not actually packed
782
+ template <typename Ptr>
783
+ class PackedChunkItemPtr {
784
+ public:
785
+ PackedChunkItemPtr(Ptr p, std::size_t i) noexcept : ptr_{p}, index_{i} {
786
+ FOLLY_SAFE_DCHECK(ptr_ != nullptr || index_ == 0, "");
787
+ }
788
+
789
+ Ptr ptr() const { return ptr_; }
790
+
791
+ std::size_t index() const { return index_; }
792
+
793
+ bool operator<(PackedChunkItemPtr const& rhs) const {
794
+ FOLLY_SAFE_DCHECK(ptr_ != rhs.ptr_ || index_ == rhs.index_, "");
795
+ return ptr_ < rhs.ptr_;
796
+ }
797
+
798
+ bool operator==(PackedChunkItemPtr const& rhs) const {
799
+ FOLLY_SAFE_DCHECK(ptr_ != rhs.ptr_ || index_ == rhs.index_, "");
800
+ return ptr_ == rhs.ptr_;
801
+ }
802
+
803
+ bool operator!=(PackedChunkItemPtr const& rhs) const {
804
+ return !(*this == rhs);
805
+ }
806
+
807
+ private:
808
+ Ptr ptr_;
809
+ std::size_t index_;
810
+ };
811
+
812
+ // Bare pointer form, packed into a uintptr_t. Uses only bits wasted by
813
+ // alignment, so it works on 32-bit and 64-bit platforms
814
+ template <typename T>
815
+ class PackedChunkItemPtr<T*> {
816
+ static_assert((alignof(F14Chunk<T>) % 16) == 0, "");
817
+
818
+ // Chunks are 16-byte aligned, so we can maintain a packed pointer to a
819
+ // chunk item by packing the 4-bit item index into the least significant
820
+ // bits of a pointer to the chunk itself. This makes ItemIter::pack
821
+ // more expensive, however, since it has to compute the chunk address.
822
+ //
823
+ // Chunk items have varying alignment constraints, so it would seem
824
+ // to be that we can't do a similar trick while using only bit masking
825
+ // operations on the Item* itself. It happens to be, however, that if
826
+ // sizeof(Item) is not a multiple of 16 then we can recover a portion
827
+ // of the index bits from the knowledge that the Item-s are stored in
828
+ // an array that is itself 16-byte aligned.
829
+ //
830
+ // If kAlignBits is the number of trailing zero bits in sizeof(Item)
831
+ // (up to 4), then we can borrow those bits to store kAlignBits of the
832
+ // index directly. We can recover (4 - kAlignBits) bits of the index
833
+ // from the item pointer itself, by defining/observing that
834
+ //
835
+ // A = kAlignBits (A <= 4)
836
+ //
837
+ // S = (sizeof(Item) % 16) >> A (shifted-away bits are all zero)
838
+ //
839
+ // R = (itemPtr % 16) >> A (shifted-away bits are all zero)
840
+ //
841
+ // M = 16 >> A
842
+ //
843
+ // itemPtr % 16 = (index * sizeof(Item)) % 16
844
+ //
845
+ // (R * 2^A) % 16 = (index * (sizeof(Item) % 16)) % 16
846
+ //
847
+ // (R * 2^A) % 16 = (index * 2^A * S) % 16
848
+ //
849
+ // R % M = (index * S) % M
850
+ //
851
+ // S is relatively prime with M, so a multiplicative inverse is easy
852
+ // to compute
853
+ //
854
+ // Sinv = S^(M - 1) % M
855
+ //
856
+ // (R * Sinv) % M = index % M
857
+ //
858
+ // This lets us recover the bottom bits of the index. When sizeof(T)
859
+ // is 8-byte aligned kSizeInverse will always be 1. When sizeof(T)
860
+ // is 4-byte aligned kSizeInverse will be either 1 or 3.
861
+
862
+ // returns pow(x, y) % m
863
+ static constexpr uintptr_t powerMod(uintptr_t x, uintptr_t y, uintptr_t m) {
864
+ return y == 0 ? 1 : (x * powerMod(x, y - 1, m)) % m;
865
+ }
866
+
867
+ static constexpr uintptr_t kIndexBits = 4;
868
+ static constexpr uintptr_t kIndexMask = (uintptr_t{1} << kIndexBits) - 1;
869
+
870
+ static constexpr uintptr_t kAlignBits = constexpr_min(
871
+ uintptr_t{4}, constexpr_find_first_set(uintptr_t{sizeof(T)}) - 1);
872
+
873
+ static constexpr uintptr_t kAlignMask = (uintptr_t{1} << kAlignBits) - 1;
874
+
875
+ static constexpr uintptr_t kModulus = uintptr_t{1}
876
+ << (kIndexBits - kAlignBits);
877
+ static constexpr uintptr_t kSizeInverse =
878
+ powerMod(sizeof(T) >> kAlignBits, kModulus - 1, kModulus);
879
+
880
+ public:
881
+ PackedChunkItemPtr(T* p, std::size_t i) noexcept {
882
+ uintptr_t encoded = i >> (kIndexBits - kAlignBits);
883
+ assume((encoded & ~kAlignMask) == 0);
884
+ raw_ = reinterpret_cast<uintptr_t>(p) | encoded;
885
+ FOLLY_SAFE_DCHECK(p == ptr(), "");
886
+ FOLLY_SAFE_DCHECK(i == index(), "");
887
+ }
888
+
889
+ T* ptr() const { return reinterpret_cast<T*>(raw_ & ~kAlignMask); }
890
+
891
+ std::size_t index() const {
892
+ auto encoded = (raw_ & kAlignMask) << (kIndexBits - kAlignBits);
893
+ auto deduced =
894
+ ((raw_ >> kAlignBits) * kSizeInverse) & (kIndexMask >> kAlignBits);
895
+ return encoded | deduced;
896
+ }
897
+
898
+ bool operator<(PackedChunkItemPtr const& rhs) const {
899
+ return raw_ < rhs.raw_;
900
+ }
901
+ bool operator==(PackedChunkItemPtr const& rhs) const {
902
+ return raw_ == rhs.raw_;
903
+ }
904
+ bool operator!=(PackedChunkItemPtr const& rhs) const {
905
+ return !(*this == rhs);
906
+ }
907
+
908
+ private:
909
+ uintptr_t raw_;
910
+ };
911
+
912
+ template <typename ChunkPtr>
913
+ class F14ItemIter {
914
+ private:
915
+ using Chunk = typename std::pointer_traits<ChunkPtr>::element_type;
916
+
917
+ public:
918
+ using Item = typename Chunk::Item;
919
+ using ItemPtr = typename std::pointer_traits<ChunkPtr>::template rebind<Item>;
920
+ using ItemConstPtr =
921
+ typename std::pointer_traits<ChunkPtr>::template rebind<Item const>;
922
+
923
+ using Packed = PackedChunkItemPtr<ItemPtr>;
924
+
925
+ //// PUBLIC
926
+
927
+ F14ItemIter() noexcept : itemPtr_{nullptr}, index_{0} {}
928
+
929
+ // default copy and move constructors and assignment operators are correct
930
+
931
+ explicit F14ItemIter(Packed const& packed)
932
+ : itemPtr_{packed.ptr()}, index_{packed.index()} {}
933
+
934
+ F14ItemIter(ChunkPtr chunk, std::size_t index)
935
+ : itemPtr_{std::pointer_traits<ItemPtr>::pointer_to(chunk->item(index))},
936
+ index_{index} {
937
+ FOLLY_SAFE_DCHECK(index < Chunk::kCapacity, "");
938
+ assume(
939
+ std::pointer_traits<ItemPtr>::pointer_to(chunk->item(index)) !=
940
+ nullptr);
941
+ assume(itemPtr_ != nullptr);
942
+ }
943
+
944
+ FOLLY_ALWAYS_INLINE void advanceImpl(bool checkEof, bool likelyDead) {
945
+ auto c = chunk();
946
+
947
+ // common case is packed entries
948
+ while (index_ > 0) {
949
+ --index_;
950
+ --itemPtr_;
951
+ if (FOLLY_LIKELY(c->occupied(index_))) {
952
+ return;
953
+ }
954
+ }
955
+
956
+ // It's fairly common for an iterator to be advanced and then become
957
+ // dead, for example in the return value from erase(iter) or in
958
+ // the last step of a loop. We'd like to make sure that the entire
959
+ // advance() method can be eliminated by the compiler's dead code
960
+ // elimination pass. To do that it must eliminate the loops, which
961
+ // requires it to prove that they have no side effects. It's easy
962
+ // to show that there are no escaping stores, but at the moment
963
+ // compilers also consider an infinite loop to be a side effect.
964
+ // (There are parts of the standard that would allow them to treat
965
+ // this as undefined behavior, but at the moment they don't exploit
966
+ // those clauses.)
967
+ //
968
+ // The following loop should really be a while loop, which would
969
+ // save a register, some instructions, and a conditional branch,
970
+ // but by writing it as a for loop the compiler can prove to itself
971
+ // that it will eventually terminate. (No matter that even if the
972
+ // loop executed in a single cycle it would take about 200 years to
973
+ // run all 2^64 iterations.)
974
+ //
975
+ // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=82776 has the bug we
976
+ // filed about the issue. while (true) {
977
+ for (std::size_t i = 1; !likelyDead || i != 0; ++i) {
978
+ if (checkEof) {
979
+ // exhausted the current chunk
980
+ if (FOLLY_UNLIKELY(c->eof())) {
981
+ FOLLY_SAFE_DCHECK(index_ == 0, "");
982
+ itemPtr_ = nullptr;
983
+ return;
984
+ }
985
+ } else {
986
+ FOLLY_SAFE_DCHECK(!c->eof(), "");
987
+ }
988
+ --c;
989
+ auto last = c->lastOccupied();
990
+ if (checkEof && !likelyDead) {
991
+ prefetchAddr(&*c - 1);
992
+ }
993
+ if (FOLLY_LIKELY(last.hasIndex())) {
994
+ index_ = last.index();
995
+ itemPtr_ = std::pointer_traits<ItemPtr>::pointer_to(c->item(index_));
996
+ return;
997
+ }
998
+ }
999
+ }
1000
+
1001
+ void precheckedAdvance() { advanceImpl(false, false); }
1002
+
1003
+ FOLLY_ALWAYS_INLINE void advance() { advanceImpl(true, false); }
1004
+
1005
+ FOLLY_ALWAYS_INLINE void advanceLikelyDead() { advanceImpl(true, true); }
1006
+
1007
+ ChunkPtr chunk() const {
1008
+ return std::pointer_traits<ChunkPtr>::pointer_to(
1009
+ Chunk::owner(*itemPtr_, index_));
1010
+ }
1011
+
1012
+ std::size_t index() const { return index_; }
1013
+
1014
+ Item* itemAddr() const { return std::addressof(*itemPtr_); }
1015
+ Item& item() const { return *itemPtr_; }
1016
+ Item const& citem() const { return *itemPtr_; }
1017
+
1018
+ bool atEnd() const { return itemPtr_ == nullptr; }
1019
+
1020
+ Packed pack() const { return Packed{itemPtr_, static_cast<uint8_t>(index_)}; }
1021
+
1022
+ bool operator==(F14ItemIter const& rhs) const {
1023
+ // this form makes iter == end() into a single null check after inlining
1024
+ // and constant propagation
1025
+ return itemPtr_ == rhs.itemPtr_;
1026
+ }
1027
+
1028
+ bool operator!=(F14ItemIter const& rhs) const { return !(*this == rhs); }
1029
+
1030
+ private:
1031
+ ItemPtr itemPtr_;
1032
+ std::size_t index_;
1033
+ };
1034
+
1035
+ ////////////////
1036
+
1037
+ struct PackedSizeAndChunkShift {
1038
+ private:
1039
+ // F14Table's chunk count is a power of 2 that is at least 1 and at
1040
+ // most 1 << 63. In order to encode it efficiently, we store its base 2
1041
+ // logarithm `n`, so that (1UL << n) is the chunkCount. Despite
1042
+ // needing only 6 bits to encode the shift, we reserve 8 bits to
1043
+ // avoid extra masking, leaving 56 bits for the size, which is
1044
+ // plenty.
1045
+
1046
+ // We use the least significant bits of
1047
+ // packedSizeAndChunkShift_ for the shift so that size access
1048
+ // is just a single shift and shift access is a normal 8-bit load.
1049
+ static constexpr uint32_t kSizeShift = 8;
1050
+ static constexpr uint32_t kChunkCountShiftMask = (1 << kSizeShift) - 1;
1051
+ uint64_t packedSizeAndChunkShift_{0};
1052
+
1053
+ public:
1054
+ // subtract 1 because we can't represent 1 << 64, triggering UBSAN.
1055
+ static constexpr uint8_t kMaxSupportedChunkShift =
1056
+ std::numeric_limits<uint64_t>::digits - 1;
1057
+
1058
+ static constexpr std::size_t kMaxSize =
1059
+ (size_t(1) << (std::numeric_limits<std::size_t>::digits - kSizeShift)) -
1060
+ 1;
1061
+
1062
+ uint64_t size() const noexcept {
1063
+ return packedSizeAndChunkShift_ >> kSizeShift;
1064
+ }
1065
+
1066
+ uint8_t chunkShift() const noexcept {
1067
+ return packedSizeAndChunkShift_ & kChunkCountShiftMask;
1068
+ }
1069
+
1070
+ std::size_t chunkCount() const noexcept {
1071
+ const auto chunkCountShift = chunkShift();
1072
+ return std::size_t(1) << chunkCountShift;
1073
+ }
1074
+
1075
+ void setSize(std::size_t sz) noexcept {
1076
+ packedSizeAndChunkShift_ =
1077
+ chunkShift() | (static_cast<uint64_t>(sz) << kSizeShift);
1078
+ }
1079
+
1080
+ void setChunkCount(std::size_t newCount) {
1081
+ FOLLY_SAFE_DCHECK(
1082
+ folly::isPowTwo(newCount), newCount); // note that this forbids 0!
1083
+ const auto shift = findFirstSet(newCount) - 1; // firstSet is 1-based.
1084
+ packedSizeAndChunkShift_ =
1085
+ (static_cast<uint64_t>(size()) << kSizeShift) | shift;
1086
+ FOLLY_SAFE_DCHECK(chunkCount() == newCount, "");
1087
+ }
1088
+
1089
+ void swap(PackedSizeAndChunkShift& rhs) noexcept {
1090
+ std::swap(packedSizeAndChunkShift_, rhs.packedSizeAndChunkShift_);
1091
+ }
1092
+ };
1093
+
1094
+ struct UnpackedSizeAndChunkShift {
1095
+ private:
1096
+ // Simple implementation for 32-bit systems: just use two words.
1097
+ std::size_t size_ = 0;
1098
+ uint8_t chunkShift_ = 0;
1099
+
1100
+ public:
1101
+ // subtract 1 because we can't represent 1 << 32, triggering UBSAN.
1102
+ static constexpr uint8_t kMaxSupportedChunkShift =
1103
+ std::numeric_limits<std::size_t>::digits - 1;
1104
+
1105
+ static constexpr std::size_t kMaxSize =
1106
+ std::numeric_limits<std::size_t>::max();
1107
+
1108
+ uint64_t size() const noexcept { return size_; }
1109
+
1110
+ uint8_t chunkShift() const noexcept { return chunkShift_; }
1111
+
1112
+ std::size_t chunkCount() const noexcept {
1113
+ const auto chunkCountShift = chunkShift();
1114
+ return std::size_t(1) << chunkCountShift;
1115
+ }
1116
+
1117
+ void setSize(std::size_t sz) noexcept { size_ = sz; }
1118
+
1119
+ void setChunkCount(std::size_t newCount) {
1120
+ FOLLY_SAFE_DCHECK(
1121
+ folly::isPowTwo(newCount), newCount); // note that this forbids 0!
1122
+ const auto shift = findFirstSet(newCount) - 1; // firstSet is 1-based.
1123
+ FOLLY_SAFE_DCHECK(shift <= std::numeric_limits<uint8_t>::max(), "");
1124
+ chunkShift_ = static_cast<uint8_t>(shift);
1125
+ FOLLY_SAFE_DCHECK(chunkCount() == newCount, "");
1126
+ }
1127
+
1128
+ void swap(UnpackedSizeAndChunkShift& rhs) noexcept {
1129
+ std::swap(size_, rhs.size_);
1130
+ std::swap(chunkShift_, rhs.chunkShift_);
1131
+ }
1132
+ };
1133
+
1134
+ using SizeAndChunkShift = std::conditional_t<
1135
+ sizeof(uint64_t) == sizeof(std::size_t),
1136
+ PackedSizeAndChunkShift,
1137
+ UnpackedSizeAndChunkShift>;
1138
+
1139
+ template <typename ItemIter, bool EnablePackedItemIter>
1140
+ struct SizeAndChunkShiftAndPackedBegin {
1141
+ private:
1142
+ SizeAndChunkShift sizeAndChunkShift_;
1143
+
1144
+ typename ItemIter::Packed packedBegin_{ItemIter{}.pack()};
1145
+
1146
+ public:
1147
+ auto size() const { return sizeAndChunkShift_.size(); }
1148
+
1149
+ auto chunkShift() const { return sizeAndChunkShift_.chunkShift(); }
1150
+
1151
+ auto chunkCount() const { return sizeAndChunkShift_.chunkCount(); }
1152
+
1153
+ void setSize(uint64_t sz) { sizeAndChunkShift_.setSize(sz); }
1154
+
1155
+ void incrementSize() { sizeAndChunkShift_.setSize(size() + 1); }
1156
+
1157
+ void decrementSize() { sizeAndChunkShift_.setSize(size() - 1); }
1158
+
1159
+ void setChunkCount(std::size_t count) {
1160
+ sizeAndChunkShift_.setChunkCount(count);
1161
+ }
1162
+
1163
+ typename ItemIter::Packed& packedBegin() { return packedBegin_; }
1164
+
1165
+ typename ItemIter::Packed const& packedBegin() const { return packedBegin_; }
1166
+
1167
+ void swap(SizeAndChunkShiftAndPackedBegin& rhs) noexcept {
1168
+ sizeAndChunkShift_.swap(rhs.sizeAndChunkShift_);
1169
+ std::swap(packedBegin_, rhs.packedBegin_);
1170
+ }
1171
+ };
1172
+
1173
+ template <typename ItemIter>
1174
+ struct SizeAndChunkShiftAndPackedBegin<ItemIter, false> {
1175
+ private:
1176
+ SizeAndChunkShift sizeAndChunkShift_;
1177
+
1178
+ public:
1179
+ auto size() const { return sizeAndChunkShift_.size(); }
1180
+
1181
+ auto chunkShift() const { return sizeAndChunkShift_.chunkShift(); }
1182
+
1183
+ auto chunkCount() const { return sizeAndChunkShift_.chunkCount(); }
1184
+
1185
+ void setSize(uint64_t sz) { sizeAndChunkShift_.setSize(sz); }
1186
+
1187
+ void incrementSize() { sizeAndChunkShift_.setSize(size() + 1); }
1188
+
1189
+ void decrementSize() { sizeAndChunkShift_.setSize(size() - 1); }
1190
+
1191
+ void setChunkCount(std::size_t count) {
1192
+ sizeAndChunkShift_.setChunkCount(count);
1193
+ }
1194
+
1195
+ [[noreturn]] typename ItemIter::Packed& packedBegin() {
1196
+ assume_unreachable();
1197
+ }
1198
+
1199
+ [[noreturn]] typename ItemIter::Packed const& packedBegin() const {
1200
+ assume_unreachable();
1201
+ }
1202
+ };
1203
+
1204
+ template <typename Policy>
1205
+ class F14Table : public Policy {
1206
+ public:
1207
+ using Item = typename Policy::Item;
1208
+
1209
+ using value_type = typename Policy::Value;
1210
+ using allocator_type = typename Policy::Alloc;
1211
+
1212
+ private:
1213
+ using Alloc = typename Policy::Alloc;
1214
+ using AllocTraits = typename Policy::AllocTraits;
1215
+ using Hasher = typename Policy::Hasher;
1216
+ using InternalSizeType = typename Policy::InternalSizeType;
1217
+ using KeyEqual = typename Policy::KeyEqual;
1218
+
1219
+ using Policy::kAllocIsAlwaysEqual;
1220
+ using Policy::kContinuousCapacity;
1221
+ using Policy::kDefaultConstructIsNoexcept;
1222
+ using Policy::kEnableItemIteration;
1223
+ using Policy::kSwapIsNoexcept;
1224
+
1225
+ using Policy::destroyItemOnClear;
1226
+ using Policy::isAvalanchingHasher;
1227
+ using Policy::prefetchBeforeCopy;
1228
+ using Policy::prefetchBeforeDestroy;
1229
+ using Policy::prefetchBeforeRehash;
1230
+ using Policy::shouldAssume32BitHash;
1231
+
1232
+ using ByteAlloc = typename AllocTraits::template rebind_alloc<uint8_t>;
1233
+ using BytePtr = typename std::allocator_traits<ByteAlloc>::pointer;
1234
+
1235
+ using Chunk = F14Chunk<Item>;
1236
+ using ChunkPtr =
1237
+ typename std::pointer_traits<BytePtr>::template rebind<Chunk>;
1238
+
1239
+ using HashPair = typename F14HashToken::HashPair;
1240
+
1241
+ public:
1242
+ using ItemIter = F14ItemIter<ChunkPtr>;
1243
+
1244
+ private:
1245
+ //////// begin fields
1246
+
1247
+ ChunkPtr chunks_{Chunk::getSomeEmptyInstance()};
1248
+ SizeAndChunkShiftAndPackedBegin<ItemIter, kEnableItemIteration>
1249
+ sizeAndChunkShiftAndPackedBegin_;
1250
+
1251
+ //////// end fields
1252
+
1253
+ auto chunkShift() const {
1254
+ return sizeAndChunkShiftAndPackedBegin_.chunkShift();
1255
+ }
1256
+
1257
+ auto chunkCount() const {
1258
+ return sizeAndChunkShiftAndPackedBegin_.chunkCount();
1259
+ }
1260
+
1261
+ std::size_t moduloByChunkCount(std::size_t index) const {
1262
+ #ifdef __BMI2__
1263
+ // TODO: remove once the compiler selects BZHI on its own.
1264
+ // see codegen for: codeSize_find_F14value, defined in:
1265
+ // folly/container/test/F14SmallOverheads.cpp
1266
+ return _bzhi_u64(index, chunkShift());
1267
+ #else
1268
+ return index & ((std::size_t(1) << chunkShift()) - 1);
1269
+ #endif
1270
+ }
1271
+
1272
+ void swapContents(F14Table& rhs) noexcept {
1273
+ using std::swap;
1274
+ swap(chunks_, rhs.chunks_);
1275
+ swap(
1276
+ sizeAndChunkShiftAndPackedBegin_, rhs.sizeAndChunkShiftAndPackedBegin_);
1277
+ }
1278
+
1279
+ public:
1280
+ // Equivalent to F14Table(0, ...), but implemented separately to avoid forcing
1281
+ // a reserve() instantiation in the common case.
1282
+ F14Table() noexcept(Policy::kDefaultConstructIsNoexcept)
1283
+ : Policy{Hasher{}, KeyEqual{}, Alloc{}} {}
1284
+
1285
+ F14Table(
1286
+ std::size_t initialCapacity,
1287
+ Hasher const& hasher,
1288
+ KeyEqual const& keyEqual,
1289
+ Alloc const& alloc)
1290
+ : Policy{hasher, keyEqual, alloc} {
1291
+ debugModeOnReserve(initialCapacity);
1292
+ initialReserve(initialCapacity);
1293
+ }
1294
+
1295
+ F14Table(F14Table const& rhs) : Policy{rhs} { buildFromF14Table(rhs); }
1296
+
1297
+ F14Table(F14Table const& rhs, Alloc const& alloc) : Policy{rhs, alloc} {
1298
+ buildFromF14Table(rhs);
1299
+ }
1300
+
1301
+ F14Table(F14Table&& rhs) noexcept(
1302
+ std::is_nothrow_move_constructible<Hasher>::value &&
1303
+ std::is_nothrow_move_constructible<KeyEqual>::value &&
1304
+ std::is_nothrow_move_constructible<Alloc>::value)
1305
+ : Policy{std::move(rhs)} {
1306
+ swapContents(rhs);
1307
+ }
1308
+
1309
+ F14Table(F14Table&& rhs, Alloc const& alloc) noexcept(kAllocIsAlwaysEqual)
1310
+ : Policy{std::move(rhs), alloc} {
1311
+ // if-constexpr allows avoiding dependence on usable Hasher etc.
1312
+ if constexpr (kAllocIsAlwaysEqual) {
1313
+ // move storage (common case)
1314
+ swapContents(rhs);
1315
+ } else if (this->alloc() == rhs.alloc()) {
1316
+ // move storage (common case)
1317
+ swapContents(rhs);
1318
+ } else {
1319
+ // new storage because allocators unequal, move values (rare case)
1320
+ buildFromF14Table(std::move(rhs));
1321
+ }
1322
+ }
1323
+
1324
+ F14Table& operator=(F14Table const& rhs) {
1325
+ if (this != &rhs) {
1326
+ reset();
1327
+ static_cast<Policy&>(*this) = rhs;
1328
+ buildFromF14Table(rhs);
1329
+ }
1330
+ return *this;
1331
+ }
1332
+
1333
+ F14Table& operator=(F14Table&& rhs) noexcept(
1334
+ std::is_nothrow_move_assignable<Hasher>::value &&
1335
+ std::is_nothrow_move_assignable<KeyEqual>::value &&
1336
+ (kAllocIsAlwaysEqual ||
1337
+ (AllocTraits::propagate_on_container_move_assignment::value &&
1338
+ std::is_nothrow_move_assignable<Alloc>::value))) {
1339
+ if (this != &rhs) {
1340
+ reset();
1341
+ static_cast<Policy&>(*this) = std::move(rhs);
1342
+ // if-constexpr allows avoiding dependence on usable Hasher etc.
1343
+ if constexpr (
1344
+ AllocTraits::propagate_on_container_move_assignment::value ||
1345
+ kAllocIsAlwaysEqual) {
1346
+ // move storage (common case)
1347
+ swapContents(rhs);
1348
+ } else if (this->alloc() == rhs.alloc()) {
1349
+ // move storage (common case)
1350
+ swapContents(rhs);
1351
+ } else {
1352
+ // new storage because allocators unequal, move values (rare case)
1353
+ buildFromF14Table(std::move(rhs));
1354
+ }
1355
+ }
1356
+ return *this;
1357
+ }
1358
+
1359
+ ~F14Table() { reset(); }
1360
+
1361
+ void swap(F14Table& rhs) noexcept(kSwapIsNoexcept) {
1362
+ // If propagate_on_container_swap is false and allocators are
1363
+ // not equal, the only way to accomplish a swap would be to do
1364
+ // dynamic allocation and then move (or swap) each contained value.
1365
+ // AllocatorAwareContainer-s are not supposed to attempt this, but
1366
+ // rather are supposed to have undefined behavior in that case.
1367
+ FOLLY_SAFE_CHECK(
1368
+ AllocTraits::propagate_on_container_swap::value ||
1369
+ kAllocIsAlwaysEqual || this->alloc() == rhs.alloc(),
1370
+ "swap is undefined for unequal non-propagating allocators");
1371
+ this->swapPolicy(rhs);
1372
+ swapContents(rhs);
1373
+ }
1374
+
1375
+ private:
1376
+ static HashPair splitHash(std::size_t hash) {
1377
+ return f14::detail::splitHashImpl<Hasher, value_type>(hash);
1378
+ }
1379
+ //////// memory management helpers
1380
+
1381
+ static std::size_t computeCapacity(
1382
+ std::size_t chunkCount, std::size_t scale) {
1383
+ FOLLY_SAFE_DCHECK(!(chunkCount > 1 && scale == 0), "");
1384
+ FOLLY_SAFE_DCHECK(
1385
+ scale < (std::size_t{1} << Chunk::kCapacityScaleBits), "");
1386
+ FOLLY_SAFE_DCHECK((chunkCount & (chunkCount - 1)) == 0, "");
1387
+ return (((chunkCount - 1) >> Chunk::kCapacityScaleShift) + 1) * scale;
1388
+ }
1389
+
1390
+ std::pair<std::size_t, std::size_t> computeChunkCountAndScale(
1391
+ std::size_t desiredCapacity,
1392
+ bool continuousSingleChunkCapacity,
1393
+ bool continuousMultiChunkCapacity) const {
1394
+ if (desiredCapacity <= Chunk::kCapacity) {
1395
+ // we can go to 100% capacity in a single chunk with no problem
1396
+ if (!continuousSingleChunkCapacity) {
1397
+ if (desiredCapacity <= 2) {
1398
+ desiredCapacity = 2;
1399
+ } else if (desiredCapacity <= 6) {
1400
+ desiredCapacity = 6;
1401
+ } else {
1402
+ desiredCapacity = Chunk::kCapacity;
1403
+ }
1404
+ }
1405
+ auto rv = std::make_pair(std::size_t{1}, desiredCapacity);
1406
+ FOLLY_SAFE_DCHECK(
1407
+ computeCapacity(rv.first, rv.second) == desiredCapacity, "");
1408
+ return rv;
1409
+ } else {
1410
+ std::size_t minChunks =
1411
+ (desiredCapacity - 1) / Chunk::kDesiredCapacity + 1;
1412
+ std::size_t chunkPow = findLastSet(minChunks - 1);
1413
+ if (chunkPow == 8 * sizeof(std::size_t)) {
1414
+ throw_exception<std::bad_alloc>();
1415
+ }
1416
+
1417
+ std::size_t chunkCount = std::size_t{1} << chunkPow;
1418
+
1419
+ // Let cc * scale be the actual capacity.
1420
+ // cc = ((chunkCount - 1) >> kCapacityScaleShift) + 1.
1421
+ // If chunkPow >= kCapacityScaleShift, then cc = chunkCount >>
1422
+ // kCapacityScaleShift = 1 << (chunkPow - kCapacityScaleShift),
1423
+ // otherwise it equals 1 = 1 << 0. Let cc = 1 << ss.
1424
+ std::size_t ss = chunkPow >= Chunk::kCapacityScaleShift
1425
+ ? chunkPow - Chunk::kCapacityScaleShift
1426
+ : 0;
1427
+
1428
+ std::size_t scale;
1429
+ if (continuousMultiChunkCapacity) {
1430
+ // (1 << ss) * scale >= desiredCapacity
1431
+ scale = ((desiredCapacity - 1) >> ss) + 1;
1432
+ } else {
1433
+ // (1 << ss) * scale == chunkCount * kDesiredCapacity
1434
+ scale = Chunk::kDesiredCapacity << (chunkPow - ss);
1435
+ }
1436
+
1437
+ std::size_t actualCapacity = computeCapacity(chunkCount, scale);
1438
+ FOLLY_SAFE_DCHECK(actualCapacity >= desiredCapacity, "");
1439
+ if (actualCapacity > max_size()) {
1440
+ throw_exception<std::bad_alloc>();
1441
+ }
1442
+
1443
+ return std::make_pair(chunkCount, scale);
1444
+ }
1445
+ }
1446
+
1447
+ static std::size_t chunkAllocSize(
1448
+ std::size_t chunkCount, std::size_t capacityScale) {
1449
+ FOLLY_SAFE_DCHECK(chunkCount > 0, "");
1450
+ FOLLY_SAFE_DCHECK(!(chunkCount > 1 && capacityScale == 0), "");
1451
+ if (chunkCount == 1) {
1452
+ static_assert(offsetof(Chunk, rawItems_) == 16, "");
1453
+ return 16 + sizeof(Item) * computeCapacity(1, capacityScale);
1454
+ } else {
1455
+ return sizeof(Chunk) * chunkCount;
1456
+ }
1457
+ }
1458
+
1459
+ ChunkPtr initializeChunks(
1460
+ BytePtr raw, std::size_t chunkCount, std::size_t capacityScale) {
1461
+ static_assert(std::is_trivial<Chunk>::value, "F14Chunk should be POD");
1462
+ auto chunks = static_cast<Chunk*>(static_cast<void*>(&*raw));
1463
+ for (std::size_t i = 0; i < chunkCount; ++i) {
1464
+ chunks[i].clear();
1465
+ }
1466
+ chunks[0].markEof(capacityScale);
1467
+ return std::pointer_traits<ChunkPtr>::pointer_to(*chunks);
1468
+ }
1469
+
1470
+ std::size_t itemCount() const noexcept {
1471
+ if (chunkShift() == 0) {
1472
+ return computeCapacity(
1473
+ 1, Chunk::capacityScale(access::to_address(chunks_)));
1474
+ } else {
1475
+ return chunkCount() * Chunk::kCapacity;
1476
+ }
1477
+ }
1478
+
1479
+ public:
1480
+ ItemIter begin() const noexcept {
1481
+ FOLLY_SAFE_DCHECK(kEnableItemIteration, "");
1482
+ return ItemIter{sizeAndChunkShiftAndPackedBegin_.packedBegin()};
1483
+ }
1484
+
1485
+ ItemIter end() const noexcept { return ItemIter{}; }
1486
+
1487
+ bool empty() const noexcept { return size() == 0; }
1488
+
1489
+ auto size() const noexcept { return sizeAndChunkShiftAndPackedBegin_.size(); }
1490
+
1491
+ std::size_t max_size() const noexcept {
1492
+ auto& a = this->alloc();
1493
+ return std::min<std::size_t>(
1494
+ {SizeAndChunkShift::kMaxSize,
1495
+ std::numeric_limits<InternalSizeType>::max(),
1496
+ AllocTraits::max_size(a)});
1497
+ }
1498
+
1499
+ std::size_t bucket_count() const noexcept {
1500
+ return computeCapacity(
1501
+ chunkCount(), Chunk::capacityScale(access::to_address(chunks_)));
1502
+ }
1503
+
1504
+ std::size_t max_bucket_count() const noexcept { return max_size(); }
1505
+
1506
+ float load_factor() const noexcept {
1507
+ return empty()
1508
+ ? 0.0f
1509
+ : static_cast<float>(size()) / static_cast<float>(bucket_count());
1510
+ }
1511
+
1512
+ float max_load_factor() const noexcept { return 1.0f; }
1513
+
1514
+ void max_load_factor(float) noexcept {
1515
+ // Probing hash tables can't run load factors >= 1 (unlike chaining
1516
+ // tables). In addition, we have measured that there is little or
1517
+ // no performance advantage to running a smaller load factor (cache
1518
+ // locality losses outweigh the small reduction in probe lengths,
1519
+ // often making it slower). Therefore, we've decided to just fix
1520
+ // max_load_factor at 1.0f regardless of what the user requests.
1521
+ // This has an additional advantage that we don't have to store it.
1522
+ // Taking alignment into consideration this makes every F14 table
1523
+ // 8 bytes smaller, and is part of the reason an empty F14NodeMap
1524
+ // is almost half the size of an empty std::unordered_map (32 vs
1525
+ // 56 bytes).
1526
+ //
1527
+ // I don't have a strong opinion on whether we should remove this
1528
+ // method or leave a stub, let ngbronson or xshi know if you have a
1529
+ // compelling argument either way.
1530
+ }
1531
+
1532
+ private:
1533
+ // Our probe strategy is to advance through additional chunks with
1534
+ // a stride that is key-specific. This is called double hashing,
1535
+ // and is a well known and high quality probing strategy. So long as
1536
+ // the stride and the chunk count are relatively prime, we will visit
1537
+ // every chunk once and then return to the original chunk, letting us
1538
+ // detect and end the cycle. The chunk count is a power of two, so
1539
+ // we can satisfy the relatively prime part by choosing an odd stride.
1540
+ // We've already computed a high quality secondary hash value for the
1541
+ // tag, so we just use it for the second probe hash as well.
1542
+ //
1543
+ // At the maximum load factor of 12/14, expected probe length for a
1544
+ // find hit is 1.041, with 99% of keys found in the first three chunks.
1545
+ // Expected probe length for a find miss (or insert) is 1.275, with a
1546
+ // p99 probe length of 4 (fewer than 1% of failing find look at 5 or
1547
+ // more chunks).
1548
+ //
1549
+ // This code is structured so you can try various ways of encoding
1550
+ // the current probe state. For example, at the moment the probe's
1551
+ // state is the position in the cycle and the resulting chunk index is
1552
+ // computed from that inside probeCurrentIndex. We could also make the
1553
+ // probe state the chunk index, and then increment it by hp.second *
1554
+ // 2 + 1 in probeAdvance. Wrapping can be applied early or late as
1555
+ // well. This particular code seems to be easier for the optimizer
1556
+ // to understand.
1557
+ //
1558
+ // We could also implement probing strategies that resulted in the same
1559
+ // tour for every key initially assigned to a chunk (linear probing or
1560
+ // quadratic), but that results in longer probe lengths. In particular,
1561
+ // the cache locality wins of linear probing are not worth the increase
1562
+ // in probe lengths (extra work and less branch predictability) in
1563
+ // our experiments.
1564
+
1565
+ std::size_t probeDelta(HashPair hp) const { return 2 * hp.second + 1; }
1566
+
1567
+ enum class Prefetch { DISABLED, ENABLED };
1568
+
1569
+ template <typename K>
1570
+ FOLLY_ALWAYS_INLINE ItemIter
1571
+ findImpl(HashPair hp, K const& key, Prefetch prefetch) const {
1572
+ std::size_t index = hp.first;
1573
+ std::size_t step = probeDelta(hp);
1574
+ for (std::size_t tries = 0; tries >> chunkShift() == 0; ++tries) {
1575
+ ChunkPtr chunk = chunks_ + moduloByChunkCount(index);
1576
+ if (prefetch == Prefetch::ENABLED && sizeof(Chunk) > 64) {
1577
+ prefetchAddr(chunk->itemAddr(8));
1578
+ }
1579
+ auto hits = chunk->tagMatchIter(hp.second);
1580
+ while (hits.hasNext()) {
1581
+ auto i = hits.next();
1582
+ if (FOLLY_LIKELY(this->keyMatchesItem(key, chunk->item(i)))) {
1583
+ // Tag match and key match were both successful. The chance
1584
+ // of a false tag match is 1/128 for each key in the chunk
1585
+ // (with a proper hash function).
1586
+ return ItemIter{chunk, i};
1587
+ }
1588
+ }
1589
+ if (FOLLY_LIKELY(chunk->outboundOverflowCount() == 0)) {
1590
+ // No keys that wanted to be placed in this chunk were denied
1591
+ // entry, so our search is over. This is the common case.
1592
+ break;
1593
+ }
1594
+ index += step;
1595
+ }
1596
+ // Loop exit because tries is exhausted is rare, but possible.
1597
+ // That means that for every chunk there is currently a key present
1598
+ // in the map that visited that chunk on its probe search but ended
1599
+ // up somewhere else, and we have searched every chunk.
1600
+ return ItemIter{};
1601
+ }
1602
+
1603
+ public:
1604
+ // prehash()/prefetch() split the work of find(key) into three calls, enabling
1605
+ // you to manually implement loop pipelining for hot bulk lookups. prehash()
1606
+ // computes the hash and prefetch() prefetches the first computed memory
1607
+ // location, and the two-arg find(F14HashToken, K) performs the rest of the
1608
+ // search.
1609
+ template <typename K>
1610
+ F14HashToken prehash(K const& key) const {
1611
+ return F14HashToken{splitHash(this->computeKeyHash(key))};
1612
+ }
1613
+
1614
+ template <typename K>
1615
+ F14HashToken prehash(K const& key, std::size_t hash) const {
1616
+ FOLLY_SAFE_DCHECK(hash == this->computeKeyHash(key));
1617
+ return F14HashToken{splitHash(hash)};
1618
+ }
1619
+
1620
+ void prefetch(F14HashToken const& token) const {
1621
+ FOLLY_SAFE_DCHECK(chunks_ != nullptr, "");
1622
+ ChunkPtr firstChunk = chunks_ + moduloByChunkCount(token.hp_.first);
1623
+ prefetchAddr(firstChunk);
1624
+ }
1625
+
1626
+ template <typename K>
1627
+ FOLLY_ALWAYS_INLINE ItemIter find(K const& key) const {
1628
+ auto hp = splitHash(this->computeKeyHash(key));
1629
+ return findImpl(hp, key, Prefetch::ENABLED);
1630
+ }
1631
+
1632
+ template <typename K>
1633
+ FOLLY_ALWAYS_INLINE ItemIter
1634
+ find(F14HashToken const& token, K const& key) const {
1635
+ FOLLY_SAFE_DCHECK(
1636
+ splitHash(this->computeKeyHash(key)) == static_cast<HashPair>(token),
1637
+ "");
1638
+ return findImpl(static_cast<HashPair>(token), key, Prefetch::DISABLED);
1639
+ }
1640
+
1641
+ // Searches for a key using a key predicate that is a refinement
1642
+ // of key equality. func(k) should return true only if k is equal
1643
+ // to key according to key_eq(), but is allowed to apply additional
1644
+ // constraints.
1645
+ template <typename K, typename F>
1646
+ FOLLY_ALWAYS_INLINE ItemIter findMatching(K const& key, F&& func) const {
1647
+ auto hp = splitHash(this->computeKeyHash(key));
1648
+ std::size_t index = hp.first;
1649
+ std::size_t step = probeDelta(hp);
1650
+ for (std::size_t tries = 0; tries >> chunkShift() == 0; ++tries) {
1651
+ ChunkPtr chunk = chunks_ + moduloByChunkCount(index);
1652
+ if (sizeof(Chunk) > 64) {
1653
+ prefetchAddr(chunk->itemAddr(8));
1654
+ }
1655
+ auto hits = chunk->tagMatchIter(hp.second);
1656
+ while (hits.hasNext()) {
1657
+ auto i = hits.next();
1658
+ if (FOLLY_LIKELY(
1659
+ func(this->keyForValue(this->valueAtItem(chunk->item(i)))))) {
1660
+ return ItemIter{chunk, i};
1661
+ }
1662
+ }
1663
+ if (FOLLY_LIKELY(chunk->outboundOverflowCount() == 0)) {
1664
+ break;
1665
+ }
1666
+ index += step;
1667
+ }
1668
+ return ItemIter{};
1669
+ }
1670
+
1671
+ private:
1672
+ void adjustSizeAndBeginAfterInsert(ItemIter iter) {
1673
+ if constexpr (kEnableItemIteration) {
1674
+ // packedBegin is the max of all valid ItemIter::pack()
1675
+ auto packed = iter.pack();
1676
+ if (sizeAndChunkShiftAndPackedBegin_.packedBegin() < packed) {
1677
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() = packed;
1678
+ }
1679
+ }
1680
+
1681
+ sizeAndChunkShiftAndPackedBegin_.incrementSize();
1682
+ }
1683
+
1684
+ // Ignores hp if pos.chunk()->hostedOverflowCount() == 0
1685
+ void eraseBlank(ItemIter iter, HashPair hp) {
1686
+ iter.chunk()->clearTag(iter.index());
1687
+
1688
+ if (iter.chunk()->hostedOverflowCount() != 0) {
1689
+ // clean up
1690
+ std::size_t index = hp.first;
1691
+ std::size_t delta = probeDelta(hp);
1692
+ uint8_t hostedOp = 0;
1693
+ while (true) {
1694
+ ChunkPtr chunk = chunks_ + moduloByChunkCount(index);
1695
+ if (chunk == iter.chunk()) {
1696
+ chunk->adjustHostedOverflowCount(hostedOp);
1697
+ break;
1698
+ }
1699
+ chunk->decrOutboundOverflowCount();
1700
+ hostedOp = Chunk::kDecrHostedOverflowCount;
1701
+ index += delta;
1702
+ }
1703
+ }
1704
+ }
1705
+
1706
+ void adjustSizeAndBeginBeforeErase(ItemIter iter) {
1707
+ sizeAndChunkShiftAndPackedBegin_.decrementSize();
1708
+ if constexpr (kEnableItemIteration) {
1709
+ if (iter.pack() == sizeAndChunkShiftAndPackedBegin_.packedBegin()) {
1710
+ if (size() == 0) {
1711
+ iter = ItemIter{};
1712
+ } else {
1713
+ iter.precheckedAdvance();
1714
+ }
1715
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() = iter.pack();
1716
+ }
1717
+ }
1718
+ }
1719
+
1720
+ template <typename... Args>
1721
+ void insertAtBlank(ItemIter pos, HashPair hp, Args&&... args) {
1722
+ try {
1723
+ auto dst = pos.itemAddr();
1724
+ this->constructValueAtItem(*this, dst, std::forward<Args>(args)...);
1725
+ } catch (...) {
1726
+ eraseBlank(pos, hp);
1727
+ throw;
1728
+ }
1729
+ adjustSizeAndBeginAfterInsert(pos);
1730
+ }
1731
+
1732
+ ItemIter allocateTag(uint8_t* fullness, HashPair hp) {
1733
+ ChunkPtr chunk;
1734
+ std::size_t index = hp.first;
1735
+ std::size_t delta = probeDelta(hp);
1736
+ uint8_t hostedOp = 0;
1737
+ while (true) {
1738
+ index = moduloByChunkCount(index);
1739
+ chunk = chunks_ + index;
1740
+ if (FOLLY_LIKELY(fullness[index] < Chunk::kCapacity)) {
1741
+ break;
1742
+ }
1743
+ chunk->incrOutboundOverflowCount();
1744
+ hostedOp = Chunk::kIncrHostedOverflowCount;
1745
+ index += delta;
1746
+ }
1747
+ unsigned itemIndex = fullness[index]++;
1748
+ FOLLY_SAFE_DCHECK(!chunk->occupied(itemIndex), "");
1749
+ chunk->setTag(itemIndex, hp.second);
1750
+ chunk->adjustHostedOverflowCount(hostedOp);
1751
+ return ItemIter{chunk, itemIndex};
1752
+ }
1753
+
1754
+ ChunkPtr lastOccupiedChunk() const {
1755
+ FOLLY_SAFE_DCHECK(size() > 0, "");
1756
+ if constexpr (kEnableItemIteration) {
1757
+ return begin().chunk();
1758
+ } else {
1759
+ return chunks_ + chunkCount() - 1;
1760
+ }
1761
+ }
1762
+
1763
+ template <typename T>
1764
+ void directBuildFrom(T&& src) {
1765
+ FOLLY_SAFE_DCHECK(src.size() > 0 && chunkShift() == src.chunkShift(), "");
1766
+
1767
+ // We use std::forward<T> to allow portions of src to be moved out by
1768
+ // either beforeBuild or afterBuild, but we are just relying on good
1769
+ // behavior of our Policy superclass to ensure that any particular
1770
+ // field of this is a donor at most once.
1771
+
1772
+ auto undoState =
1773
+ this->beforeBuild(src.size(), bucket_count(), std::forward<T>(src));
1774
+ bool success = false;
1775
+ SCOPE_EXIT {
1776
+ this->afterBuild(
1777
+ undoState, success, src.size(), bucket_count(), std::forward<T>(src));
1778
+ };
1779
+
1780
+ // Copy can fail part-way through if a Value copy constructor throws.
1781
+ // Failing afterBuild is limited in its cleanup power in this case,
1782
+ // because it can't enumerate the items that were actually copied.
1783
+ // Fortunately we can divide the situation into cases where all of
1784
+ // the state is owned by the table itself (F14Node and F14Value),
1785
+ // for which clearImpl() can do partial cleanup, and cases where all
1786
+ // of the values are owned by the policy (F14Vector), in which case
1787
+ // partial failure should not occur. Sorry for the subtle invariants
1788
+ // in the Policy API.
1789
+
1790
+ if (std::is_trivially_copyable<Item>::value &&
1791
+ !this->destroyItemOnClear() && itemCount() == src.itemCount()) {
1792
+ FOLLY_SAFE_DCHECK(chunkShift() == src.chunkShift(), "");
1793
+
1794
+ auto scale = Chunk::capacityScale(access::to_address(chunks_));
1795
+
1796
+ // most happy path
1797
+ auto n = chunkAllocSize(chunkCount(), scale);
1798
+ std::memcpy(&chunks_[0], &src.chunks_[0], n);
1799
+ sizeAndChunkShiftAndPackedBegin_.setSize(src.size());
1800
+ if constexpr (kEnableItemIteration) {
1801
+ auto srcBegin = src.begin();
1802
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() =
1803
+ ItemIter{
1804
+ chunks_ + (srcBegin.chunk() - src.chunks_), srcBegin.index()}
1805
+ .pack();
1806
+ }
1807
+ if constexpr (kContinuousCapacity) {
1808
+ // capacityScale might not match even if itemCount matches
1809
+ chunks_->setCapacityScale(scale);
1810
+ }
1811
+ } else {
1812
+ // Happy path, no rehash but pack items toward bottom of chunk
1813
+ // and use copy constructor. Don't try to optimize by using
1814
+ // lastOccupiedChunk() because there may be higher unoccupied chunks
1815
+ // with the overflow bit set.
1816
+ auto srcChunk = &src.chunks_[chunkCount() - 1];
1817
+ Chunk* dstChunk = &chunks_[chunkCount() - 1];
1818
+ do {
1819
+ dstChunk->copyOverflowInfoFrom(*srcChunk);
1820
+
1821
+ auto iter = srcChunk->occupiedIter();
1822
+ if (prefetchBeforeCopy()) {
1823
+ for (auto piter = iter; piter.hasNext();) {
1824
+ this->prefetchValue(srcChunk->citem(piter.next()));
1825
+ }
1826
+ }
1827
+
1828
+ std::size_t dstI = 0;
1829
+ for (; iter.hasNext(); ++dstI) {
1830
+ auto srcI = iter.next();
1831
+ auto&& srcArg =
1832
+ std::forward<T>(src).buildArgForItem(srcChunk->item(srcI));
1833
+ auto dst = dstChunk->itemAddr(dstI);
1834
+ this->constructValueAtItem(
1835
+ 0, dst, std::forward<decltype(srcArg)>(srcArg));
1836
+ dstChunk->setTag(dstI, srcChunk->tag(srcI));
1837
+ sizeAndChunkShiftAndPackedBegin_.incrementSize();
1838
+ }
1839
+
1840
+ --srcChunk;
1841
+ --dstChunk;
1842
+ } while (size() != src.size());
1843
+
1844
+ // reset doesn't care about packedBegin, so we don't fix it until the end
1845
+ if constexpr (kEnableItemIteration) {
1846
+ std::size_t maxChunkIndex = src.lastOccupiedChunk() - src.chunks_;
1847
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() =
1848
+ ItemIter{
1849
+ chunks_ + maxChunkIndex,
1850
+ chunks_[maxChunkIndex].lastOccupied().index()}
1851
+ .pack();
1852
+ }
1853
+ }
1854
+
1855
+ success = true;
1856
+ }
1857
+
1858
+ template <typename T>
1859
+ void rehashBuildFrom(T&& src) {
1860
+ FOLLY_SAFE_DCHECK(src.chunkCount() > chunkCount(), "");
1861
+
1862
+ // 1 byte per chunk means < 1 bit per value temporary overhead
1863
+ std::array<uint8_t, 256> stackBuf;
1864
+ uint8_t* fullness;
1865
+ auto cc = chunkCount();
1866
+ if (cc <= stackBuf.size()) {
1867
+ fullness = stackBuf.data();
1868
+ } else {
1869
+ ByteAlloc a{this->alloc()};
1870
+ fullness = &*std::allocator_traits<ByteAlloc>::allocate(a, cc);
1871
+ }
1872
+ SCOPE_EXIT {
1873
+ if (cc > stackBuf.size()) {
1874
+ ByteAlloc a{this->alloc()};
1875
+ std::allocator_traits<ByteAlloc>::deallocate(
1876
+ a,
1877
+ std::pointer_traits<typename std::allocator_traits<
1878
+ ByteAlloc>::pointer>::pointer_to(*fullness),
1879
+ cc);
1880
+ }
1881
+ };
1882
+ std::memset(fullness, '\0', cc);
1883
+
1884
+ // We use std::forward<T> to allow portions of src to be moved out by
1885
+ // either beforeBuild or afterBuild, but we are just relying on good
1886
+ // behavior of our Policy superclass to ensure that any particular
1887
+ // field of this is a donor at most once.
1888
+
1889
+ // Exception safety requires beforeBuild to happen after all of the
1890
+ // allocate() calls.
1891
+ auto undoState =
1892
+ this->beforeBuild(src.size(), bucket_count(), std::forward<T>(src));
1893
+ bool success = false;
1894
+ SCOPE_EXIT {
1895
+ this->afterBuild(
1896
+ undoState, success, src.size(), bucket_count(), std::forward<T>(src));
1897
+ };
1898
+
1899
+ // The current table is at a valid state at all points for policies
1900
+ // in which non-trivial values are owned by the main table (F14Node
1901
+ // and F14Value), so reset() will clean things up properly if we
1902
+ // fail partway through. For the case that the policy manages value
1903
+ // lifecycle (F14Vector) then nothing after beforeBuild can throw and
1904
+ // we don't have to worry about partial failure.
1905
+
1906
+ std::size_t srcChunkIndex = src.lastOccupiedChunk() - src.chunks_;
1907
+ while (true) {
1908
+ auto srcChunk = &src.chunks_[srcChunkIndex];
1909
+ auto iter = srcChunk->occupiedIter();
1910
+ if (prefetchBeforeRehash()) {
1911
+ for (auto piter = iter; piter.hasNext();) {
1912
+ this->prefetchValue(srcChunk->item(piter.next()));
1913
+ }
1914
+ }
1915
+ if (srcChunk->hostedOverflowCount() == 0) {
1916
+ // all items are in their preferred chunk (no probing), so we
1917
+ // don't need to compute any hash values
1918
+ while (iter.hasNext()) {
1919
+ auto i = iter.next();
1920
+ auto& srcItem = srcChunk->item(i);
1921
+ auto&& srcArg = std::forward<T>(src).buildArgForItem(srcItem);
1922
+ HashPair hp{srcChunkIndex, srcChunk->tag(i)};
1923
+ insertAtBlank(
1924
+ allocateTag(fullness, hp),
1925
+ hp,
1926
+ std::forward<decltype(srcArg)>(srcArg));
1927
+ }
1928
+ } else {
1929
+ // any chunk's items might be in here
1930
+ while (iter.hasNext()) {
1931
+ auto i = iter.next();
1932
+ auto& srcItem = srcChunk->item(i);
1933
+ auto&& srcArg = std::forward<T>(src).buildArgForItem(srcItem);
1934
+ auto const& srcKey = src.keyForValue(srcArg);
1935
+ auto hp = splitHash(this->computeKeyHash(srcKey));
1936
+ FOLLY_SAFE_CHECK(hp.second == srcChunk->tag(i), "");
1937
+ insertAtBlank(
1938
+ allocateTag(fullness, hp),
1939
+ hp,
1940
+ std::forward<decltype(srcArg)>(srcArg));
1941
+ }
1942
+ }
1943
+ if (srcChunkIndex == 0) {
1944
+ break;
1945
+ }
1946
+ --srcChunkIndex;
1947
+ }
1948
+
1949
+ success = true;
1950
+ }
1951
+
1952
+ template <typename T>
1953
+ FOLLY_NOINLINE void buildFromF14Table(T&& src) {
1954
+ FOLLY_SAFE_DCHECK(bucket_count() == 0, "");
1955
+ if (src.size() == 0) {
1956
+ return;
1957
+ }
1958
+
1959
+ // Use the source's capacity, unless it is oversized.
1960
+ auto upperLimit = computeChunkCountAndScale(src.size(), false, false);
1961
+ auto ccas = std::make_pair(
1962
+ src.chunkCount(),
1963
+ Chunk::capacityScale(access::to_address(src.chunks_)));
1964
+ FOLLY_SAFE_DCHECK(
1965
+ ccas.first >= upperLimit.first,
1966
+ "rounded chunk count can't be bigger than actual");
1967
+ if (ccas.first > upperLimit.first || ccas.second > upperLimit.second) {
1968
+ ccas = upperLimit;
1969
+ }
1970
+ rehashImpl(0, 1, 0, ccas.first, ccas.second);
1971
+
1972
+ try {
1973
+ if (chunkShift() == src.chunkShift()) {
1974
+ directBuildFrom(std::forward<T>(src));
1975
+ } else {
1976
+ rehashBuildFrom(std::forward<T>(src));
1977
+ }
1978
+ } catch (...) {
1979
+ reset();
1980
+ F14LinkCheck<getF14IntrinsicsMode()>::check();
1981
+ throw;
1982
+ }
1983
+ }
1984
+
1985
+ void maybeRehash(std::size_t desiredCapacity, bool attemptExact) {
1986
+ auto origChunkCount = chunkCount();
1987
+ auto origCapacityScale = Chunk::capacityScale(access::to_address(chunks_));
1988
+ auto origCapacity = computeCapacity(origChunkCount, origCapacityScale);
1989
+
1990
+ std::size_t newChunkCount;
1991
+ std::size_t newCapacityScale;
1992
+ std::tie(newChunkCount, newCapacityScale) = computeChunkCountAndScale(
1993
+ desiredCapacity, attemptExact, kContinuousCapacity && attemptExact);
1994
+ auto newCapacity = computeCapacity(newChunkCount, newCapacityScale);
1995
+
1996
+ if (origCapacity != newCapacity) {
1997
+ rehashImpl(
1998
+ size(),
1999
+ origChunkCount,
2000
+ origCapacityScale,
2001
+ newChunkCount,
2002
+ newCapacityScale);
2003
+ }
2004
+ }
2005
+
2006
+ void reserveImpl(std::size_t requestedCapacity) {
2007
+ const size_t targetCapacity =
2008
+ std::max<std::size_t>(requestedCapacity, size());
2009
+ if (targetCapacity == 0) {
2010
+ reset();
2011
+ return;
2012
+ }
2013
+
2014
+ // Special case reserve(n) for n <= size() (pseudo "shrink_to_fit")
2015
+ if (requestedCapacity <= size()) {
2016
+ maybeRehash(targetCapacity, /*attemptExact*/ true);
2017
+ return;
2018
+ }
2019
+
2020
+ auto origCapacity = bucket_count();
2021
+
2022
+ // Never shrink in order to avoid O(n^2) behavior of repeated reserves
2023
+ if (targetCapacity <= origCapacity) {
2024
+ return;
2025
+ }
2026
+
2027
+ // Large increase? Good chance the capacity is exactly right
2028
+ bool attemptExact =
2029
+ targetCapacity > origCapacity + ((origCapacity + 7) / 8);
2030
+ maybeRehash(targetCapacity, attemptExact);
2031
+ }
2032
+
2033
+ FOLLY_NOINLINE void reserveForInsertImpl(
2034
+ std::size_t capacityMinusOne,
2035
+ std::size_t origChunkCount,
2036
+ std::size_t origCapacityScale,
2037
+ std::size_t origCapacity) {
2038
+ FOLLY_SAFE_DCHECK(capacityMinusOne >= size(), "");
2039
+ std::size_t capacity = capacityMinusOne + 1;
2040
+
2041
+ // we want to grow by between 2^0.5 and 2^1.5 ending at a "good"
2042
+ // size, so we grow by 2^0.5 and then round up
2043
+
2044
+ // 1.01101_2 = 1.40625
2045
+ std::size_t minGrowth = origCapacity + (origCapacity >> 2) +
2046
+ (origCapacity >> 3) + (origCapacity >> 5);
2047
+ capacity = std::max<std::size_t>(capacity, minGrowth);
2048
+
2049
+ std::size_t newChunkCount;
2050
+ std::size_t newCapacityScale;
2051
+ std::tie(newChunkCount, newCapacityScale) =
2052
+ computeChunkCountAndScale(capacity, false, false);
2053
+
2054
+ FOLLY_SAFE_DCHECK(
2055
+ computeCapacity(newChunkCount, newCapacityScale) > origCapacity, "");
2056
+
2057
+ rehashImpl(
2058
+ size(),
2059
+ origChunkCount,
2060
+ origCapacityScale,
2061
+ newChunkCount,
2062
+ newCapacityScale);
2063
+ }
2064
+
2065
+ void initialReserve(std::size_t desiredCapacity) {
2066
+ FOLLY_SAFE_DCHECK(size() == 0, "");
2067
+ FOLLY_SAFE_DCHECK(chunkShift() == 0, "");
2068
+ FOLLY_SAFE_DCHECK(!!chunks_);
2069
+ FOLLY_SAFE_DCHECK(Chunk::isEmptyInstance(access::to_address(chunks_)), "");
2070
+ if (desiredCapacity == 0) {
2071
+ return;
2072
+ }
2073
+
2074
+ std::size_t newChunkCount;
2075
+ std::size_t newCapacityScale;
2076
+ std::tie(newChunkCount, newCapacityScale) = computeChunkCountAndScale(
2077
+ desiredCapacity, /*attemptExact=*/true, kContinuousCapacity);
2078
+ auto newCapacity = computeCapacity(newChunkCount, newCapacityScale);
2079
+ auto newAllocSize = chunkAllocSize(newChunkCount, newCapacityScale);
2080
+
2081
+ BytePtr rawAllocation;
2082
+ auto undoState =
2083
+ this->beforeRehash(0, 0, newCapacity, newAllocSize, rawAllocation);
2084
+
2085
+ chunks_ = initializeChunks(rawAllocation, newChunkCount, newCapacityScale);
2086
+
2087
+ sizeAndChunkShiftAndPackedBegin_.setChunkCount(newChunkCount);
2088
+
2089
+ this->afterRehash(
2090
+ std::move(undoState), true, 0, 0, newCapacity, nullptr, 0);
2091
+ }
2092
+
2093
+ void rehashImpl(
2094
+ std::size_t origSize,
2095
+ std::size_t origChunkCount,
2096
+ std::size_t origCapacityScale,
2097
+ std::size_t newChunkCount,
2098
+ std::size_t newCapacityScale) {
2099
+ auto origChunks = chunks_;
2100
+ auto origCapacity = computeCapacity(origChunkCount, origCapacityScale);
2101
+ auto origAllocSize = chunkAllocSize(origChunkCount, origCapacityScale);
2102
+ auto newCapacity = computeCapacity(newChunkCount, newCapacityScale);
2103
+ auto newAllocSize = chunkAllocSize(newChunkCount, newCapacityScale);
2104
+
2105
+ BytePtr rawAllocation;
2106
+ auto undoState = this->beforeRehash(
2107
+ origSize, origCapacity, newCapacity, newAllocSize, rawAllocation);
2108
+ chunks_ = initializeChunks(rawAllocation, newChunkCount, newCapacityScale);
2109
+
2110
+ sizeAndChunkShiftAndPackedBegin_.setChunkCount(newChunkCount);
2111
+
2112
+ bool success = false;
2113
+ SCOPE_EXIT {
2114
+ // this SCOPE_EXIT reverts chunks_ and chunkShift if necessary
2115
+ BytePtr finishedRawAllocation = nullptr;
2116
+ std::size_t finishedAllocSize = 0;
2117
+ if (FOLLY_LIKELY(success)) {
2118
+ if (origCapacity > 0) {
2119
+ finishedRawAllocation = std::pointer_traits<BytePtr>::pointer_to(
2120
+ *static_cast<uint8_t*>(static_cast<void*>(&*origChunks)));
2121
+ finishedAllocSize = origAllocSize;
2122
+ }
2123
+ } else {
2124
+ finishedRawAllocation = rawAllocation;
2125
+ finishedAllocSize = newAllocSize;
2126
+ chunks_ = origChunks;
2127
+ sizeAndChunkShiftAndPackedBegin_.setChunkCount(origChunkCount);
2128
+ F14LinkCheck<getF14IntrinsicsMode()>::check();
2129
+ }
2130
+
2131
+ this->afterRehash(
2132
+ std::move(undoState),
2133
+ success,
2134
+ origSize,
2135
+ origCapacity,
2136
+ newCapacity,
2137
+ finishedRawAllocation,
2138
+ finishedAllocSize);
2139
+ };
2140
+
2141
+ if (origSize == 0) {
2142
+ // nothing to do
2143
+ } else if (origChunkCount == 1 && newChunkCount == 1) {
2144
+ // no mask, no chunk scan, no hash computation, no probing
2145
+ auto srcChunk = origChunks;
2146
+ auto dstChunk = chunks_;
2147
+ std::size_t srcI = 0;
2148
+ std::size_t dstI = 0;
2149
+ while (dstI < origSize) {
2150
+ if (FOLLY_LIKELY(srcChunk->occupied(srcI))) {
2151
+ dstChunk->setTag(dstI, srcChunk->tag(srcI));
2152
+ this->moveItemDuringRehash(
2153
+ dstChunk->itemAddr(dstI), srcChunk->item(srcI));
2154
+ ++dstI;
2155
+ }
2156
+ ++srcI;
2157
+ }
2158
+ if constexpr (kEnableItemIteration) {
2159
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() =
2160
+ ItemIter{dstChunk, dstI - 1}.pack();
2161
+ }
2162
+ } else {
2163
+ // 1 byte per chunk means < 1 bit per value temporary overhead
2164
+ std::array<uint8_t, 256> stackBuf;
2165
+ uint8_t* fullness;
2166
+ if (newChunkCount <= stackBuf.size()) {
2167
+ fullness = stackBuf.data();
2168
+ } else {
2169
+ ByteAlloc a{this->alloc()};
2170
+ // may throw
2171
+ fullness =
2172
+ &*std::allocator_traits<ByteAlloc>::allocate(a, newChunkCount);
2173
+ }
2174
+ std::memset(fullness, '\0', newChunkCount);
2175
+ SCOPE_EXIT {
2176
+ if (newChunkCount > stackBuf.size()) {
2177
+ ByteAlloc a{this->alloc()};
2178
+ std::allocator_traits<ByteAlloc>::deallocate(
2179
+ a,
2180
+ std::pointer_traits<typename std::allocator_traits<
2181
+ ByteAlloc>::pointer>::pointer_to(*fullness),
2182
+ newChunkCount);
2183
+ }
2184
+ };
2185
+
2186
+ auto srcChunk = origChunks + origChunkCount - 1;
2187
+ std::size_t remaining = origSize;
2188
+ while (remaining > 0) {
2189
+ auto iter = srcChunk->occupiedIter();
2190
+ if (prefetchBeforeRehash()) {
2191
+ for (auto piter = iter; piter.hasNext();) {
2192
+ this->prefetchValue(srcChunk->item(piter.next()));
2193
+ }
2194
+ }
2195
+ while (iter.hasNext()) {
2196
+ --remaining;
2197
+ auto srcI = iter.next();
2198
+ Item& srcItem = srcChunk->item(srcI);
2199
+ auto hp = splitHash(
2200
+ this->computeItemHash(const_cast<Item const&>(srcItem)));
2201
+ FOLLY_SAFE_CHECK(hp.second == srcChunk->tag(srcI), "");
2202
+
2203
+ auto dstIter = allocateTag(fullness, hp);
2204
+ this->moveItemDuringRehash(dstIter.itemAddr(), srcItem);
2205
+ }
2206
+ --srcChunk;
2207
+ }
2208
+
2209
+ if constexpr (kEnableItemIteration) {
2210
+ // this code replaces size invocations of adjustSizeAndBeginAfterInsert
2211
+ std::size_t i = chunkCount() - 1;
2212
+ while (fullness[i] == 0) {
2213
+ --i;
2214
+ }
2215
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() =
2216
+ ItemIter{chunks_ + i, std::size_t{fullness[i]} - 1}.pack();
2217
+ }
2218
+ }
2219
+
2220
+ success = true;
2221
+ }
2222
+
2223
+ // Randomization to help expose bugs when running tests in debug or
2224
+ // sanitizer builds
2225
+
2226
+ FOLLY_ALWAYS_INLINE void debugModeOnReserve(std::size_t capacity) {
2227
+ if constexpr (kIsLibrarySanitizeAddress || kIsDebug) {
2228
+ if (capacity > size()) {
2229
+ tlsPendingSafeInserts(static_cast<std::ptrdiff_t>(capacity - size()));
2230
+ }
2231
+ }
2232
+ }
2233
+
2234
+ void debugModeSpuriousRehash() {
2235
+ auto cc = chunkCount();
2236
+ auto ss = Chunk::capacityScale(access::to_address(chunks_));
2237
+ rehashImpl(size(), cc, ss, cc, ss);
2238
+ }
2239
+
2240
+ FOLLY_ALWAYS_INLINE void debugModeBeforeInsert() {
2241
+ // When running under ASAN, we add a spurious rehash with 1/size()
2242
+ // probability before every insert. This means that finding reference
2243
+ // stability problems for F14Value and F14Vector is much more likely.
2244
+ // The most common pattern that causes this is
2245
+ //
2246
+ // auto& ref = map[k1]; map[k2] = foo(ref);
2247
+ //
2248
+ // One way to fix this is to call map.reserve(N) before such a
2249
+ // sequence, where N is the number of keys that might be inserted
2250
+ // within the section that retains references plus the existing size.
2251
+ if constexpr (kIsLibrarySanitizeAddress) {
2252
+ if (!tlsPendingSafeInserts() && size() > 0 &&
2253
+ tlsMinstdRand(size()) == 0) {
2254
+ debugModeSpuriousRehash();
2255
+ }
2256
+ }
2257
+ }
2258
+
2259
+ FOLLY_ALWAYS_INLINE void debugModeAfterInsert() {
2260
+ if constexpr (kIsLibrarySanitizeAddress || kIsDebug) {
2261
+ tlsPendingSafeInserts(-1);
2262
+ }
2263
+ }
2264
+
2265
+ FOLLY_ALWAYS_INLINE void debugModePerturbSlotInsertOrder(
2266
+ ChunkPtr chunk, std::size_t& itemIndex) {
2267
+ FOLLY_SAFE_DCHECK(!chunk->occupied(itemIndex), "");
2268
+ constexpr bool perturbSlot = FOLLY_F14_PERTURB_INSERTION_ORDER;
2269
+ if (perturbSlot && !tlsPendingSafeInserts()) {
2270
+ std::size_t e = chunkShift() == 0 ? bucket_count() : Chunk::kCapacity;
2271
+ std::size_t i = itemIndex + tlsMinstdRand(e - itemIndex);
2272
+ if (!chunk->occupied(i)) {
2273
+ itemIndex = i;
2274
+ }
2275
+ }
2276
+ }
2277
+
2278
+ public:
2279
+ // user has no control over max_load_factor
2280
+
2281
+ void rehash(std::size_t capacity) { reserve(capacity); }
2282
+
2283
+ void reserve(std::size_t capacity) {
2284
+ // We want to support the pattern
2285
+ // map.reserve(map.size() + 2); auto& r1 = map[k1]; auto& r2 = map[k2];
2286
+ debugModeOnReserve(capacity);
2287
+ FOLLY_SAFE_DCHECK(!!chunks_);
2288
+ if (Chunk::isEmptyInstance(access::to_address(chunks_))) {
2289
+ initialReserve(capacity);
2290
+ } else {
2291
+ reserveImpl(capacity);
2292
+ }
2293
+ }
2294
+
2295
+ void reserveForInsert(size_t incoming = 1) {
2296
+ FOLLY_SAFE_DCHECK(incoming > 0, "");
2297
+
2298
+ auto needed = size() + incoming;
2299
+ auto chunkCount_ = chunkCount();
2300
+ auto scale = Chunk::capacityScale(access::to_address(chunks_));
2301
+ auto existing = computeCapacity(chunkCount_, scale);
2302
+ if (needed - 1 >= existing) {
2303
+ reserveForInsertImpl(needed - 1, chunkCount_, scale, existing);
2304
+ }
2305
+ }
2306
+
2307
+ // Returns pos,true if construct, pos,false if found. key is only used
2308
+ // during the search; all constructor args for an inserted value come
2309
+ // from args... key won't be accessed after args are touched.
2310
+ template <typename K, typename... Args>
2311
+ std::pair<ItemIter, bool> tryEmplaceValue(K const& key, Args&&... args) {
2312
+ const auto hp = splitHash(this->computeKeyHash(key));
2313
+ return tryEmplaceValueImpl(hp, key, std::forward<Args>(args)...);
2314
+ }
2315
+
2316
+ template <typename K, typename... Args>
2317
+ std::pair<ItemIter, bool> tryEmplaceValueWithToken(
2318
+ F14HashToken const& token, K const& key, Args&&... args) {
2319
+ FOLLY_SAFE_DCHECK(
2320
+ splitHash(this->computeKeyHash(key)) == static_cast<HashPair>(token),
2321
+ "");
2322
+ return tryEmplaceValueImpl(
2323
+ static_cast<HashPair>(token), key, std::forward<Args>(args)...);
2324
+ }
2325
+
2326
+ template <typename K, typename... Args>
2327
+ std::pair<ItemIter, bool> tryEmplaceValueImpl(
2328
+ HashPair hp, K const& key, Args&&... args) {
2329
+ if (size() > 0) {
2330
+ auto existing = findImpl(hp, key, Prefetch::ENABLED);
2331
+ if (!existing.atEnd()) {
2332
+ return std::make_pair(existing, false);
2333
+ }
2334
+ }
2335
+
2336
+ debugModeBeforeInsert();
2337
+
2338
+ reserveForInsert();
2339
+
2340
+ std::size_t index = hp.first;
2341
+ ChunkPtr chunk = chunks_ + moduloByChunkCount(index);
2342
+ auto firstEmpty = chunk->firstEmpty();
2343
+
2344
+ if (!firstEmpty.hasIndex()) {
2345
+ std::size_t delta = probeDelta(hp);
2346
+ do {
2347
+ chunk->incrOutboundOverflowCount();
2348
+ index += delta;
2349
+ chunk = chunks_ + moduloByChunkCount(index);
2350
+ firstEmpty = chunk->firstEmpty();
2351
+ } while (!firstEmpty.hasIndex());
2352
+ chunk->adjustHostedOverflowCount(Chunk::kIncrHostedOverflowCount);
2353
+ }
2354
+ std::size_t itemIndex = firstEmpty.index();
2355
+
2356
+ debugModePerturbSlotInsertOrder(chunk, itemIndex);
2357
+
2358
+ chunk->setTag(itemIndex, hp.second);
2359
+ ItemIter iter{chunk, itemIndex};
2360
+
2361
+ // insertAtBlank will clear the tag if the constructor throws
2362
+ insertAtBlank(iter, hp, std::forward<Args>(args)...);
2363
+
2364
+ debugModeAfterInsert();
2365
+
2366
+ return std::make_pair(iter, true);
2367
+ }
2368
+
2369
+ private:
2370
+ template <bool Reset>
2371
+ void clearImpl() noexcept {
2372
+ FOLLY_SAFE_DCHECK(!!chunks_);
2373
+ if (Chunk::isEmptyInstance(access::to_address(chunks_))) {
2374
+ FOLLY_SAFE_DCHECK(empty() && bucket_count() == 0, "");
2375
+ return;
2376
+ }
2377
+
2378
+ // turn clear into reset if the table is >= 16 chunks so that
2379
+ // we don't get too low a load factor
2380
+ bool willReset = Reset || chunkCount() >= 16;
2381
+
2382
+ auto origSize = size();
2383
+ auto origCapacity = bucket_count();
2384
+ if (willReset) {
2385
+ this->beforeReset(origSize, origCapacity);
2386
+ } else {
2387
+ this->beforeClear(origSize, origCapacity);
2388
+ }
2389
+
2390
+ if (!empty()) {
2391
+ if (destroyItemOnClear()) {
2392
+ for (std::size_t ci = 0; ci < chunkCount(); ++ci) {
2393
+ ChunkPtr chunk = chunks_ + ci;
2394
+ auto iter = chunk->occupiedIter();
2395
+ if (prefetchBeforeDestroy()) {
2396
+ for (auto piter = iter; piter.hasNext();) {
2397
+ this->prefetchValue(chunk->item(piter.next()));
2398
+ }
2399
+ }
2400
+ while (iter.hasNext()) {
2401
+ this->destroyItem(chunk->item(iter.next()));
2402
+ }
2403
+ }
2404
+ }
2405
+ if (!willReset) {
2406
+ // It's okay to do this in a separate loop because we only do it
2407
+ // when the chunk count is small. That avoids a branch when we
2408
+ // are promoting a clear to a reset for a large table.
2409
+ auto scale = Chunk::capacityScale(access::to_address(chunks_));
2410
+ for (std::size_t ci = 0; ci < chunkCount(); ++ci) {
2411
+ chunks_[ci].clear();
2412
+ }
2413
+ chunks_[0].markEof(scale);
2414
+ }
2415
+ if constexpr (kEnableItemIteration) {
2416
+ sizeAndChunkShiftAndPackedBegin_.packedBegin() = ItemIter{}.pack();
2417
+ }
2418
+ sizeAndChunkShiftAndPackedBegin_.setSize(0);
2419
+ }
2420
+
2421
+ if (willReset) {
2422
+ BytePtr rawAllocation = std::pointer_traits<BytePtr>::pointer_to(
2423
+ *static_cast<uint8_t*>(static_cast<void*>(&*chunks_)));
2424
+ std::size_t rawSize = chunkAllocSize(
2425
+ chunkCount(), Chunk::capacityScale(access::to_address(chunks_)));
2426
+
2427
+ chunks_ = Chunk::getSomeEmptyInstance();
2428
+ sizeAndChunkShiftAndPackedBegin_.setChunkCount(1);
2429
+
2430
+ this->afterReset(origSize, origCapacity, rawAllocation, rawSize);
2431
+ } else {
2432
+ this->afterClear(origSize, origCapacity);
2433
+ }
2434
+ }
2435
+
2436
+ void eraseImpl(ItemIter pos, HashPair hp) {
2437
+ this->destroyItem(pos.item());
2438
+ adjustSizeAndBeginBeforeErase(pos);
2439
+ eraseBlank(pos, hp);
2440
+ }
2441
+
2442
+ public:
2443
+ // The item needs to still be hashable during this call. If you want
2444
+ // to intercept the value before it is destroyed (to extract it, for
2445
+ // example), do so in the beforeDestroy callback.
2446
+ template <typename BeforeDestroy>
2447
+ void eraseIterInto(ItemIter pos, BeforeDestroy&& beforeDestroy) {
2448
+ HashPair hp{};
2449
+ if (pos.chunk()->hostedOverflowCount() != 0) {
2450
+ hp = splitHash(this->computeItemHash(pos.citem()));
2451
+ }
2452
+ beforeDestroy(this->valueAtItemForExtract(pos.item()));
2453
+ eraseImpl(pos, hp);
2454
+ }
2455
+
2456
+ template <typename K, typename BeforeDestroy>
2457
+ std::size_t eraseKeyInto(K const& key, BeforeDestroy&& beforeDestroy) {
2458
+ if (FOLLY_UNLIKELY(size() == 0)) {
2459
+ return 0;
2460
+ }
2461
+ auto hp = splitHash(this->computeKeyHash(key));
2462
+ auto iter = findImpl(hp, key, Prefetch::ENABLED);
2463
+ if (!iter.atEnd()) {
2464
+ beforeDestroy(this->valueAtItemForExtract(iter.item()));
2465
+ eraseImpl(iter, hp);
2466
+ return 1;
2467
+ } else {
2468
+ return 0;
2469
+ }
2470
+ }
2471
+
2472
+ void clear() noexcept {
2473
+ if constexpr (kIsLibrarySanitizeAddress) {
2474
+ // force recycling of heap memory
2475
+ auto bc = bucket_count();
2476
+ reset();
2477
+ try {
2478
+ reserveImpl(bc);
2479
+ } catch (std::bad_alloc const&) {
2480
+ // ASAN mode only, keep going
2481
+ }
2482
+ } else {
2483
+ clearImpl<false>();
2484
+ }
2485
+ }
2486
+
2487
+ // Like clear(), but always frees all dynamic storage allocated
2488
+ // by the table.
2489
+ void reset() noexcept { clearImpl<true>(); }
2490
+
2491
+ // Get memory footprint, not including sizeof(*this).
2492
+ std::size_t getAllocatedMemorySize() const {
2493
+ std::size_t sum = 0;
2494
+ visitAllocationClasses(
2495
+ [&sum](std::size_t bytes, std::size_t n) { sum += bytes * n; });
2496
+ return sum;
2497
+ }
2498
+
2499
+ // Enumerates classes of allocated memory blocks currently owned
2500
+ // by this table, calling visitor(allocationSize, allocationCount).
2501
+ // This can be used to get a more accurate indication of memory footprint
2502
+ // than getAllocatedMemorySize() if you have some way of computing the
2503
+ // internal fragmentation of the allocator, such as JEMalloc's nallocx.
2504
+ // The visitor might be called twice with the same allocationSize. The
2505
+ // visitor's computation should produce the same result for visitor(8,
2506
+ // 2) as for two calls to visitor(8, 1), for example. The visitor may
2507
+ // be called with a zero allocationCount.
2508
+ template <typename V>
2509
+ void visitAllocationClasses(V&& visitor) const {
2510
+ auto scale = Chunk::capacityScale(access::to_address(chunks_));
2511
+ this->visitPolicyAllocationClasses(
2512
+ scale == 0 ? 0 : chunkAllocSize(chunkCount(), scale),
2513
+ size(),
2514
+ bucket_count(),
2515
+ visitor);
2516
+ }
2517
+
2518
+ // visitor should take an Item const&
2519
+ template <typename V>
2520
+ void visitItems(V&& visitor) const {
2521
+ if (empty()) {
2522
+ return;
2523
+ }
2524
+ std::size_t maxChunkIndex = lastOccupiedChunk() - chunks_;
2525
+ auto chunk = &chunks_[0];
2526
+ for (std::size_t i = 0; i <= maxChunkIndex; ++i, ++chunk) {
2527
+ auto iter = chunk->occupiedIter();
2528
+ if (prefetchBeforeCopy()) {
2529
+ for (auto piter = iter; piter.hasNext();) {
2530
+ this->prefetchValue(chunk->citem(piter.next()));
2531
+ }
2532
+ }
2533
+ while (iter.hasNext()) {
2534
+ visitor(chunk->citem(iter.next()));
2535
+ }
2536
+ }
2537
+ }
2538
+
2539
+ // visitor should take two Item const*
2540
+ template <typename V>
2541
+ void visitContiguousItemRanges(V&& visitor) const {
2542
+ if (empty()) {
2543
+ return;
2544
+ }
2545
+ std::size_t maxChunkIndex = lastOccupiedChunk() - chunks_;
2546
+ auto chunk = &chunks_[0];
2547
+ for (std::size_t i = 0; i <= maxChunkIndex; ++i, ++chunk) {
2548
+ for (auto iter = chunk->occupiedRangeIter(); iter.hasNext();) {
2549
+ auto be = iter.next();
2550
+ FOLLY_SAFE_DCHECK(
2551
+ chunk->occupied(be.first) && chunk->occupied(be.second - 1), "");
2552
+ Item const* b = chunk->itemAddr(be.first);
2553
+ visitor(b, b + (be.second - be.first));
2554
+ }
2555
+ }
2556
+ }
2557
+
2558
+ private:
2559
+ static std::size_t& histoAt(
2560
+ std::vector<std::size_t>& histo, std::size_t index) {
2561
+ if (histo.size() <= index) {
2562
+ histo.resize(index + 1);
2563
+ }
2564
+ return histo.at(index);
2565
+ }
2566
+
2567
+ public:
2568
+ // Expensive
2569
+ F14TableStats computeStats() const {
2570
+ F14TableStats stats;
2571
+
2572
+ if constexpr (kIsDebug && kEnableItemIteration) {
2573
+ // validate iteration
2574
+ std::size_t n = 0;
2575
+ ItemIter prev;
2576
+ for (auto iter = begin(); iter != end(); iter.advance()) {
2577
+ FOLLY_SAFE_DCHECK(n == 0 || iter.pack() < prev.pack(), "");
2578
+ ++n;
2579
+ prev = iter;
2580
+ }
2581
+ FOLLY_SAFE_DCHECK(n == size(), "");
2582
+ }
2583
+
2584
+ FOLLY_SAFE_DCHECK(
2585
+ (Chunk::isEmptyInstance(access::to_address(chunks_))) ==
2586
+ (bucket_count() == 0),
2587
+ "");
2588
+
2589
+ std::size_t n1 = 0;
2590
+ std::size_t n2 = 0;
2591
+ auto cc = bucket_count() == 0 ? 0 : chunkCount();
2592
+ for (std::size_t ci = 0; ci < cc; ++ci) {
2593
+ ChunkPtr chunk = chunks_ + ci;
2594
+ FOLLY_SAFE_DCHECK(chunk->eof() == (ci == 0), "");
2595
+
2596
+ auto iter = chunk->occupiedIter();
2597
+
2598
+ std::size_t chunkOccupied = 0;
2599
+ for (auto piter = iter; piter.hasNext(); piter.next()) {
2600
+ ++chunkOccupied;
2601
+ }
2602
+ n1 += chunkOccupied;
2603
+
2604
+ histoAt(stats.chunkOccupancyHisto, chunkOccupied)++;
2605
+ histoAt(
2606
+ stats.chunkOutboundOverflowHisto, chunk->outboundOverflowCount())++;
2607
+ histoAt(stats.chunkHostedOverflowHisto, chunk->hostedOverflowCount())++;
2608
+
2609
+ while (iter.hasNext()) {
2610
+ auto ii = iter.next();
2611
+ ++n2;
2612
+
2613
+ {
2614
+ auto& item = chunk->citem(ii);
2615
+ auto hp = splitHash(this->computeItemHash(item));
2616
+ FOLLY_SAFE_DCHECK(chunk->tag(ii) == hp.second, "");
2617
+
2618
+ std::size_t dist = 1;
2619
+ std::size_t index = hp.first;
2620
+ std::size_t delta = probeDelta(hp);
2621
+ while (moduloByChunkCount(index) != ci) {
2622
+ index += delta;
2623
+ ++dist;
2624
+ }
2625
+
2626
+ histoAt(stats.keyProbeLengthHisto, dist)++;
2627
+ }
2628
+
2629
+ // misses could have any tag, so we do the dumb but accurate
2630
+ // thing and just try them all
2631
+ for (std::size_t ti = 0; ti < 256; ++ti) {
2632
+ uint8_t tag = static_cast<uint8_t>(ti == 0 ? 1 : 0);
2633
+ HashPair hp{ci, tag};
2634
+
2635
+ std::size_t dist = 1;
2636
+ std::size_t index = hp.first;
2637
+ std::size_t delta = probeDelta(hp);
2638
+ for (std::size_t tries = 0; tries >> chunkShift() == 0 &&
2639
+ chunks_[moduloByChunkCount(index)].outboundOverflowCount() != 0;
2640
+ ++tries) {
2641
+ index += delta;
2642
+ ++dist;
2643
+ }
2644
+
2645
+ histoAt(stats.missProbeLengthHisto, dist)++;
2646
+ }
2647
+ }
2648
+ }
2649
+
2650
+ FOLLY_SAFE_DCHECK(n1 == size(), "");
2651
+ FOLLY_SAFE_DCHECK(n2 == size(), "");
2652
+
2653
+ stats.policy = pretty_name<Policy>();
2654
+ stats.size = size();
2655
+ stats.valueSize = sizeof(value_type);
2656
+ stats.bucketCount = bucket_count();
2657
+ stats.chunkCount = cc;
2658
+
2659
+ stats.totalBytes = sizeof(*this) + getAllocatedMemorySize();
2660
+ stats.overheadBytes = stats.totalBytes - size() * sizeof(value_type);
2661
+
2662
+ return stats;
2663
+ }
2664
+ };
2665
+ } // namespace detail
2666
+ } // namespace f14
2667
+
2668
+ #endif // FOLLY_F14_VECTOR_INTRINSICS_AVAILABLE
2669
+
2670
+ namespace f14 {
2671
+ namespace test {
2672
+ inline void disableInsertOrderRandomization() {
2673
+ if constexpr (kIsLibrarySanitizeAddress || kIsDebug) {
2674
+ detail::tlsPendingSafeInserts(static_cast<std::ptrdiff_t>(
2675
+ (std::numeric_limits<std::size_t>::max)() / 2));
2676
+ }
2677
+ }
2678
+ } // namespace test
2679
+ } // namespace f14
2680
+ } // namespace folly