react-native-windows 0.81.34 → 0.81.37
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.
- package/Directory.Build.props +1 -16
- package/Folly/ThreadNameStub.cpp +4 -6
- package/Microsoft.ReactNative/Fabric/Composition/BorderPrimitive.cpp +1 -1
- package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +27 -4
- package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +8 -4
- package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +7 -3
- package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +48 -2
- package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +40 -13
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +1 -7
- package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj.filters +0 -3
- package/Microsoft.ReactNative/TurboModulesProvider.cpp +30 -13
- package/PropertySheets/Generated/PackageVersion.g.props +3 -3
- package/PropertySheets/React.Cpp.props +3 -3
- package/ReactCommon/ReactCommon.vcxproj +0 -10
- package/ReactCommon/packages.lock.win32.json +0 -10
- package/Scripts/Tfs/Layout-Desktop-Headers.ps1 +4 -37
- package/Scripts/creaternwlib.cmd +2 -2
- package/Shared/Shared.vcxitems +2 -0
- package/{Folly → external}/.clang-format +0 -1
- package/external/External.vcxitems +10 -0
- package/external/fast-float/.syncignore +10 -0
- package/external/fast-float/LICENSE-APACHE +190 -0
- package/external/fast-float/LICENSE-BOOST +23 -0
- package/external/fast-float/LICENSE-MIT +27 -0
- package/external/fast-float/README.md +545 -0
- package/external/fast-float/cgmanifest.json +15 -0
- package/external/fast-float/fast-float.vcxitems +14 -0
- package/external/fast-float/include/fast_float/ascii_number.h +588 -0
- package/external/fast-float/include/fast_float/bigint.h +638 -0
- package/external/fast-float/include/fast_float/constexpr_feature_detect.h +46 -0
- package/external/fast-float/include/fast_float/decimal_to_binary.h +212 -0
- package/external/fast-float/include/fast_float/digit_comparison.h +457 -0
- package/external/fast-float/include/fast_float/fast_float.h +59 -0
- package/external/fast-float/include/fast_float/fast_table.h +708 -0
- package/external/fast-float/include/fast_float/float_common.h +1240 -0
- package/external/fast-float/include/fast_float/parse_number.h +399 -0
- package/external/fast-float/sync-config.json +8 -0
- package/external/fmt/.syncignore +10 -0
- package/external/fmt/CONTRIBUTING.md +20 -0
- package/external/fmt/LICENSE +27 -0
- package/external/fmt/README.md +484 -0
- package/{fmt → external/fmt}/cgmanifest.json +1 -1
- package/external/fmt/doc/ChangeLog-old.md +3290 -0
- package/external/fmt/doc/api.md +650 -0
- package/external/fmt/doc/fmt.css +61 -0
- package/external/fmt/doc/fmt.js +4 -0
- package/external/fmt/doc/get-started.md +222 -0
- package/external/fmt/doc/index.md +151 -0
- package/external/fmt/doc/perf.svg +1 -0
- package/external/fmt/doc/python-license.txt +290 -0
- package/external/fmt/doc/syntax.md +887 -0
- package/external/fmt/fmt.vcxitems +28 -0
- package/external/fmt/include/fmt/args.h +228 -0
- package/{fmt/TEMP_UntilFmtUpdate/core.h → external/fmt/include/fmt/base.h} +1188 -1036
- package/external/fmt/include/fmt/chrono.h +2432 -0
- package/external/fmt/include/fmt/color.h +612 -0
- package/external/fmt/include/fmt/compile.h +529 -0
- package/external/fmt/include/fmt/core.h +5 -0
- package/external/fmt/include/fmt/format-inl.h +1928 -0
- package/external/fmt/include/fmt/format.h +4427 -0
- package/external/fmt/include/fmt/os.h +439 -0
- package/external/fmt/include/fmt/ostream.h +211 -0
- package/external/fmt/include/fmt/printf.h +656 -0
- package/external/fmt/include/fmt/ranges.h +882 -0
- package/external/fmt/include/fmt/std.h +699 -0
- package/external/fmt/include/fmt/xchar.h +322 -0
- package/external/fmt/src/fmt.cc +135 -0
- package/external/fmt/src/format.cc +43 -0
- package/external/fmt/src/os.cc +403 -0
- package/external/fmt/sync-config.json +8 -0
- package/external/folly/.syncignore +60 -0
- package/external/folly/LICENSE +200 -0
- package/external/folly/README.md +263 -0
- package/{fmt → external/folly/folly}/.clang-format +0 -1
- package/external/folly/folly/AtomicHashArray-inl.h +546 -0
- package/external/folly/folly/AtomicHashArray.h +431 -0
- package/external/folly/folly/AtomicHashMap-inl.h +653 -0
- package/external/folly/folly/AtomicHashMap.h +484 -0
- package/external/folly/folly/AtomicIntrusiveLinkedList.h +206 -0
- package/external/folly/folly/AtomicLinkedList.h +110 -0
- package/external/folly/folly/AtomicUnorderedMap.h +522 -0
- package/external/folly/folly/BUCK +1631 -0
- package/external/folly/folly/BUILD_MODE.bzl +72 -0
- package/external/folly/folly/Benchmark.cpp +986 -0
- package/external/folly/folly/Benchmark.h +680 -0
- package/external/folly/folly/BenchmarkUtil.h +47 -0
- package/external/folly/folly/Bits.h +17 -0
- package/external/folly/folly/CMakeLists.txt +110 -0
- package/external/folly/folly/CPortability.h +338 -0
- package/external/folly/folly/CancellationToken-inl.h +449 -0
- package/external/folly/folly/CancellationToken.cpp +250 -0
- package/external/folly/folly/CancellationToken.h +365 -0
- package/external/folly/folly/Chrono.h +132 -0
- package/external/folly/folly/ClockGettimeWrappers.cpp +93 -0
- package/external/folly/folly/ClockGettimeWrappers.h +29 -0
- package/external/folly/folly/ConcurrentBitSet.h +157 -0
- package/external/folly/folly/ConcurrentLazy.h +74 -0
- package/external/folly/folly/ConcurrentSkipList-inl.h +341 -0
- package/external/folly/folly/ConcurrentSkipList.h +824 -0
- package/external/folly/folly/ConstructorCallbackList.h +158 -0
- package/external/folly/folly/Conv.h +2026 -0
- package/external/folly/folly/CppAttributes.h +170 -0
- package/external/folly/folly/CpuId.h +297 -0
- package/external/folly/folly/DefaultKeepAliveExecutor.h +172 -0
- package/external/folly/folly/Demangle.cpp +255 -0
- package/external/folly/folly/Demangle.h +73 -0
- package/external/folly/folly/DiscriminatedPtr.h +236 -0
- package/external/folly/folly/DynamicConverter.h +17 -0
- package/external/folly/folly/Exception.h +150 -0
- package/external/folly/folly/ExceptionString.cpp +51 -0
- package/external/folly/folly/ExceptionString.h +33 -0
- package/external/folly/folly/ExceptionWrapper-inl.h +264 -0
- package/external/folly/folly/ExceptionWrapper.cpp +37 -0
- package/external/folly/folly/ExceptionWrapper.h +377 -0
- package/external/folly/folly/Executor.cpp +111 -0
- package/external/folly/folly/Executor.h +351 -0
- package/external/folly/folly/Expected.h +1725 -0
- package/external/folly/folly/FBString.h +2888 -0
- package/external/folly/folly/FBVector.h +17 -0
- package/external/folly/folly/File.cpp +180 -0
- package/external/folly/folly/File.h +177 -0
- package/external/folly/folly/FileUtil.cpp +378 -0
- package/external/folly/folly/FileUtil.h +332 -0
- package/external/folly/folly/Fingerprint.cpp +135 -0
- package/external/folly/folly/Fingerprint.h +289 -0
- package/external/folly/folly/FixedString.h +2965 -0
- package/external/folly/folly/FollyMemcpy.cpp +30 -0
- package/external/folly/folly/FollyMemcpy.h +23 -0
- package/external/folly/folly/FollyMemset.cpp +29 -0
- package/external/folly/folly/FollyMemset.h +25 -0
- package/external/folly/folly/Format-inl.h +1152 -0
- package/external/folly/folly/Format.cpp +429 -0
- package/external/folly/folly/Format.h +463 -0
- package/external/folly/folly/FormatArg.h +285 -0
- package/external/folly/folly/FormatTraits.h +65 -0
- package/external/folly/folly/Function.h +1159 -0
- package/external/folly/folly/GLog.h +85 -0
- package/external/folly/folly/GroupVarint.cpp +153 -0
- package/external/folly/folly/GroupVarint.h +630 -0
- package/external/folly/folly/Hash.h +20 -0
- package/external/folly/folly/IPAddress.cpp +490 -0
- package/external/folly/folly/IPAddress.h +667 -0
- package/external/folly/folly/IPAddressException.h +82 -0
- package/external/folly/folly/IPAddressV4.cpp +305 -0
- package/external/folly/folly/IPAddressV4.h +495 -0
- package/external/folly/folly/IPAddressV6.cpp +541 -0
- package/external/folly/folly/IPAddressV6.h +627 -0
- package/external/folly/folly/Indestructible.h +164 -0
- package/external/folly/folly/IndexedMemPool.h +550 -0
- package/external/folly/folly/IntrusiveList.h +17 -0
- package/external/folly/folly/Lazy.h +142 -0
- package/external/folly/folly/Likely.h +76 -0
- package/external/folly/folly/MPMCPipeline.h +280 -0
- package/external/folly/folly/MPMCQueue.h +1556 -0
- package/external/folly/folly/MacAddress.cpp +188 -0
- package/external/folly/folly/MacAddress.h +260 -0
- package/external/folly/folly/MapUtil.h +17 -0
- package/external/folly/folly/Math.h +258 -0
- package/external/folly/folly/MaybeManagedPtr.h +120 -0
- package/external/folly/folly/Memory.h +900 -0
- package/external/folly/folly/MicroLock.cpp +76 -0
- package/external/folly/folly/MicroLock.h +354 -0
- package/external/folly/folly/MicroSpinLock.h +17 -0
- package/external/folly/folly/MoveWrapper.h +76 -0
- package/external/folly/folly/ObserverContainer.h +1026 -0
- package/external/folly/folly/Optional.h +743 -0
- package/external/folly/folly/Overload.h +325 -0
- package/external/folly/folly/PackedSyncPtr.h +147 -0
- package/external/folly/folly/Padded.h +464 -0
- package/external/folly/folly/Poly-inl.h +230 -0
- package/external/folly/folly/Poly.h +1095 -0
- package/external/folly/folly/PolyException.h +43 -0
- package/external/folly/folly/Portability.h +644 -0
- package/external/folly/folly/Preprocessor.h +236 -0
- package/external/folly/folly/ProducerConsumerQueue.h +182 -0
- package/external/folly/folly/RWSpinLock.h +17 -0
- package/external/folly/folly/Random-inl.h +86 -0
- package/external/folly/folly/Random.cpp +184 -0
- package/external/folly/folly/Random.h +434 -0
- package/external/folly/folly/Range.h +1772 -0
- package/external/folly/folly/Replaceable.h +636 -0
- package/external/folly/folly/ScopeGuard.cpp +29 -0
- package/external/folly/folly/ScopeGuard.h +420 -0
- package/external/folly/folly/SharedMutex.cpp +81 -0
- package/external/folly/folly/SharedMutex.h +1751 -0
- package/external/folly/folly/Singleton-inl.h +332 -0
- package/external/folly/folly/Singleton.cpp +512 -0
- package/external/folly/folly/Singleton.h +891 -0
- package/external/folly/folly/SingletonThreadLocal.cpp +53 -0
- package/external/folly/folly/SingletonThreadLocal.h +263 -0
- package/external/folly/folly/SocketAddress.cpp +786 -0
- package/external/folly/folly/SocketAddress.h +768 -0
- package/external/folly/folly/SpinLock.h +55 -0
- package/external/folly/folly/String-inl.h +668 -0
- package/external/folly/folly/String.cpp +777 -0
- package/external/folly/folly/String.h +767 -0
- package/external/folly/folly/Subprocess.cpp +1142 -0
- package/external/folly/folly/Subprocess.h +1055 -0
- package/external/folly/folly/Synchronized.h +1833 -0
- package/external/folly/folly/SynchronizedPtr.h +106 -0
- package/external/folly/folly/ThreadCachedInt.h +175 -0
- package/external/folly/folly/ThreadLocal.h +478 -0
- package/external/folly/folly/TimeoutQueue.cpp +78 -0
- package/external/folly/folly/TimeoutQueue.h +123 -0
- package/external/folly/folly/TokenBucket.h +673 -0
- package/external/folly/folly/Traits.h +1442 -0
- package/external/folly/folly/Try-inl.h +372 -0
- package/external/folly/folly/Try.cpp +23 -0
- package/external/folly/folly/Try.h +728 -0
- package/external/folly/folly/UTF8String.h +56 -0
- package/external/folly/folly/Unicode.cpp +201 -0
- package/external/folly/folly/Unicode.h +94 -0
- package/external/folly/folly/Unit.h +65 -0
- package/external/folly/folly/Uri-inl.h +101 -0
- package/external/folly/folly/Uri.cpp +190 -0
- package/external/folly/folly/Uri.h +142 -0
- package/external/folly/folly/Utility.h +932 -0
- package/external/folly/folly/VERSION +1 -0
- package/external/folly/folly/Varint.h +230 -0
- package/external/folly/folly/VirtualExecutor.h +17 -0
- package/external/folly/folly/algorithm/simd/BUCK +47 -0
- package/external/folly/folly/algorithm/simd/Contains.cpp +42 -0
- package/external/folly/folly/algorithm/simd/Contains.h +116 -0
- package/external/folly/folly/algorithm/simd/FindFixed.h +301 -0
- package/external/folly/folly/algorithm/simd/Ignore.h +52 -0
- package/external/folly/folly/algorithm/simd/Movemask.h +207 -0
- package/external/folly/folly/algorithm/simd/detail/BUCK +70 -0
- package/external/folly/folly/algorithm/simd/detail/ContainsImpl.h +91 -0
- package/external/folly/folly/algorithm/simd/detail/SimdAnyOf.h +83 -0
- package/external/folly/folly/algorithm/simd/detail/SimdForEach.h +209 -0
- package/external/folly/folly/algorithm/simd/detail/SimdPlatform.h +445 -0
- package/external/folly/folly/algorithm/simd/detail/Traits.h +125 -0
- package/external/folly/folly/algorithm/simd/detail/UnrollUtils.h +126 -0
- package/external/folly/folly/base64.h +264 -0
- package/external/folly/folly/chrono/BUCK +29 -0
- package/external/folly/folly/chrono/Clock.h +65 -0
- package/external/folly/folly/chrono/Conv.h +712 -0
- package/external/folly/folly/chrono/test/BUCK +26 -0
- package/external/folly/folly/chrono/test/ClockTest.cpp +68 -0
- package/external/folly/folly/chrono/test/ConvTest.cpp +652 -0
- package/external/folly/folly/concurrency/AtomicSharedPtr.h +387 -0
- package/external/folly/folly/concurrency/BUCK +170 -0
- package/external/folly/folly/concurrency/CacheLocality.h +460 -0
- package/external/folly/folly/concurrency/ConcurrentHashMap.h +822 -0
- package/external/folly/folly/concurrency/CoreCachedSharedPtr.h +232 -0
- package/external/folly/folly/concurrency/DeadlockDetector.cpp +27 -0
- package/external/folly/folly/concurrency/DeadlockDetector.h +44 -0
- package/external/folly/folly/concurrency/DynamicBoundedQueue.h +751 -0
- package/external/folly/folly/concurrency/PriorityUnboundedQueueSet.h +207 -0
- package/external/folly/folly/concurrency/ProcessLocalUniqueId.cpp +46 -0
- package/external/folly/folly/concurrency/ProcessLocalUniqueId.h +38 -0
- package/external/folly/folly/concurrency/SingletonRelaxedCounter.h +325 -0
- package/external/folly/folly/concurrency/ThreadCachedSynchronized.h +227 -0
- package/external/folly/folly/concurrency/UnboundedQueue.h +891 -0
- package/external/folly/folly/concurrency/container/BUCK +77 -0
- package/external/folly/folly/concurrency/container/FlatCombiningPriorityQueue.h +426 -0
- package/external/folly/folly/concurrency/container/LockFreeRingBuffer.h +306 -0
- package/external/folly/folly/concurrency/container/RelaxedConcurrentPriorityQueue.h +1212 -0
- package/external/folly/folly/concurrency/container/SingleWriterFixedHashMap.h +322 -0
- package/external/folly/folly/concurrency/container/atomic_grow_array.h +564 -0
- package/external/folly/folly/concurrency/container/test/BUCK +75 -0
- package/external/folly/folly/concurrency/container/test/FlatCombiningPriorityQueueTest.cpp +570 -0
- package/external/folly/folly/concurrency/container/test/LockFreeRingBufferTest.cpp +276 -0
- package/external/folly/folly/concurrency/container/test/RelaxedConcurrentPriorityQueueTest.cpp +1570 -0
- package/external/folly/folly/concurrency/container/test/SingleWriterFixedHashMapTest.cpp +401 -0
- package/external/folly/folly/concurrency/container/test/atomic_grow_array_test.cpp +187 -0
- package/external/folly/folly/concurrency/detail/AtomicSharedPtr-detail.h +212 -0
- package/external/folly/folly/concurrency/detail/ConcurrentHashMap-detail.h +1911 -0
- package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.cpp +43 -0
- package/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.h +190 -0
- package/external/folly/folly/concurrency/memory/BUCK +53 -0
- package/external/folly/folly/concurrency/memory/PrimaryPtr.h +338 -0
- package/external/folly/folly/concurrency/memory/ReadMostlySharedPtr.h +511 -0
- package/external/folly/folly/concurrency/memory/TLRefCount.h +228 -0
- package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrBenchmark.cpp +56 -0
- package/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrTest.cpp +454 -0
- package/external/folly/folly/concurrency/memory/test/BUCK +95 -0
- package/external/folly/folly/concurrency/memory/test/PrimaryPtrTest.cpp +303 -0
- package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrBenchmark.cpp +138 -0
- package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrStressTest.cpp +75 -0
- package/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrTest.cpp +378 -0
- package/external/folly/folly/concurrency/memory/test/RefCountBenchmark.cpp +90 -0
- package/external/folly/folly/concurrency/memory/test/RefCountTest.cpp +168 -0
- package/external/folly/folly/concurrency/test/AtomicSharedPtrCounted.h +156 -0
- package/external/folly/folly/concurrency/test/AtomicSharedPtrPerformance.cpp +255 -0
- package/external/folly/folly/concurrency/test/AtomicSharedPtrTest.cpp +257 -0
- package/external/folly/folly/concurrency/test/BUCK +229 -0
- package/external/folly/folly/concurrency/test/CacheLocalityBenchmark.cpp +392 -0
- package/external/folly/folly/concurrency/test/CacheLocalityTest.cpp +1229 -0
- package/external/folly/folly/concurrency/test/ConcurrentHashMapBench.cpp +260 -0
- package/external/folly/folly/concurrency/test/ConcurrentHashMapTest.cpp +1242 -0
- package/external/folly/folly/concurrency/test/CoreCachedSharedPtrTest.cpp +408 -0
- package/external/folly/folly/concurrency/test/DynamicBoundedQueueTest.cpp +984 -0
- package/external/folly/folly/concurrency/test/PriorityUnboundedQueueSetTest.cpp +73 -0
- package/external/folly/folly/concurrency/test/ProcessLocalUniqueIdTest.cpp +66 -0
- package/external/folly/folly/concurrency/test/SingletonRelaxedCounterBench.cpp +101 -0
- package/external/folly/folly/concurrency/test/SingletonRelaxedCounterTest.cpp +185 -0
- package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedBench.cpp +76 -0
- package/external/folly/folly/concurrency/test/ThreadCachedSynchronizedTest.cpp +93 -0
- package/external/folly/folly/concurrency/test/UnboundedQueueTest.cpp +1302 -0
- package/external/folly/folly/container/Access.h +57 -0
- package/external/folly/folly/container/Array.h +87 -0
- package/external/folly/folly/container/BUCK +353 -0
- package/external/folly/folly/container/BitIterator.h +203 -0
- package/external/folly/folly/container/Enumerate.h +162 -0
- package/external/folly/folly/container/EvictingCacheMap.h +730 -0
- package/external/folly/folly/container/F14.md +300 -0
- package/external/folly/folly/container/F14Map-fwd.h +113 -0
- package/external/folly/folly/container/F14Map.h +2108 -0
- package/external/folly/folly/container/F14Set-fwd.h +95 -0
- package/external/folly/folly/container/F14Set.h +1603 -0
- package/external/folly/folly/container/FBVector.h +1711 -0
- package/external/folly/folly/container/Foreach-inl.h +316 -0
- package/external/folly/folly/container/Foreach.h +209 -0
- package/external/folly/folly/container/HeterogeneousAccess-fwd.h +33 -0
- package/external/folly/folly/container/HeterogeneousAccess.h +171 -0
- package/external/folly/folly/container/IntrusiveHeap.h +268 -0
- package/external/folly/folly/container/IntrusiveList.h +131 -0
- package/external/folly/folly/container/Iterator.h +843 -0
- package/external/folly/folly/container/MapUtil.h +376 -0
- package/external/folly/folly/container/Merge.h +90 -0
- package/external/folly/folly/container/RegexMatchCache.cpp +521 -0
- package/external/folly/folly/container/RegexMatchCache.h +699 -0
- package/external/folly/folly/container/Reserve.h +109 -0
- package/external/folly/folly/container/SparseByteSet.h +123 -0
- package/external/folly/folly/container/View.h +81 -0
- package/external/folly/folly/container/WeightedEvictingCacheMap.h +651 -0
- package/external/folly/folly/container/detail/BUCK +115 -0
- package/external/folly/folly/container/detail/BitIteratorDetail.h +87 -0
- package/external/folly/folly/container/detail/F14Defaults.h +34 -0
- package/external/folly/folly/container/detail/F14IntrinsicsAvailability.h +67 -0
- package/external/folly/folly/container/detail/F14MapFallback.h +717 -0
- package/external/folly/folly/container/detail/F14Mask.h +235 -0
- package/external/folly/folly/container/detail/F14Policy.h +1523 -0
- package/external/folly/folly/container/detail/F14SetFallback.h +528 -0
- package/external/folly/folly/container/detail/F14Table.cpp +71 -0
- package/external/folly/folly/container/detail/F14Table.h +2680 -0
- package/external/folly/folly/container/detail/Util.h +303 -0
- package/external/folly/folly/container/detail/tape_detail.h +135 -0
- package/external/folly/folly/container/detail/test/BUCK +14 -0
- package/external/folly/folly/container/detail/test/F14DetailTest.cpp +47 -0
- package/external/folly/folly/container/heap_vector_types.h +1683 -0
- package/external/folly/folly/container/range_traits.h +81 -0
- package/external/folly/folly/container/small_vector.h +1476 -0
- package/external/folly/folly/container/sorted_vector_types.h +1652 -0
- package/external/folly/folly/container/span.h +408 -0
- package/external/folly/folly/container/tape.h +608 -0
- package/external/folly/folly/container/test/.clang-tidy +12 -0
- package/external/folly/folly/container/test/AccessTest.cpp +138 -0
- package/external/folly/folly/container/test/ArrayTest.cpp +84 -0
- package/external/folly/folly/container/test/BUCK +568 -0
- package/external/folly/folly/container/test/BitIteratorBench.cpp +112 -0
- package/external/folly/folly/container/test/BitIteratorTest.cpp +109 -0
- package/external/folly/folly/container/test/EnumerateTest.cpp +294 -0
- package/external/folly/folly/container/test/EvictingCacheMapBench.cpp +80 -0
- package/external/folly/folly/container/test/EvictingCacheMapTest.cpp +842 -0
- package/external/folly/folly/container/test/F14AsanSupportTest.cpp +143 -0
- package/external/folly/folly/container/test/F14FwdTest.cpp +37 -0
- package/external/folly/folly/container/test/F14InterprocessTest.cpp +404 -0
- package/external/folly/folly/container/test/F14MapTest.cpp +2543 -0
- package/external/folly/folly/container/test/F14PolicyTest.cpp +49 -0
- package/external/folly/folly/container/test/F14SetTest.cpp +1738 -0
- package/external/folly/folly/container/test/F14SmallOverheads.cpp +215 -0
- package/external/folly/folly/container/test/F14TestUtil.h +117 -0
- package/external/folly/folly/container/test/FBVectorBenchmark.cpp +380 -0
- package/external/folly/folly/container/test/FBVectorBenchmarks.cpp.h +100 -0
- package/external/folly/folly/container/test/FBVectorTest.cpp +326 -0
- package/external/folly/folly/container/test/FBVectorTests.cpp.h +304 -0
- package/external/folly/folly/container/test/ForeachBenchmark.cpp +388 -0
- package/external/folly/folly/container/test/ForeachTest.cpp +338 -0
- package/external/folly/folly/container/test/HashMapsBench.cpp +458 -0
- package/external/folly/folly/container/test/HeterogeneousAccessTest.cpp +242 -0
- package/external/folly/folly/container/test/IntrusiveHeapTest.cpp +262 -0
- package/external/folly/folly/container/test/IteratorTest.cpp +989 -0
- package/external/folly/folly/container/test/MapUtilTest.cpp +365 -0
- package/external/folly/folly/container/test/MergeTest.cpp +66 -0
- package/external/folly/folly/container/test/RegexMatchCacheTest.cpp +634 -0
- package/external/folly/folly/container/test/ReserveTest.cpp +173 -0
- package/external/folly/folly/container/test/SparseByteSetBenchmark.cpp +153 -0
- package/external/folly/folly/container/test/SparseByteSetTest.cpp +117 -0
- package/external/folly/folly/container/test/TrackingTypes.h +584 -0
- package/external/folly/folly/container/test/UtilTest.cpp +609 -0
- package/external/folly/folly/container/test/WeightedEvictingCacheMapTest.cpp +800 -0
- package/external/folly/folly/container/test/heap_vector_types_test.cpp +1774 -0
- package/external/folly/folly/container/test/range_traits_test.cpp +59 -0
- package/external/folly/folly/container/test/small_vector_test.cpp +1571 -0
- package/external/folly/folly/container/test/sorted_vector_test.cpp +1589 -0
- package/external/folly/folly/container/test/span_test.cpp +520 -0
- package/external/folly/folly/container/test/tape_bench.cpp +200 -0
- package/external/folly/folly/container/test/tape_test.cpp +590 -0
- package/external/folly/folly/defs.bzl +238 -0
- package/external/folly/folly/detail/AsyncTrace.cpp +36 -0
- package/external/folly/folly/detail/AsyncTrace.h +44 -0
- package/external/folly/folly/detail/AtomicHashUtils.h +42 -0
- package/external/folly/folly/detail/AtomicUnorderedMapUtils.h +80 -0
- package/external/folly/folly/detail/BUCK +406 -0
- package/external/folly/folly/detail/DiscriminatedPtrDetail.h +172 -0
- package/external/folly/folly/detail/FileUtilDetail.cpp +63 -0
- package/external/folly/folly/detail/FileUtilDetail.h +85 -0
- package/external/folly/folly/detail/FileUtilVectorDetail.h +81 -0
- package/external/folly/folly/detail/FingerprintPolynomial.h +132 -0
- package/external/folly/folly/detail/Futex-inl.h +123 -0
- package/external/folly/folly/detail/Futex.cpp +273 -0
- package/external/folly/folly/detail/Futex.h +109 -0
- package/external/folly/folly/detail/GroupVarintDetail.h +101 -0
- package/external/folly/folly/detail/IPAddress.cpp +37 -0
- package/external/folly/folly/detail/IPAddress.h +57 -0
- package/external/folly/folly/detail/IPAddressSource.h +278 -0
- package/external/folly/folly/detail/Iterators.h +156 -0
- package/external/folly/folly/detail/MPMCPipelineDetail.h +122 -0
- package/external/folly/folly/detail/MemoryIdler.cpp +233 -0
- package/external/folly/folly/detail/MemoryIdler.h +216 -0
- package/external/folly/folly/detail/PerfScoped.cpp +112 -0
- package/external/folly/folly/detail/PerfScoped.h +70 -0
- package/external/folly/folly/detail/PolyDetail.h +921 -0
- package/external/folly/folly/detail/RangeCommon.cpp +55 -0
- package/external/folly/folly/detail/RangeCommon.h +93 -0
- package/external/folly/folly/detail/RangeSse42.cpp +198 -0
- package/external/folly/folly/detail/RangeSse42.h +30 -0
- package/external/folly/folly/detail/SimpleSimdStringUtils.cpp +31 -0
- package/external/folly/folly/detail/SimpleSimdStringUtils.h +27 -0
- package/external/folly/folly/detail/SimpleSimdStringUtilsImpl.h +63 -0
- package/external/folly/folly/detail/Singleton.h +34 -0
- package/external/folly/folly/detail/SlowFingerprint.h +90 -0
- package/external/folly/folly/detail/SocketFastOpen.cpp +175 -0
- package/external/folly/folly/detail/SocketFastOpen.h +89 -0
- package/external/folly/folly/detail/SplitStringSimd.cpp +84 -0
- package/external/folly/folly/detail/SplitStringSimd.h +151 -0
- package/external/folly/folly/detail/SplitStringSimdImpl.h +149 -0
- package/external/folly/folly/detail/Sse.cpp +35 -0
- package/external/folly/folly/detail/Sse.h +45 -0
- package/external/folly/folly/detail/StaticSingletonManager.cpp +119 -0
- package/external/folly/folly/detail/StaticSingletonManager.h +298 -0
- package/external/folly/folly/detail/ThreadLocalDetail.cpp +492 -0
- package/external/folly/folly/detail/ThreadLocalDetail.h +800 -0
- package/external/folly/folly/detail/TrapOnAvx512.cpp +41 -0
- package/external/folly/folly/detail/TrapOnAvx512.h +21 -0
- package/external/folly/folly/detail/TurnSequencer.h +295 -0
- package/external/folly/folly/detail/TypeList.h +551 -0
- package/external/folly/folly/detail/UniqueInstance.cpp +136 -0
- package/external/folly/folly/detail/UniqueInstance.h +68 -0
- package/external/folly/folly/detail/base64_detail/BUCK +102 -0
- package/external/folly/folly/detail/base64_detail/Base64Api.cpp +40 -0
- package/external/folly/folly/detail/base64_detail/Base64Api.h +101 -0
- package/external/folly/folly/detail/base64_detail/Base64Common.h +80 -0
- package/external/folly/folly/detail/base64_detail/Base64Constants.h +79 -0
- package/external/folly/folly/detail/base64_detail/Base64HiddenConstants.h +129 -0
- package/external/folly/folly/detail/base64_detail/Base64SWAR.cpp +161 -0
- package/external/folly/folly/detail/base64_detail/Base64SWAR.h +32 -0
- package/external/folly/folly/detail/base64_detail/Base64Scalar.h +262 -0
- package/external/folly/folly/detail/base64_detail/Base64Simd.h +102 -0
- package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.cpp +42 -0
- package/external/folly/folly/detail/base64_detail/Base64_SSE4_2.h +33 -0
- package/external/folly/folly/detail/base64_detail/Base64_SSE4_2_Platform.h +167 -0
- package/external/folly/folly/detail/base64_detail/README.md +392 -0
- package/external/folly/folly/detail/base64_detail/tests/BUCK +36 -0
- package/external/folly/folly/detail/base64_detail/tests/Base64AgainstScalarTest.cpp +141 -0
- package/external/folly/folly/detail/base64_detail/tests/Base64PlatformTest.cpp +273 -0
- package/external/folly/folly/detail/base64_detail/tests/Base64SpecialCasesTest.cpp +555 -0
- package/external/folly/folly/detail/test/AsyncTraceTest.cpp +43 -0
- package/external/folly/folly/detail/test/BUCK +118 -0
- package/external/folly/folly/detail/test/FileUtilDetailTest.cpp +56 -0
- package/external/folly/folly/detail/test/PerfScopedTest.cpp +107 -0
- package/external/folly/folly/detail/test/SimpleSimdStringUtilsTest.cpp +92 -0
- package/external/folly/folly/detail/test/SplitStringSimdTest.cpp +242 -0
- package/external/folly/folly/detail/test/StaticSingletonManagerTest.cpp +121 -0
- package/external/folly/folly/detail/test/ThreadLocalBenchmark.cpp +116 -0
- package/external/folly/folly/detail/test/ThreadLocalDetailTest.cpp +194 -0
- package/external/folly/folly/detail/test/TrapOnAvx512TestNegative.cpp +29 -0
- package/external/folly/folly/detail/test/UniqueInstanceTest.cpp +60 -0
- package/external/folly/folly/detail/thread_local_globals.cpp +69 -0
- package/external/folly/folly/detail/thread_local_globals.h +36 -0
- package/external/folly/folly/docs/AtomicHashMap.md +134 -0
- package/external/folly/folly/docs/Benchmark.md +310 -0
- package/external/folly/folly/docs/Conv.md +291 -0
- package/external/folly/folly/docs/Dynamic.md +220 -0
- package/external/folly/folly/docs/DynamicConverter.md +71 -0
- package/external/folly/folly/docs/Executors.md +63 -0
- package/external/folly/folly/docs/FBString.md +46 -0
- package/external/folly/folly/docs/FBVector.md +200 -0
- package/external/folly/folly/docs/Fbvector--graphical_solutions.png +0 -0
- package/external/folly/folly/docs/Format.md +177 -0
- package/external/folly/folly/docs/Function.md +92 -0
- package/external/folly/folly/docs/Futures.md +263 -0
- package/external/folly/folly/docs/GroupVarint.md +46 -0
- package/external/folly/folly/docs/Histogram.md +104 -0
- package/external/folly/folly/docs/MapUtils.md +80 -0
- package/external/folly/folly/docs/Overview.md +263 -0
- package/external/folly/folly/docs/PackedSyncPtr.md +77 -0
- package/external/folly/folly/docs/Poly.md +500 -0
- package/external/folly/folly/docs/ProducerConsumerQueue.md +82 -0
- package/external/folly/folly/docs/Rcu.md +218 -0
- package/external/folly/folly/docs/SmallLocks.md +24 -0
- package/external/folly/folly/docs/Synchronized.md +793 -0
- package/external/folly/folly/docs/ThreadCachedInt.md +98 -0
- package/external/folly/folly/docs/ThreadLocal.md +105 -0
- package/external/folly/folly/docs/Traits.md +161 -0
- package/external/folly/folly/docs/small_vector.md +64 -0
- package/external/folly/folly/docs/style.css +23 -0
- package/external/folly/folly/dynamic-inl.h +17 -0
- package/external/folly/folly/dynamic.h +17 -0
- package/external/folly/folly/folly_extended_library.bzl +28 -0
- package/external/folly/folly/functional/ApplyTuple.h +204 -0
- package/external/folly/folly/functional/BUCK +57 -0
- package/external/folly/folly/functional/Invoke.h +880 -0
- package/external/folly/folly/functional/Partial.h +130 -0
- package/external/folly/folly/functional/protocol.h +203 -0
- package/external/folly/folly/functional/test/ApplyTupleTest.cpp +549 -0
- package/external/folly/folly/functional/test/BUCK +57 -0
- package/external/folly/folly/functional/test/InvokeTest.cpp +483 -0
- package/external/folly/folly/functional/test/PartialTest.cpp +141 -0
- package/external/folly/folly/functional/test/protocol_test.cpp +177 -0
- package/external/folly/folly/functional/test/traits_test.cpp +551 -0
- package/external/folly/folly/functional/traits.h +675 -0
- package/external/folly/folly/hash/BUCK +86 -0
- package/external/folly/folly/hash/Checksum.cpp +275 -0
- package/external/folly/folly/hash/Checksum.h +94 -0
- package/external/folly/folly/hash/FarmHash.h +46 -0
- package/external/folly/folly/hash/Hash.h +1045 -0
- package/external/folly/folly/hash/MurmurHash.h +86 -0
- package/external/folly/folly/hash/SpookyHashV1.cpp +391 -0
- package/external/folly/folly/hash/SpookyHashV1.h +307 -0
- package/external/folly/folly/hash/SpookyHashV2.cpp +392 -0
- package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/hash/SpookyHashV2.h +6 -1
- package/external/folly/folly/hash/detail/BUCK +26 -0
- package/external/folly/folly/hash/detail/ChecksumDetail.cpp +296 -0
- package/external/folly/folly/hash/detail/ChecksumDetail.h +137 -0
- package/external/folly/folly/hash/detail/Crc32CombineDetail.cpp +191 -0
- package/external/folly/folly/hash/detail/Crc32cDetail.cpp +303 -0
- package/external/folly/folly/hash/test/BUCK +132 -0
- package/external/folly/folly/hash/test/ChecksumBenchmark.cpp +91 -0
- package/external/folly/folly/hash/test/ChecksumTest.cpp +587 -0
- package/external/folly/folly/hash/test/FarmHashTest.cpp +41 -0
- package/external/folly/folly/hash/test/HashBenchmark.cpp +238 -0
- package/external/folly/folly/hash/test/HashTest.cpp +997 -0
- package/external/folly/folly/hash/test/MurmurHashTest.cpp +76 -0
- package/external/folly/folly/hash/test/SpookyHashV1Test.cpp +559 -0
- package/external/folly/folly/hash/test/SpookyHashV2Test.cpp +549 -0
- package/external/folly/folly/hash/test/traits_test.cpp +69 -0
- package/external/folly/folly/hash/traits.h +115 -0
- package/external/folly/folly/json/BUCK +155 -0
- package/external/folly/folly/json/DynamicConverter.h +464 -0
- package/external/folly/folly/json/DynamicParser-inl.h +316 -0
- package/external/folly/folly/json/DynamicParser.cpp +198 -0
- package/external/folly/folly/json/DynamicParser.h +394 -0
- package/external/folly/folly/json/JSONSchema.cpp +1030 -0
- package/external/folly/folly/json/JSONSchema.h +73 -0
- package/external/folly/folly/json/JsonMockUtil.h +73 -0
- package/external/folly/folly/json/JsonTestUtil.cpp +167 -0
- package/external/folly/folly/json/JsonTestUtil.h +88 -0
- package/external/folly/folly/json/bser/BUCK +24 -0
- package/external/folly/folly/json/bser/Bser.h +107 -0
- package/external/folly/folly/json/bser/Dump.cpp +253 -0
- package/external/folly/folly/json/bser/Load.cpp +246 -0
- package/external/folly/folly/json/bser/test/BUCK +14 -0
- package/external/folly/folly/json/bser/test/BserTest.cpp +149 -0
- package/external/folly/folly/json/dynamic.cpp +552 -0
- package/external/folly/folly/json/dynamic.h +1346 -0
- package/external/folly/folly/json/json.h +238 -0
- package/external/folly/folly/json/json_patch.cpp +325 -0
- package/external/folly/folly/json/json_patch.h +126 -0
- package/external/folly/folly/json/json_pointer.cpp +114 -0
- package/external/folly/folly/json/json_pointer.h +87 -0
- package/external/folly/folly/json/test/BUCK +147 -0
- package/external/folly/folly/json/test/DynamicBenchmark.cpp +146 -0
- package/external/folly/folly/json/test/DynamicConverterTest.cpp +518 -0
- package/external/folly/folly/json/test/DynamicOtherTest.cpp +344 -0
- package/external/folly/folly/json/test/DynamicParserTest.cpp +443 -0
- package/external/folly/folly/json/test/DynamicTest.cpp +1647 -0
- package/external/folly/folly/json/test/JSONSchemaTest.cpp +450 -0
- package/external/folly/folly/json/test/JsonBenchmark.cpp +264 -0
- package/external/folly/folly/json/test/JsonOtherTest.cpp +51 -0
- package/external/folly/folly/json/test/JsonTest.cpp +1153 -0
- package/external/folly/folly/json/test/JsonTestUtilTest.cpp +97 -0
- package/external/folly/folly/json/test/json_patch_test.cpp +361 -0
- package/external/folly/folly/json/test/json_pointer_test.cpp +58 -0
- package/external/folly/folly/json/tool/BUCK +13 -0
- package/external/folly/folly/json/tool/JSONSchemaTester.cpp +58 -0
- package/external/folly/folly/json.h +17 -0
- package/external/folly/folly/json_patch.h +17 -0
- package/external/folly/folly/json_pointer.h +17 -0
- package/external/folly/folly/lang/Access.h +29 -0
- package/external/folly/folly/lang/Align.h +240 -0
- package/external/folly/folly/lang/Aligned.h +92 -0
- package/external/folly/folly/lang/Assume.h +82 -0
- package/external/folly/folly/lang/BUCK +287 -0
- package/external/folly/folly/lang/Badge.h +108 -0
- package/external/folly/folly/lang/Bits.h +570 -0
- package/external/folly/folly/lang/BitsClass.h +312 -0
- package/external/folly/folly/lang/Builtin.h +74 -0
- package/external/folly/folly/lang/CArray.h +34 -0
- package/external/folly/folly/lang/CString.cpp +86 -0
- package/external/folly/folly/lang/CString.h +55 -0
- package/external/folly/folly/lang/Cast.h +51 -0
- package/external/folly/folly/lang/CheckedMath.h +253 -0
- package/external/folly/folly/lang/CustomizationPoint.h +58 -0
- package/external/folly/folly/lang/Exception.cpp +822 -0
- package/external/folly/folly/lang/Exception.h +716 -0
- package/external/folly/folly/lang/Extern.h +55 -0
- package/external/folly/folly/lang/Hint-inl.h +144 -0
- package/external/folly/folly/lang/Hint.h +238 -0
- package/external/folly/folly/lang/Keep.h +98 -0
- package/external/folly/folly/lang/New.h +124 -0
- package/external/folly/folly/lang/Ordering.h +140 -0
- package/external/folly/folly/lang/Pretty.h +159 -0
- package/external/folly/folly/lang/PropagateConst.h +413 -0
- package/external/folly/folly/lang/RValueReferenceWrapper.h +152 -0
- package/external/folly/folly/lang/SafeAssert.cpp +589 -0
- package/external/folly/folly/lang/StaticConst.h +33 -0
- package/external/folly/folly/lang/Thunk.h +100 -0
- package/external/folly/folly/lang/TypeInfo.h +58 -0
- package/external/folly/folly/lang/UncaughtExceptions.cpp +17 -0
- package/external/folly/folly/lang/UncaughtExceptions.h +19 -0
- package/external/folly/folly/lang/test/AlignTest.cpp +87 -0
- package/external/folly/folly/lang/test/AlignedTest.cpp +130 -0
- package/external/folly/folly/lang/test/BUCK +258 -0
- package/external/folly/folly/lang/test/BadgeTest.cpp +89 -0
- package/external/folly/folly/lang/test/BitsBenchmark.cpp +164 -0
- package/external/folly/folly/lang/test/BitsClassBenchmark.cpp +122 -0
- package/external/folly/folly/lang/test/BitsClassTest.cpp +379 -0
- package/external/folly/folly/lang/test/BitsTest.cpp +577 -0
- package/external/folly/folly/lang/test/CStringTest.cpp +60 -0
- package/external/folly/folly/lang/test/CastTest.cpp +47 -0
- package/external/folly/folly/lang/test/CheckedMathTest.cpp +394 -0
- package/external/folly/folly/lang/test/ExceptionBench.cpp +427 -0
- package/external/folly/folly/lang/test/ExceptionTest.cpp +413 -0
- package/external/folly/folly/lang/test/ExternTest.cpp +39 -0
- package/external/folly/folly/lang/test/HintTest.cpp +100 -0
- package/external/folly/folly/lang/test/NewTest.cpp +38 -0
- package/external/folly/folly/lang/test/OrderingTest.cpp +105 -0
- package/external/folly/folly/lang/test/PrettyTest.cpp +44 -0
- package/external/folly/folly/lang/test/PropagateConstTest.cpp +356 -0
- package/external/folly/folly/lang/test/RValueReferenceWrapperTest.cpp +85 -0
- package/external/folly/folly/lang/test/SafeAssertTest.cpp +75 -0
- package/external/folly/folly/lang/test/ThunkTest.cpp +105 -0
- package/external/folly/folly/lang/test/ToAsciiBench.cpp +466 -0
- package/external/folly/folly/lang/test/ToAsciiTest.cpp +266 -0
- package/external/folly/folly/lang/test/TypeInfoTest.cpp +56 -0
- package/external/folly/folly/memcpy.S +292 -0
- package/external/folly/folly/memcpy_select_aarch64.cpp +145 -0
- package/external/folly/folly/memory/Arena-inl.h +83 -0
- package/external/folly/folly/memory/Arena.h +325 -0
- package/external/folly/folly/memory/BUCK +191 -0
- package/external/folly/folly/memory/JemallocHugePageAllocator.cpp +449 -0
- package/external/folly/folly/memory/JemallocHugePageAllocator.h +105 -0
- package/external/folly/folly/memory/JemallocHugePageAllocatorTest.cpp +341 -0
- package/external/folly/folly/memory/JemallocNodumpAllocator.cpp +176 -0
- package/external/folly/folly/memory/JemallocNodumpAllocator.h +119 -0
- package/external/folly/folly/memory/JemallocNodumpAllocatorTest.cpp +61 -0
- package/external/folly/folly/memory/MallctlHelper.cpp +37 -0
- package/external/folly/folly/memory/MallctlHelper.h +167 -0
- package/external/folly/folly/memory/Malloc.h +551 -0
- package/external/folly/folly/memory/MemoryResource.h +57 -0
- package/external/folly/folly/memory/ReentrantAllocator.cpp +162 -0
- package/external/folly/folly/memory/ReentrantAllocator.h +261 -0
- package/external/folly/folly/memory/SanitizeAddress.cpp +75 -0
- package/external/folly/folly/memory/SanitizeAddress.h +117 -0
- package/external/folly/folly/memory/SanitizeLeak.cpp +119 -0
- package/external/folly/folly/memory/SanitizeLeak.h +108 -0
- package/external/folly/folly/memory/ThreadCachedArena.cpp +53 -0
- package/external/folly/folly/memory/ThreadCachedArena.h +90 -0
- package/external/folly/folly/memory/UninitializedMemoryHacks.h +426 -0
- package/external/folly/folly/memory/detail/BUCK +10 -0
- package/external/folly/folly/memory/detail/MallocImpl.cpp +52 -0
- package/external/folly/folly/memory/detail/MallocImpl.h +97 -0
- package/external/folly/folly/memory/not_null-inl.h +522 -0
- package/external/folly/folly/memory/not_null.h +449 -0
- package/external/folly/folly/memory/test/ArenaTest.cpp +354 -0
- package/external/folly/folly/memory/test/BUCK +146 -0
- package/external/folly/folly/memory/test/MallctlHelperTest.cpp +169 -0
- package/external/folly/folly/memory/test/MallocBenchmark.cpp +91 -0
- package/external/folly/folly/memory/test/MallocTest.cpp +78 -0
- package/external/folly/folly/memory/test/MemoryResourceTest.cpp +31 -0
- package/external/folly/folly/memory/test/ReentrantAllocatorTest.cpp +144 -0
- package/external/folly/folly/memory/test/SanitizeAddressTest.cpp +67 -0
- package/external/folly/folly/memory/test/SanitizeLeakTest.cpp +139 -0
- package/external/folly/folly/memory/test/ThreadCachedArenaTest.cpp +276 -0
- package/external/folly/folly/memory/test/UninitializedMemoryHacksODR.cpp +21 -0
- package/external/folly/folly/memory/test/UninitializedMemoryHacksTest.cpp +327 -0
- package/external/folly/folly/memory/test/not_null_test.cpp +608 -0
- package/external/folly/folly/memset.S +245 -0
- package/external/folly/folly/memset_select_aarch64.cpp +72 -0
- package/external/folly/folly/portability/Asm.h +50 -0
- package/external/folly/folly/portability/Atomic.h +31 -0
- package/external/folly/folly/portability/BUCK +456 -0
- package/external/folly/folly/portability/Builtins.cpp +31 -0
- package/external/folly/folly/portability/Builtins.h +161 -0
- package/external/folly/folly/portability/Config.h +43 -0
- package/external/folly/folly/portability/Constexpr.h +145 -0
- package/external/folly/folly/portability/Dirent.cpp +140 -0
- package/external/folly/folly/portability/Dirent.h +41 -0
- package/external/folly/folly/portability/Event.h +44 -0
- package/external/folly/folly/portability/Fcntl.cpp +120 -0
- package/external/folly/folly/portability/Fcntl.h +67 -0
- package/external/folly/folly/portability/Filesystem.cpp +67 -0
- package/external/folly/folly/portability/Filesystem.h +114 -0
- package/external/folly/folly/portability/FmtCompile.h +40 -0
- package/external/folly/folly/portability/GFlags.h +139 -0
- package/external/folly/folly/portability/GMock.h +35 -0
- package/external/folly/folly/portability/GTest.h +35 -0
- package/external/folly/folly/portability/IOVec.h +34 -0
- package/external/folly/folly/portability/Libgen.cpp +59 -0
- package/external/folly/folly/portability/Libgen.h +29 -0
- package/external/folly/folly/portability/Libunwind.h +21 -0
- package/external/folly/folly/portability/Malloc.cpp +31 -0
- package/external/folly/folly/portability/Malloc.h +53 -0
- package/external/folly/folly/portability/Math.h +90 -0
- package/external/folly/folly/portability/Memory.h +26 -0
- package/external/folly/folly/portability/OpenSSL.cpp +17 -0
- package/external/folly/folly/portability/OpenSSL.h +102 -0
- package/external/folly/folly/portability/PThread.cpp +697 -0
- package/external/folly/folly/portability/PThread.h +148 -0
- package/external/folly/folly/portability/README.md +21 -0
- package/external/folly/folly/portability/Sched.cpp +41 -0
- package/external/folly/folly/portability/Sched.h +45 -0
- package/external/folly/folly/portability/Sockets.cpp +245 -0
- package/external/folly/folly/portability/Sockets.h +155 -0
- package/external/folly/folly/portability/SourceLocation.h +49 -0
- package/external/folly/folly/portability/Stdio.cpp +77 -0
- package/external/folly/folly/portability/Stdio.h +32 -0
- package/external/folly/folly/portability/Stdlib.cpp +172 -0
- package/external/folly/folly/portability/Stdlib.h +64 -0
- package/external/folly/folly/portability/String.cpp +53 -0
- package/external/folly/folly/portability/String.h +39 -0
- package/external/folly/folly/portability/SysFile.cpp +46 -0
- package/external/folly/folly/portability/SysFile.h +27 -0
- package/external/folly/folly/portability/SysMembarrier.cpp +104 -0
- package/external/folly/folly/portability/SysMembarrier.h +26 -0
- package/external/folly/folly/portability/SysMman.cpp +242 -0
- package/external/folly/folly/portability/SysMman.h +68 -0
- package/external/folly/folly/portability/SysResource.cpp +108 -0
- package/external/folly/folly/portability/SysResource.h +71 -0
- package/external/folly/folly/portability/SysStat.cpp +66 -0
- package/external/folly/folly/portability/SysStat.h +52 -0
- package/external/folly/folly/portability/SysSyscall.h +73 -0
- package/external/folly/folly/portability/SysTime.cpp +62 -0
- package/external/folly/folly/portability/SysTime.h +50 -0
- package/external/folly/folly/portability/SysTypes.h +44 -0
- package/external/folly/folly/portability/SysUio.cpp +179 -0
- package/external/folly/folly/portability/SysUio.h +51 -0
- package/external/folly/folly/portability/Syslog.h +39 -0
- package/external/folly/folly/portability/Time.cpp +357 -0
- package/external/folly/folly/portability/Time.h +74 -0
- package/external/folly/folly/portability/Unistd.h +111 -0
- package/external/folly/folly/portability/Windows.h +108 -0
- package/external/folly/folly/portability/openat2.c +30 -0
- package/external/folly/folly/portability/openat2.h +39 -0
- package/external/folly/folly/portability/test/BUCK +59 -0
- package/external/folly/folly/portability/test/ConstexprTest.cpp +102 -0
- package/external/folly/folly/portability/test/FilesystemTest.cpp +35 -0
- package/external/folly/folly/portability/test/LibgenTest.cpp +35 -0
- package/external/folly/folly/portability/test/OpenSSLPortabilityTest.cpp +108 -0
- package/external/folly/folly/portability/test/PThreadTest.cpp +80 -0
- package/external/folly/folly/portability/test/TimeTest.cpp +90 -0
- package/external/folly/folly/small_vector.h +17 -0
- package/external/folly/folly/somerge_defs.bzl +399 -0
- package/external/folly/folly/sorted_vector_types.h +17 -0
- package/external/folly/folly/stop_watch.h +317 -0
- package/external/folly/folly/synchronization/AsymmetricThreadFence.cpp +91 -0
- package/external/folly/folly/synchronization/AsymmetricThreadFence.h +60 -0
- package/external/folly/folly/synchronization/AtomicNotification-inl.h +146 -0
- package/external/folly/folly/synchronization/AtomicNotification.cpp +34 -0
- package/external/folly/folly/synchronization/AtomicNotification.h +117 -0
- package/external/folly/folly/synchronization/AtomicRef.h +181 -0
- package/external/folly/folly/synchronization/AtomicStruct.h +150 -0
- package/external/folly/folly/synchronization/AtomicUtil-inl.h +482 -0
- package/external/folly/folly/synchronization/AtomicUtil.h +179 -0
- package/external/folly/folly/synchronization/BUCK +418 -0
- package/external/folly/folly/synchronization/Baton.h +419 -0
- package/external/folly/folly/synchronization/CallOnce.h +263 -0
- package/external/folly/folly/synchronization/DelayedInit.h +179 -0
- package/external/folly/folly/synchronization/DistributedMutex-inl.h +1744 -0
- package/external/folly/folly/synchronization/DistributedMutex.cpp +27 -0
- package/external/folly/folly/synchronization/DistributedMutex.h +342 -0
- package/external/folly/folly/synchronization/EventCount.h +200 -0
- package/external/folly/folly/synchronization/FlatCombining.h +629 -0
- package/external/folly/folly/synchronization/Hazptr-fwd.h +217 -0
- package/external/folly/folly/synchronization/Hazptr.cpp +36 -0
- package/external/folly/folly/synchronization/Hazptr.h +209 -0
- package/external/folly/folly/synchronization/HazptrDomain.cpp +68 -0
- package/external/folly/folly/synchronization/HazptrDomain.h +832 -0
- package/external/folly/folly/synchronization/HazptrHolder.h +431 -0
- package/external/folly/folly/synchronization/HazptrObj.h +533 -0
- package/external/folly/folly/synchronization/HazptrObjLinked.h +315 -0
- package/external/folly/folly/synchronization/HazptrRec.h +68 -0
- package/external/folly/folly/synchronization/HazptrThrLocal.h +180 -0
- package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.cpp +46 -0
- package/external/folly/folly/synchronization/HazptrThreadPoolExecutor.h +25 -0
- package/external/folly/folly/synchronization/Latch.h +160 -0
- package/external/folly/folly/synchronization/LifoSem.h +767 -0
- package/external/folly/folly/synchronization/Lock.h +887 -0
- package/external/folly/folly/synchronization/MicroSpinLock.h +154 -0
- package/external/folly/folly/synchronization/NativeSemaphore.h +187 -0
- package/external/folly/folly/synchronization/ParkingLot.cpp +37 -0
- package/external/folly/folly/synchronization/ParkingLot.h +330 -0
- package/external/folly/folly/synchronization/PicoSpinLock.h +167 -0
- package/external/folly/folly/synchronization/RWSpinLock.h +549 -0
- package/external/folly/folly/synchronization/Rcu.cpp +26 -0
- package/external/folly/folly/synchronization/Rcu.h +553 -0
- package/external/folly/folly/synchronization/RelaxedAtomic.h +336 -0
- package/external/folly/folly/synchronization/SanitizeThread.cpp +141 -0
- package/external/folly/folly/synchronization/SanitizeThread.h +166 -0
- package/external/folly/folly/synchronization/SaturatingSemaphore.h +324 -0
- package/external/folly/folly/synchronization/SmallLocks.h +36 -0
- package/external/folly/folly/synchronization/ThrottledLifoSem.h +362 -0
- package/external/folly/folly/synchronization/WaitOptions.cpp +25 -0
- package/external/folly/folly/synchronization/WaitOptions.h +75 -0
- package/external/folly/folly/synchronization/detail/AtomicUtils.h +59 -0
- package/external/folly/folly/synchronization/detail/BUCK +104 -0
- package/external/folly/folly/synchronization/detail/Hardware.cpp +192 -0
- package/external/folly/folly/synchronization/detail/Hardware.h +75 -0
- package/external/folly/folly/synchronization/detail/HazptrUtils.h +339 -0
- package/external/folly/folly/synchronization/detail/InlineFunctionRef.h +229 -0
- package/external/folly/folly/synchronization/detail/Sleeper.cpp +27 -0
- package/external/folly/folly/synchronization/detail/Sleeper.h +62 -0
- package/external/folly/folly/synchronization/detail/Spin.h +96 -0
- package/external/folly/folly/synchronization/detail/ThreadCachedLists.h +174 -0
- package/external/folly/folly/synchronization/detail/ThreadCachedReaders.h +189 -0
- package/external/folly/folly/synchronization/detail/ThreadCachedTag.h +26 -0
- package/external/folly/folly/synchronization/detail/test/BUCK +28 -0
- package/external/folly/folly/synchronization/detail/test/HardwareTest.cpp +74 -0
- package/external/folly/folly/synchronization/detail/test/InlineFunctionRefTest.cpp +286 -0
- package/external/folly/folly/synchronization/example/BUCK +27 -0
- package/external/folly/folly/synchronization/example/HazptrLockFreeLIFO.h +88 -0
- package/external/folly/folly/synchronization/example/HazptrSWMRSet.h +133 -0
- package/external/folly/folly/synchronization/example/HazptrWideCAS.h +62 -0
- package/external/folly/folly/synchronization/test/AtomicNotificationTest.cpp +236 -0
- package/external/folly/folly/synchronization/test/AtomicRefTest.cpp +170 -0
- package/external/folly/folly/synchronization/test/AtomicStructTest.cpp +65 -0
- package/external/folly/folly/synchronization/test/AtomicUtilBench.cpp +457 -0
- package/external/folly/folly/synchronization/test/AtomicUtilTest.cpp +650 -0
- package/external/folly/folly/synchronization/test/BUCK +495 -0
- package/external/folly/folly/synchronization/test/Barrier.h +52 -0
- package/external/folly/folly/synchronization/test/BarrierTest.cpp +56 -0
- package/external/folly/folly/synchronization/test/BatonBenchmark.cpp +77 -0
- package/external/folly/folly/synchronization/test/BatonTest.cpp +164 -0
- package/external/folly/folly/synchronization/test/BatonTestHelpers.h +118 -0
- package/external/folly/folly/synchronization/test/CallOnceBenchmark.cpp +72 -0
- package/external/folly/folly/synchronization/test/CallOnceTest.cpp +153 -0
- package/external/folly/folly/synchronization/test/DelayedInitTest.cpp +281 -0
- package/external/folly/folly/synchronization/test/DistributedMutexTest.cpp +2074 -0
- package/external/folly/folly/synchronization/test/EventCountTest.cpp +124 -0
- package/external/folly/folly/synchronization/test/FlatCombiningBenchmark.cpp +1789 -0
- package/external/folly/folly/synchronization/test/FlatCombiningExamples.h +222 -0
- package/external/folly/folly/synchronization/test/FlatCombiningTest.cpp +121 -0
- package/external/folly/folly/synchronization/test/FlatCombiningTestHelpers.h +227 -0
- package/external/folly/folly/synchronization/test/HazptrTest.cpp +1689 -0
- package/external/folly/folly/synchronization/test/LatchTest.cpp +224 -0
- package/external/folly/folly/synchronization/test/LifoSemBench.cpp +185 -0
- package/external/folly/folly/synchronization/test/LifoSemTests.cpp +353 -0
- package/external/folly/folly/synchronization/test/LockTest.cpp +1239 -0
- package/external/folly/folly/synchronization/test/NativeSemaphoreTest.cpp +37 -0
- package/external/folly/folly/synchronization/test/ParkingLotBenchmark.cpp +239 -0
- package/external/folly/folly/synchronization/test/ParkingLotTest.cpp +170 -0
- package/external/folly/folly/synchronization/test/RWSpinLockTest.cpp +235 -0
- package/external/folly/folly/synchronization/test/RcuBench.cpp +66 -0
- package/external/folly/folly/synchronization/test/RcuTest.cpp +330 -0
- package/external/folly/folly/synchronization/test/RelaxedAtomicTest.cpp +389 -0
- package/external/folly/folly/synchronization/test/SaturatingSemaphoreTest.cpp +166 -0
- package/external/folly/folly/synchronization/test/Semaphore.h +242 -0
- package/external/folly/folly/synchronization/test/SemaphoreTest.cpp +271 -0
- package/external/folly/folly/synchronization/test/SmallLocksBenchmark.cpp +1296 -0
- package/external/folly/folly/synchronization/test/SmallLocksTest.cpp +510 -0
- package/external/folly/folly/synchronization/test/ThreadCachedEpochBench.h +67 -0
- package/external/folly/folly/synchronization/test/ThreadCachedReadersBench.cpp +42 -0
- package/external/folly/folly/synchronization/test/ThreadCachedReadersTest.cpp +52 -0
- package/external/folly/folly/synchronization/test/ThrottledLifoSemTest.cpp +243 -0
- package/external/folly/folly/system/AtFork.cpp +205 -0
- package/external/folly/folly/system/AtFork.h +116 -0
- package/external/folly/folly/system/AuxVector.h +198 -0
- package/external/folly/folly/system/BUCK +144 -0
- package/external/folly/folly/system/EnvUtil.cpp +93 -0
- package/external/folly/folly/system/EnvUtil.h +113 -0
- package/external/folly/folly/system/HardwareConcurrency.cpp +39 -0
- package/external/folly/folly/system/HardwareConcurrency.h +23 -0
- package/external/folly/folly/system/MemoryMapping.cpp +477 -0
- package/external/folly/folly/system/MemoryMapping.h +287 -0
- package/external/folly/folly/system/Pid.cpp +87 -0
- package/external/folly/folly/system/Pid.h +34 -0
- package/external/folly/folly/system/Shell.cpp +33 -0
- package/external/folly/folly/system/Shell.h +93 -0
- package/external/folly/folly/system/ThreadId.cpp +89 -0
- package/external/folly/folly/system/ThreadId.h +62 -0
- package/external/folly/folly/system/ThreadName.cpp +330 -0
- package/external/folly/folly/system/ThreadName.h +72 -0
- package/external/folly/folly/system/test/AtForkTest.cpp +309 -0
- package/external/folly/folly/system/test/AuxVectorTest.cpp +55 -0
- package/external/folly/folly/system/test/BUCK +120 -0
- package/external/folly/folly/system/test/EnvUtilSubprocess.cpp +26 -0
- package/external/folly/folly/system/test/EnvUtilTest.cpp +197 -0
- package/external/folly/folly/system/test/MemoryMappingTest.cpp +179 -0
- package/external/folly/folly/system/test/PidTest.cpp +46 -0
- package/external/folly/folly/system/test/ShellTest.cpp +66 -0
- package/external/folly/folly/system/test/ThreadIdTest.cpp +114 -0
- package/external/folly/folly/system/test/ThreadNameTest.cpp +85 -0
- package/external/folly/folly.vcxitems +164 -0
- package/external/folly/static/logo.svg +1 -0
- package/external/folly/sync-config.json +8 -0
- package/package.json +3 -3
- package/template/cpp-app/proj/MyApp.sln +0 -33
- package/template/cpp-lib/proj/MyLib.sln +0 -33
- package/template/cs-app/proj/MyApp.sln +0 -33
- package/template/cs-lib/proj/MyLib.sln +0 -33
- package/templates/cpp-app/windows/MyApp.sln +0 -33
- package/templates/cpp-lib/example/metro.config.js +31 -6
- package/templates/cpp-lib/windows/MyLib.sln +0 -33
- package/Folly/Folly.vcxproj +0 -383
- package/Folly/Folly.vcxproj.filters +0 -558
- package/Folly/Folly.win32.vcxproj +0 -11
- package/Folly/packages.lock.win32.json +0 -20
- package/Scripts/Warm-RnwFeedCache.ps1 +0 -413
- package/fmt/fmt.vcxproj +0 -163
- package/fmt/fmt.vcxproj.filters +0 -59
- package/fmt/fmt.win32.vcxproj +0 -10
- package/fmt/pch.cpp +0 -4
- package/fmt/pch.h +0 -2
- /package/{Folly → external/folly}/Folly.natvis +0 -0
- /package/{Folly → external/folly}/cgmanifest.json +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/ConstexprMath.h +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/Conv.cpp +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/chrono/Hardware.h +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/concurrency/CacheLocality.cpp +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/dynamic-inl.h +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/json/json.cpp +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/SafeAssert.h +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.cpp +0 -0
- /package/{Folly/TEMP_UntilFollyUpdate → external/folly/folly}/lang/ToAscii.h +0 -0
- /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
|