From 2a079c2782f12f3fba0bb2a299f1badcd5468d60 Mon Sep 17 00:00:00 2001 From: Vladimir Morozov Date: Thu, 9 Apr 2026 16:50:44 -0700 Subject: [PATCH 1/3] Add folly and fast-float to fork-sync --- .../windows/AutomationChannel.sln | 16 - .../AutomationChannel/packages.lock.json | 8 - .../windows/WithIndirectDependency.sln | 15 - .../packages.lock.json | 8 - .../windows/RNTesterApp-Fabric.sln | 16 - .../RNTesterApp-Fabric/packages.lock.json | 8 - .../packages.experimentalwinui3.lock.json | 8 - .../packages.lock.json | 8 - .../windows/playground-composition.sln | 16 - .../packages.experimentalwinui3.lock.json | 8 - .../playground-composition/packages.lock.json | 8 - .../packages.lock.json | 8 - .../windows/SampleAppFabric.sln | 16 - .../SampleAppFabric/packages.lock.json | 8 - .../windows/SampleCustomComponent.sln | 16 - .../packages.experimentalwinui3.lock.json | 8 - .../SampleCustomComponent/packages.lock.json | 8 - sync-manifest.json | 4 +- .../packages.experimentalwinui3.lock.json | 15 - vnext/Desktop.ABITests/packages.lock.json | 15 - .../packages.experimentalwinui3.lock.json | 15 - vnext/Desktop.DLL/packages.lock.json | 15 - .../packages.experimentalwinui3.lock.json | 16 - .../packages.lock.json | 16 - .../packages.experimentalwinui3.lock.json | 15 - vnext/Desktop.UnitTests/packages.lock.json | 15 - vnext/Desktop/React.Windows.Desktop.vcxproj | 6 - .../packages.experimentalwinui3.lock.json | 13 - vnext/Desktop/packages.lock.json | 13 - vnext/Directory.Build.props | 11 - vnext/Folly/Folly.vcxproj | 375 --- vnext/Folly/Folly.vcxproj.filters | 558 ---- vnext/Folly/ThreadNameStub.cpp | 10 +- vnext/Folly/packages.lock.json | 20 - vnext/FollyWin32/FollyWin32.vcxproj | 90 - vnext/FollyWin32/FollyWin32.vcxproj.filters | 21 - vnext/FollyWin32/README.md | 1 - .../React.Windows.IntegrationTests.vcxproj | 3 - vnext/IntegrationTests/packages.lock.json | 6 - .../packages.experimentalwinui3.lock.json | 8 - .../packages.lock.json | 8 - .../packages.experimentalwinui3.lock.json | 8 - .../packages.lock.json | 8 - ...Microsoft.ReactNative.NewArch.Publish.slnf | 1 - vnext/Microsoft.ReactNative.NewArch.sln | 15 - .../Microsoft.ReactNative.vcxproj | 5 +- .../packages.experimentalwinui3.lock.json | 7 - .../Microsoft.ReactNative/packages.lock.json | 7 - vnext/PropertySheets/React.Cpp.props | 4 +- .../packages.experimentalwinui3.lock.json | 15 - .../ReactCommon.UnitTests/packages.lock.json | 15 - vnext/ReactCommon/ReactCommon.vcxproj | 5 - vnext/ReactCommon/packages.lock.json | 6 - vnext/ReactWindows-Desktop.Publish.slnf | 2 - vnext/ReactWindows-Desktop.sln | 42 - vnext/Scripts/Tfs/Layout-Desktop-Headers.ps1 | 30 +- vnext/external/External.vcxitems | 2 + vnext/external/fast-float/.syncignore | 12 + vnext/external/fast-float/cgmanifest.json | 15 + vnext/external/fast-float/fast-float.vcxitems | 14 + .../include/fast_float/ascii_number.h | 588 ++++ .../fast-float/include/fast_float/bigint.h | 638 ++++ .../fast_float/constexpr_feature_detect.h | 46 + .../include/fast_float/decimal_to_binary.h | 212 ++ .../include/fast_float/digit_comparison.h | 457 +++ .../include/fast_float/fast_float.h | 59 + .../include/fast_float/fast_table.h | 708 ++++ .../include/fast_float/float_common.h | 1240 +++++++ .../include/fast_float/parse_number.h | 399 +++ vnext/external/fast-float/sync-config.json | 8 + vnext/external/folly/.syncignore | 62 + vnext/{Folly => external/folly}/Folly.natvis | 0 .../{Folly => external/folly}/cgmanifest.json | 0 vnext/external/folly/folly.vcxitems | 156 + .../folly/folly}/.clang-format | 1 - .../folly/folly/AtomicHashArray-inl.h | 546 +++ vnext/external/folly/folly/AtomicHashArray.h | 431 +++ .../external/folly/folly/AtomicHashMap-inl.h | 653 ++++ vnext/external/folly/folly/AtomicHashMap.h | 484 +++ .../folly/folly/AtomicIntrusiveLinkedList.h | 206 ++ vnext/external/folly/folly/AtomicLinkedList.h | 110 + .../external/folly/folly/AtomicUnorderedMap.h | 522 +++ vnext/external/folly/folly/BUCK | 1631 +++++++++ vnext/external/folly/folly/BUILD_MODE.bzl | 72 + vnext/external/folly/folly/Benchmark.cpp | 986 ++++++ vnext/external/folly/folly/Benchmark.h | 680 ++++ vnext/external/folly/folly/BenchmarkUtil.h | 47 + vnext/external/folly/folly/Bits.h | 17 + vnext/external/folly/folly/CMakeLists.txt | 110 + vnext/external/folly/folly/CPortability.h | 338 ++ .../folly/folly/CancellationToken-inl.h | 449 +++ .../folly/folly/CancellationToken.cpp | 250 ++ .../external/folly/folly/CancellationToken.h | 365 ++ vnext/external/folly/folly/Chrono.h | 132 + .../folly/folly/ClockGettimeWrappers.cpp | 93 + .../folly/folly/ClockGettimeWrappers.h | 29 + vnext/external/folly/folly/ConcurrentBitSet.h | 157 + vnext/external/folly/folly/ConcurrentLazy.h | 74 + .../folly/folly/ConcurrentSkipList-inl.h | 341 ++ .../external/folly/folly/ConcurrentSkipList.h | 824 +++++ .../folly/folly}/ConstexprMath.h | 0 .../folly/folly/ConstructorCallbackList.h | 158 + .../folly/folly}/Conv.cpp | 0 vnext/external/folly/folly/Conv.h | 2026 +++++++++++ vnext/external/folly/folly/CppAttributes.h | 170 + vnext/external/folly/folly/CpuId.h | 297 ++ .../folly/folly/DefaultKeepAliveExecutor.h | 172 + vnext/external/folly/folly/Demangle.cpp | 255 ++ vnext/external/folly/folly/Demangle.h | 73 + vnext/external/folly/folly/DiscriminatedPtr.h | 236 ++ vnext/external/folly/folly/DynamicConverter.h | 17 + vnext/external/folly/folly/Exception.h | 150 + .../external/folly/folly/ExceptionString.cpp | 51 + vnext/external/folly/folly/ExceptionString.h | 33 + .../folly/folly/ExceptionWrapper-inl.h | 264 ++ .../external/folly/folly/ExceptionWrapper.cpp | 37 + vnext/external/folly/folly/ExceptionWrapper.h | 377 +++ vnext/external/folly/folly/Executor.cpp | 111 + vnext/external/folly/folly/Executor.h | 351 ++ vnext/external/folly/folly/Expected.h | 1725 ++++++++++ vnext/external/folly/folly/FBString.h | 2888 ++++++++++++++++ vnext/external/folly/folly/FBVector.h | 17 + vnext/external/folly/folly/File.cpp | 180 + vnext/external/folly/folly/File.h | 177 + vnext/external/folly/folly/FileUtil.cpp | 378 +++ vnext/external/folly/folly/FileUtil.h | 332 ++ vnext/external/folly/folly/Fingerprint.cpp | 135 + vnext/external/folly/folly/Fingerprint.h | 289 ++ vnext/external/folly/folly/FixedString.h | 2965 +++++++++++++++++ vnext/external/folly/folly/FollyMemcpy.cpp | 30 + vnext/external/folly/folly/FollyMemcpy.h | 23 + vnext/external/folly/folly/FollyMemset.cpp | 29 + vnext/external/folly/folly/FollyMemset.h | 25 + vnext/external/folly/folly/Format-inl.h | 1152 +++++++ vnext/external/folly/folly/Format.cpp | 429 +++ vnext/external/folly/folly/Format.h | 463 +++ vnext/external/folly/folly/FormatArg.h | 285 ++ vnext/external/folly/folly/FormatTraits.h | 65 + vnext/external/folly/folly/Function.h | 1159 +++++++ vnext/external/folly/folly/GLog.h | 85 + vnext/external/folly/folly/GroupVarint.cpp | 153 + vnext/external/folly/folly/GroupVarint.h | 630 ++++ vnext/external/folly/folly/Hash.h | 20 + vnext/external/folly/folly/IPAddress.cpp | 490 +++ vnext/external/folly/folly/IPAddress.h | 667 ++++ .../external/folly/folly/IPAddressException.h | 82 + vnext/external/folly/folly/IPAddressV4.cpp | 305 ++ vnext/external/folly/folly/IPAddressV4.h | 495 +++ vnext/external/folly/folly/IPAddressV6.cpp | 541 +++ vnext/external/folly/folly/IPAddressV6.h | 627 ++++ vnext/external/folly/folly/Indestructible.h | 164 + vnext/external/folly/folly/IndexedMemPool.h | 550 +++ vnext/external/folly/folly/IntrusiveList.h | 17 + vnext/external/folly/folly/Lazy.h | 142 + vnext/external/folly/folly/Likely.h | 76 + vnext/external/folly/folly/MPMCPipeline.h | 280 ++ vnext/external/folly/folly/MPMCQueue.h | 1556 +++++++++ vnext/external/folly/folly/MacAddress.cpp | 188 ++ vnext/external/folly/folly/MacAddress.h | 260 ++ vnext/external/folly/folly/MapUtil.h | 17 + vnext/external/folly/folly/Math.h | 258 ++ vnext/external/folly/folly/MaybeManagedPtr.h | 120 + vnext/external/folly/folly/Memory.h | 900 +++++ vnext/external/folly/folly/MicroLock.cpp | 76 + vnext/external/folly/folly/MicroLock.h | 354 ++ vnext/external/folly/folly/MicroSpinLock.h | 17 + vnext/external/folly/folly/MoveWrapper.h | 76 + .../external/folly/folly/ObserverContainer.h | 1026 ++++++ vnext/external/folly/folly/Optional.h | 743 +++++ vnext/external/folly/folly/Overload.h | 325 ++ vnext/external/folly/folly/PackedSyncPtr.h | 147 + vnext/external/folly/folly/Padded.h | 464 +++ vnext/external/folly/folly/Poly-inl.h | 230 ++ vnext/external/folly/folly/Poly.h | 1095 ++++++ vnext/external/folly/folly/PolyException.h | 43 + vnext/external/folly/folly/Portability.h | 644 ++++ vnext/external/folly/folly/Preprocessor.h | 236 ++ .../folly/folly/ProducerConsumerQueue.h | 182 + vnext/external/folly/folly/RWSpinLock.h | 17 + vnext/external/folly/folly/Random-inl.h | 86 + vnext/external/folly/folly/Random.cpp | 184 + vnext/external/folly/folly/Random.h | 434 +++ vnext/external/folly/folly/Range.h | 1772 ++++++++++ vnext/external/folly/folly/Replaceable.h | 636 ++++ vnext/external/folly/folly/ScopeGuard.cpp | 29 + vnext/external/folly/folly/ScopeGuard.h | 420 +++ vnext/external/folly/folly/SharedMutex.cpp | 81 + vnext/external/folly/folly/SharedMutex.h | 1751 ++++++++++ vnext/external/folly/folly/Singleton-inl.h | 332 ++ vnext/external/folly/folly/Singleton.cpp | 512 +++ vnext/external/folly/folly/Singleton.h | 891 +++++ .../folly/folly/SingletonThreadLocal.cpp | 53 + .../folly/folly/SingletonThreadLocal.h | 263 ++ vnext/external/folly/folly/SocketAddress.cpp | 786 +++++ vnext/external/folly/folly/SocketAddress.h | 768 +++++ vnext/external/folly/folly/SpinLock.h | 55 + vnext/external/folly/folly/String-inl.h | 668 ++++ vnext/external/folly/folly/String.cpp | 777 +++++ vnext/external/folly/folly/String.h | 767 +++++ vnext/external/folly/folly/Subprocess.cpp | 1142 +++++++ vnext/external/folly/folly/Subprocess.h | 1055 ++++++ vnext/external/folly/folly/Synchronized.h | 1833 ++++++++++ vnext/external/folly/folly/SynchronizedPtr.h | 106 + vnext/external/folly/folly/ThreadCachedInt.h | 175 + vnext/external/folly/folly/ThreadLocal.h | 478 +++ vnext/external/folly/folly/TimeoutQueue.cpp | 78 + vnext/external/folly/folly/TimeoutQueue.h | 123 + vnext/external/folly/folly/TokenBucket.h | 673 ++++ vnext/external/folly/folly/Traits.h | 1407 ++++++++ vnext/external/folly/folly/Try-inl.h | 372 +++ vnext/external/folly/folly/Try.cpp | 23 + vnext/external/folly/folly/Try.h | 728 ++++ vnext/external/folly/folly/UTF8String.h | 56 + vnext/external/folly/folly/Unicode.cpp | 201 ++ vnext/external/folly/folly/Unicode.h | 94 + vnext/external/folly/folly/Unit.h | 65 + vnext/external/folly/folly/Uri-inl.h | 101 + vnext/external/folly/folly/Uri.cpp | 190 ++ vnext/external/folly/folly/Uri.h | 142 + vnext/external/folly/folly/Utility.h | 932 ++++++ vnext/external/folly/folly/VERSION | 1 + vnext/external/folly/folly/Varint.h | 230 ++ vnext/external/folly/folly/VirtualExecutor.h | 17 + .../external/folly/folly/algorithm/simd/BUCK | 47 + .../folly/folly/algorithm/simd/Contains.cpp | 42 + .../folly/folly/algorithm/simd/Contains.h | 116 + .../folly/folly/algorithm/simd/FindFixed.h | 301 ++ .../folly/folly/algorithm/simd/Ignore.h | 52 + .../folly/folly/algorithm/simd/Movemask.h | 207 ++ .../folly/folly/algorithm/simd/detail/BUCK | 70 + .../algorithm/simd/detail/ContainsImpl.h | 91 + .../folly/algorithm/simd/detail/SimdAnyOf.h | 83 + .../folly/algorithm/simd/detail/SimdForEach.h | 209 ++ .../algorithm/simd/detail/SimdPlatform.h | 445 +++ .../folly/algorithm/simd/detail/Traits.h | 125 + .../folly/algorithm/simd/detail/UnrollUtils.h | 126 + vnext/external/folly/folly/base64.h | 264 ++ vnext/external/folly/folly/chrono/BUCK | 29 + vnext/external/folly/folly/chrono/Clock.h | 65 + vnext/external/folly/folly/chrono/Conv.h | 712 ++++ .../folly/folly}/chrono/Hardware.h | 0 vnext/external/folly/folly/chrono/test/BUCK | 26 + .../folly/folly/chrono/test/ClockTest.cpp | 68 + .../folly/folly/chrono/test/ConvTest.cpp | 652 ++++ .../folly/folly/concurrency/AtomicSharedPtr.h | 387 +++ vnext/external/folly/folly/concurrency/BUCK | 170 + .../folly}/concurrency/CacheLocality.cpp | 0 .../folly/folly/concurrency/CacheLocality.h | 460 +++ .../folly/concurrency/ConcurrentHashMap.h | 822 +++++ .../folly/concurrency/CoreCachedSharedPtr.h | 232 ++ .../folly/concurrency/DeadlockDetector.cpp | 27 + .../folly/concurrency/DeadlockDetector.h | 44 + .../folly/concurrency/DynamicBoundedQueue.h | 751 +++++ .../concurrency/PriorityUnboundedQueueSet.h | 207 ++ .../concurrency/ProcessLocalUniqueId.cpp | 46 + .../folly/concurrency/ProcessLocalUniqueId.h | 38 + .../concurrency/SingletonRelaxedCounter.h | 325 ++ .../concurrency/ThreadCachedSynchronized.h | 227 ++ .../folly/folly/concurrency/UnboundedQueue.h | 891 +++++ .../folly/folly/concurrency/container/BUCK | 77 + .../container/FlatCombiningPriorityQueue.h | 426 +++ .../container/LockFreeRingBuffer.h | 306 ++ .../RelaxedConcurrentPriorityQueue.h | 1212 +++++++ .../container/SingleWriterFixedHashMap.h | 322 ++ .../concurrency/container/atomic_grow_array.h | 564 ++++ .../folly/concurrency/container/test/BUCK | 75 + .../test/FlatCombiningPriorityQueueTest.cpp | 570 ++++ .../container/test/LockFreeRingBufferTest.cpp | 276 ++ .../RelaxedConcurrentPriorityQueueTest.cpp | 1570 +++++++++ .../test/SingleWriterFixedHashMapTest.cpp | 401 +++ .../container/test/atomic_grow_array_test.cpp | 187 ++ .../detail/AtomicSharedPtr-detail.h | 212 ++ .../detail/ConcurrentHashMap-detail.h | 1911 +++++++++++ .../memory/AtomicReadMostlyMainPtr.cpp | 43 + .../memory/AtomicReadMostlyMainPtr.h | 190 ++ .../folly/folly/concurrency/memory/BUCK | 53 + .../folly/concurrency/memory/PrimaryPtr.h | 338 ++ .../concurrency/memory/ReadMostlySharedPtr.h | 511 +++ .../folly/concurrency/memory/TLRefCount.h | 228 ++ .../test/AtomicReadMostlyMainPtrBenchmark.cpp | 56 + .../test/AtomicReadMostlyMainPtrTest.cpp | 454 +++ .../folly/folly/concurrency/memory/test/BUCK | 95 + .../memory/test/PrimaryPtrTest.cpp | 303 ++ .../test/ReadMostlySharedPtrBenchmark.cpp | 138 + .../test/ReadMostlySharedPtrStressTest.cpp | 75 + .../memory/test/ReadMostlySharedPtrTest.cpp | 378 +++ .../memory/test/RefCountBenchmark.cpp | 90 + .../concurrency/memory/test/RefCountTest.cpp | 168 + .../concurrency/test/AtomicSharedPtrCounted.h | 156 + .../test/AtomicSharedPtrPerformance.cpp | 255 ++ .../concurrency/test/AtomicSharedPtrTest.cpp | 257 ++ .../folly/folly/concurrency/test/BUCK | 229 ++ .../test/CacheLocalityBenchmark.cpp | 392 +++ .../concurrency/test/CacheLocalityTest.cpp | 1229 +++++++ .../test/ConcurrentHashMapBench.cpp | 260 ++ .../test/ConcurrentHashMapTest.cpp | 1242 +++++++ .../test/CoreCachedSharedPtrTest.cpp | 408 +++ .../test/DynamicBoundedQueueTest.cpp | 984 ++++++ .../test/PriorityUnboundedQueueSetTest.cpp | 73 + .../test/ProcessLocalUniqueIdTest.cpp | 66 + .../test/SingletonRelaxedCounterBench.cpp | 101 + .../test/SingletonRelaxedCounterTest.cpp | 185 + .../test/ThreadCachedSynchronizedBench.cpp | 76 + .../test/ThreadCachedSynchronizedTest.cpp | 93 + .../concurrency/test/UnboundedQueueTest.cpp | 1302 ++++++++ vnext/external/folly/folly/container/Access.h | 57 + vnext/external/folly/folly/container/Array.h | 87 + vnext/external/folly/folly/container/BUCK | 353 ++ .../folly/folly/container/BitIterator.h | 203 ++ .../folly/folly/container/Enumerate.h | 162 + .../folly/folly/container/EvictingCacheMap.h | 730 ++++ vnext/external/folly/folly/container/F14.md | 300 ++ .../folly/folly/container/F14Map-fwd.h | 113 + vnext/external/folly/folly/container/F14Map.h | 2108 ++++++++++++ .../folly/folly/container/F14Set-fwd.h | 95 + vnext/external/folly/folly/container/F14Set.h | 1603 +++++++++ .../external/folly/folly/container/FBVector.h | 1711 ++++++++++ .../folly/folly/container/Foreach-inl.h | 316 ++ .../external/folly/folly/container/Foreach.h | 209 ++ .../folly/container/HeterogeneousAccess-fwd.h | 33 + .../folly/container/HeterogeneousAccess.h | 171 + .../folly/folly/container/IntrusiveHeap.h | 268 ++ .../folly/folly/container/IntrusiveList.h | 131 + .../external/folly/folly/container/Iterator.h | 843 +++++ .../external/folly/folly/container/MapUtil.h | 376 +++ vnext/external/folly/folly/container/Merge.h | 90 + .../folly/folly/container/RegexMatchCache.cpp | 521 +++ .../folly/folly/container/RegexMatchCache.h | 699 ++++ .../external/folly/folly/container/Reserve.h | 109 + .../folly/folly/container/SparseByteSet.h | 123 + vnext/external/folly/folly/container/View.h | 81 + .../container/WeightedEvictingCacheMap.h | 651 ++++ .../folly/folly/container/detail/BUCK | 115 + .../container/detail/BitIteratorDetail.h | 87 + .../folly/container/detail/F14Defaults.h | 34 + .../detail/F14IntrinsicsAvailability.h | 67 + .../folly/container/detail/F14MapFallback.h | 717 ++++ .../folly/folly/container/detail/F14Mask.h | 235 ++ .../folly/folly/container/detail/F14Policy.h | 1523 +++++++++ .../folly/container/detail/F14SetFallback.h | 528 +++ .../folly/folly/container/detail/F14Table.cpp | 71 + .../folly/folly/container/detail/F14Table.h | 2680 +++++++++++++++ .../folly/folly/container/detail/Util.h | 303 ++ .../folly/container/detail/tape_detail.h | 135 + .../folly/folly/container/detail/test/BUCK | 14 + .../container/detail/test/F14DetailTest.cpp | 47 + .../folly/folly/container/heap_vector_types.h | 1683 ++++++++++ .../folly/folly/container/range_traits.h | 81 + .../folly/folly/container/small_vector.h | 1477 ++++++++ .../folly/container/sorted_vector_types.h | 1652 +++++++++ vnext/external/folly/folly/container/span.h | 408 +++ vnext/external/folly/folly/container/tape.h | 608 ++++ .../folly/folly/container/test/.clang-tidy | 12 + .../folly/folly/container/test/AccessTest.cpp | 138 + .../folly/folly/container/test/ArrayTest.cpp | 84 + .../external/folly/folly/container/test/BUCK | 568 ++++ .../folly/container/test/BitIteratorBench.cpp | 112 + .../folly/container/test/BitIteratorTest.cpp | 109 + .../folly/container/test/EnumerateTest.cpp | 294 ++ .../container/test/EvictingCacheMapBench.cpp | 80 + .../container/test/EvictingCacheMapTest.cpp | 842 +++++ .../container/test/F14AsanSupportTest.cpp | 143 + .../folly/folly/container/test/F14FwdTest.cpp | 37 + .../container/test/F14InterprocessTest.cpp | 404 +++ .../folly/folly/container/test/F14MapTest.cpp | 2543 ++++++++++++++ .../folly/container/test/F14PolicyTest.cpp | 49 + .../folly/folly/container/test/F14SetTest.cpp | 1738 ++++++++++ .../container/test/F14SmallOverheads.cpp | 215 ++ .../folly/folly/container/test/F14TestUtil.h | 117 + .../container/test/FBVectorBenchmark.cpp | 380 +++ .../container/test/FBVectorBenchmarks.cpp.h | 100 + .../folly/container/test/FBVectorTest.cpp | 326 ++ .../folly/container/test/FBVectorTests.cpp.h | 304 ++ .../folly/container/test/ForeachBenchmark.cpp | 388 +++ .../folly/container/test/ForeachTest.cpp | 338 ++ .../folly/container/test/HashMapsBench.cpp | 458 +++ .../test/HeterogeneousAccessTest.cpp | 242 ++ .../container/test/IntrusiveHeapTest.cpp | 262 ++ .../folly/container/test/IteratorTest.cpp | 989 ++++++ .../folly/container/test/MapUtilTest.cpp | 365 ++ .../folly/folly/container/test/MergeTest.cpp | 66 + .../container/test/RegexMatchCacheTest.cpp | 634 ++++ .../folly/container/test/ReserveTest.cpp | 173 + .../container/test/SparseByteSetBenchmark.cpp | 153 + .../container/test/SparseByteSetTest.cpp | 117 + .../folly/container/test/TrackingTypes.h | 584 ++++ .../folly/folly/container/test/UtilTest.cpp | 609 ++++ .../test/WeightedEvictingCacheMapTest.cpp | 800 +++++ .../container/test/heap_vector_types_test.cpp | 1774 ++++++++++ .../container/test/range_traits_test.cpp | 59 + .../container/test/small_vector_test.cpp | 1571 +++++++++ .../container/test/sorted_vector_test.cpp | 1589 +++++++++ .../folly/folly/container/test/span_test.cpp | 520 +++ .../folly/folly/container/test/tape_bench.cpp | 200 ++ .../folly/folly/container/test/tape_test.cpp | 590 ++++ vnext/external/folly/folly/defs.bzl | 238 ++ .../folly/folly/detail/AsyncTrace.cpp | 36 + .../external/folly/folly/detail/AsyncTrace.h | 44 + .../folly/folly/detail/AtomicHashUtils.h | 42 + .../folly/detail/AtomicUnorderedMapUtils.h | 80 + vnext/external/folly/folly/detail/BUCK | 406 +++ .../folly/detail/DiscriminatedPtrDetail.h | 172 + .../folly/folly/detail/FileUtilDetail.cpp | 63 + .../folly/folly/detail/FileUtilDetail.h | 85 + .../folly/folly/detail/FileUtilVectorDetail.h | 81 + .../folly/detail/FingerprintPolynomial.h | 132 + vnext/external/folly/folly/detail/Futex-inl.h | 123 + vnext/external/folly/folly/detail/Futex.cpp | 273 ++ vnext/external/folly/folly/detail/Futex.h | 109 + .../folly/folly/detail/GroupVarintDetail.h | 101 + .../external/folly/folly/detail/IPAddress.cpp | 37 + vnext/external/folly/folly/detail/IPAddress.h | 57 + .../folly/folly/detail/IPAddressSource.h | 278 ++ vnext/external/folly/folly/detail/Iterators.h | 156 + .../folly/folly/detail/MPMCPipelineDetail.h | 122 + .../folly/folly/detail/MemoryIdler.cpp | 233 ++ .../external/folly/folly/detail/MemoryIdler.h | 216 ++ .../folly/folly/detail/PerfScoped.cpp | 112 + .../external/folly/folly/detail/PerfScoped.h | 70 + .../external/folly/folly/detail/PolyDetail.h | 921 +++++ .../folly/folly/detail/RangeCommon.cpp | 55 + .../external/folly/folly/detail/RangeCommon.h | 93 + .../folly/folly/detail/RangeSse42.cpp | 198 ++ .../external/folly/folly/detail/RangeSse42.h | 30 + .../folly/detail/SimpleSimdStringUtils.cpp | 31 + .../folly/detail/SimpleSimdStringUtils.h | 27 + .../folly/detail/SimpleSimdStringUtilsImpl.h | 63 + vnext/external/folly/folly/detail/Singleton.h | 34 + .../folly/folly/detail/SlowFingerprint.h | 90 + .../folly/folly/detail/SocketFastOpen.cpp | 175 + .../folly/folly/detail/SocketFastOpen.h | 89 + .../folly/folly/detail/SplitStringSimd.cpp | 84 + .../folly/folly/detail/SplitStringSimd.h | 151 + .../folly/folly/detail/SplitStringSimdImpl.h | 149 + vnext/external/folly/folly/detail/Sse.cpp | 35 + vnext/external/folly/folly/detail/Sse.h | 45 + .../folly/detail/StaticSingletonManager.cpp | 119 + .../folly/detail/StaticSingletonManager.h | 298 ++ .../folly/folly/detail/ThreadLocalDetail.cpp | 492 +++ .../folly/folly/detail/ThreadLocalDetail.h | 800 +++++ .../folly/folly/detail/TrapOnAvx512.cpp | 41 + .../folly/folly/detail/TrapOnAvx512.h | 21 + .../folly/folly/detail/TurnSequencer.h | 295 ++ vnext/external/folly/folly/detail/TypeList.h | 551 +++ .../folly/folly/detail/UniqueInstance.cpp | 136 + .../folly/folly/detail/UniqueInstance.h | 68 + .../folly/folly/detail/base64_detail/BUCK | 102 + .../folly/detail/base64_detail/Base64Api.cpp | 40 + .../folly/detail/base64_detail/Base64Api.h | 101 + .../folly/detail/base64_detail/Base64Common.h | 80 + .../detail/base64_detail/Base64Constants.h | 79 + .../base64_detail/Base64HiddenConstants.h | 129 + .../folly/detail/base64_detail/Base64SWAR.cpp | 161 + .../folly/detail/base64_detail/Base64SWAR.h | 32 + .../folly/detail/base64_detail/Base64Scalar.h | 262 ++ .../folly/detail/base64_detail/Base64Simd.h | 102 + .../detail/base64_detail/Base64_SSE4_2.cpp | 42 + .../detail/base64_detail/Base64_SSE4_2.h | 33 + .../base64_detail/Base64_SSE4_2_Platform.h | 167 + .../folly/detail/base64_detail/README.md | 392 +++ .../folly/detail/base64_detail/tests/BUCK | 36 + .../tests/Base64AgainstScalarTest.cpp | 141 + .../tests/Base64PlatformTest.cpp | 273 ++ .../tests/Base64SpecialCasesTest.cpp | 555 +++ .../folly/detail/test/AsyncTraceTest.cpp | 43 + vnext/external/folly/folly/detail/test/BUCK | 118 + .../folly/detail/test/FileUtilDetailTest.cpp | 56 + .../folly/detail/test/PerfScopedTest.cpp | 107 + .../detail/test/SimpleSimdStringUtilsTest.cpp | 92 + .../folly/detail/test/SplitStringSimdTest.cpp | 242 ++ .../test/StaticSingletonManagerTest.cpp | 121 + .../detail/test/ThreadLocalBenchmark.cpp | 116 + .../detail/test/ThreadLocalDetailTest.cpp | 194 ++ .../detail/test/TrapOnAvx512TestNegative.cpp | 29 + .../folly/detail/test/UniqueInstanceTest.cpp | 60 + .../folly/detail/thread_local_globals.cpp | 69 + .../folly/folly/detail/thread_local_globals.h | 36 + vnext/external/folly/folly/dynamic-inl.h | 17 + vnext/external/folly/folly/dynamic.h | 17 + .../folly/folly/folly_extended_library.bzl | 28 + .../folly/folly/functional/ApplyTuple.h | 204 ++ vnext/external/folly/folly/functional/BUCK | 57 + .../external/folly/folly/functional/Invoke.h | 880 +++++ .../external/folly/folly/functional/Partial.h | 130 + .../folly/folly/functional/protocol.h | 203 ++ .../folly/functional/test/ApplyTupleTest.cpp | 549 +++ .../external/folly/folly/functional/test/BUCK | 57 + .../folly/functional/test/InvokeTest.cpp | 483 +++ .../folly/functional/test/PartialTest.cpp | 141 + .../folly/functional/test/protocol_test.cpp | 177 + .../folly/functional/test/traits_test.cpp | 551 +++ .../external/folly/folly/functional/traits.h | 675 ++++ vnext/external/folly/folly/hash/BUCK | 86 + vnext/external/folly/folly/hash/Checksum.cpp | 275 ++ vnext/external/folly/folly/hash/Checksum.h | 94 + vnext/external/folly/folly/hash/FarmHash.h | 46 + vnext/external/folly/folly/hash/Hash.h | 1045 ++++++ vnext/external/folly/folly/hash/MurmurHash.h | 86 + .../folly/folly/hash/SpookyHashV1.cpp | 391 +++ .../external/folly/folly/hash/SpookyHashV1.h | 307 ++ .../folly/folly/hash/SpookyHashV2.cpp | 392 +++ .../external/folly/folly/hash/SpookyHashV2.h | 334 ++ vnext/external/folly/folly/hash/detail/BUCK | 26 + .../folly/hash/detail/ChecksumDetail.cpp | 296 ++ .../folly/folly/hash/detail/ChecksumDetail.h | 137 + .../folly/hash/detail/Crc32CombineDetail.cpp | 191 ++ .../folly/folly/hash/detail/Crc32cDetail.cpp | 303 ++ vnext/external/folly/folly/hash/test/BUCK | 132 + .../folly/hash/test/ChecksumBenchmark.cpp | 91 + .../folly/folly/hash/test/ChecksumTest.cpp | 587 ++++ .../folly/folly/hash/test/FarmHashTest.cpp | 41 + .../folly/folly/hash/test/HashBenchmark.cpp | 238 ++ .../folly/folly/hash/test/HashTest.cpp | 997 ++++++ .../folly/folly/hash/test/MurmurHashTest.cpp | 76 + .../folly/hash/test/SpookyHashV1Test.cpp | 559 ++++ .../folly/hash/test/SpookyHashV2Test.cpp | 549 +++ .../folly/folly/hash/test/traits_test.cpp | 69 + vnext/external/folly/folly/hash/traits.h | 115 + vnext/external/folly/folly/json.h | 17 + vnext/external/folly/folly/json/BUCK | 155 + .../folly/folly/json/DynamicConverter.h | 464 +++ .../folly/folly/json/DynamicParser-inl.h | 316 ++ .../folly/folly/json/DynamicParser.cpp | 198 ++ .../external/folly/folly/json/DynamicParser.h | 394 +++ .../external/folly/folly/json/JSONSchema.cpp | 1030 ++++++ vnext/external/folly/folly/json/JSONSchema.h | 73 + .../external/folly/folly/json/JsonMockUtil.h | 73 + .../folly/folly/json/JsonTestUtil.cpp | 167 + .../external/folly/folly/json/JsonTestUtil.h | 88 + vnext/external/folly/folly/json/bser/BUCK | 24 + vnext/external/folly/folly/json/bser/Bser.h | 107 + vnext/external/folly/folly/json/bser/Dump.cpp | 253 ++ vnext/external/folly/folly/json/bser/Load.cpp | 246 ++ .../external/folly/folly/json/bser/test/BUCK | 14 + .../folly/folly/json/bser/test/BserTest.cpp | 149 + .../folly/folly}/json/dynamic-inl.h | 0 vnext/external/folly/folly/json/dynamic.cpp | 552 +++ vnext/external/folly/folly/json/dynamic.h | 1346 ++++++++ .../folly/folly}/json/json.cpp | 0 vnext/external/folly/folly/json/json.h | 238 ++ .../external/folly/folly/json/json_patch.cpp | 325 ++ vnext/external/folly/folly/json/json_patch.h | 126 + .../folly/folly/json/json_pointer.cpp | 114 + .../external/folly/folly/json/json_pointer.h | 87 + vnext/external/folly/folly/json/test/BUCK | 147 + .../folly/json/test/DynamicBenchmark.cpp | 146 + .../folly/json/test/DynamicConverterTest.cpp | 518 +++ .../folly/json/test/DynamicOtherTest.cpp | 344 ++ .../folly/json/test/DynamicParserTest.cpp | 443 +++ .../folly/folly/json/test/DynamicTest.cpp | 1647 +++++++++ .../folly/folly/json/test/JSONSchemaTest.cpp | 450 +++ .../folly/folly/json/test/JsonBenchmark.cpp | 264 ++ .../folly/folly/json/test/JsonOtherTest.cpp | 51 + .../folly/folly/json/test/JsonTest.cpp | 1153 +++++++ .../folly/json/test/JsonTestUtilTest.cpp | 97 + .../folly/folly/json/test/json_patch_test.cpp | 361 ++ .../folly/json/test/json_pointer_test.cpp | 58 + vnext/external/folly/folly/json/tool/BUCK | 13 + .../folly/json/tool/JSONSchemaTester.cpp | 58 + vnext/external/folly/folly/json_patch.h | 17 + vnext/external/folly/folly/json_pointer.h | 17 + vnext/external/folly/folly/lang/Access.h | 29 + vnext/external/folly/folly/lang/Align.h | 240 ++ vnext/external/folly/folly/lang/Aligned.h | 92 + vnext/external/folly/folly/lang/Assume.h | 82 + vnext/external/folly/folly/lang/BUCK | 287 ++ vnext/external/folly/folly/lang/Badge.h | 108 + vnext/external/folly/folly/lang/Bits.h | 570 ++++ vnext/external/folly/folly/lang/BitsClass.h | 312 ++ vnext/external/folly/folly/lang/Builtin.h | 74 + vnext/external/folly/folly/lang/CArray.h | 34 + vnext/external/folly/folly/lang/CString.cpp | 86 + vnext/external/folly/folly/lang/CString.h | 55 + vnext/external/folly/folly/lang/Cast.h | 51 + vnext/external/folly/folly/lang/CheckedMath.h | 253 ++ .../folly/folly/lang/CustomizationPoint.h | 58 + vnext/external/folly/folly/lang/Exception.cpp | 822 +++++ vnext/external/folly/folly/lang/Exception.h | 716 ++++ vnext/external/folly/folly/lang/Extern.h | 55 + vnext/external/folly/folly/lang/Hint-inl.h | 144 + vnext/external/folly/folly/lang/Hint.h | 238 ++ vnext/external/folly/folly/lang/Keep.h | 98 + vnext/external/folly/folly/lang/New.h | 124 + vnext/external/folly/folly/lang/Ordering.h | 140 + vnext/external/folly/folly/lang/Pretty.h | 159 + .../folly/folly/lang/PropagateConst.h | 413 +++ .../folly/folly/lang/RValueReferenceWrapper.h | 152 + .../external/folly/folly/lang/SafeAssert.cpp | 589 ++++ .../folly/folly}/lang/SafeAssert.h | 0 vnext/external/folly/folly/lang/StaticConst.h | 33 + vnext/external/folly/folly/lang/Thunk.h | 100 + .../folly/folly}/lang/ToAscii.cpp | 0 .../folly/folly}/lang/ToAscii.h | 0 vnext/external/folly/folly/lang/TypeInfo.h | 58 + .../folly/folly/lang/UncaughtExceptions.cpp | 17 + .../folly/folly/lang/UncaughtExceptions.h | 19 + .../folly/folly/lang/test/AlignTest.cpp | 87 + .../folly/folly/lang/test/AlignedTest.cpp | 130 + vnext/external/folly/folly/lang/test/BUCK | 258 ++ .../folly/folly/lang/test/BadgeTest.cpp | 89 + .../folly/folly/lang/test/BitsBenchmark.cpp | 164 + .../folly/lang/test/BitsClassBenchmark.cpp | 122 + .../folly/folly/lang/test/BitsClassTest.cpp | 379 +++ .../folly/folly/lang/test/BitsTest.cpp | 577 ++++ .../folly/folly/lang/test/CStringTest.cpp | 60 + .../folly/folly/lang/test/CastTest.cpp | 47 + .../folly/folly/lang/test/CheckedMathTest.cpp | 394 +++ .../folly/folly/lang/test/ExceptionBench.cpp | 427 +++ .../folly/folly/lang/test/ExceptionTest.cpp | 413 +++ .../folly/folly/lang/test/ExternTest.cpp | 39 + .../folly/folly/lang/test/HintTest.cpp | 100 + .../folly/folly/lang/test/NewTest.cpp | 38 + .../folly/folly/lang/test/OrderingTest.cpp | 105 + .../folly/folly/lang/test/PrettyTest.cpp | 44 + .../folly/lang/test/PropagateConstTest.cpp | 356 ++ .../lang/test/RValueReferenceWrapperTest.cpp | 85 + .../folly/folly/lang/test/SafeAssertTest.cpp | 75 + .../folly/folly/lang/test/ThunkTest.cpp | 105 + .../folly/folly/lang/test/ToAsciiBench.cpp | 466 +++ .../folly/folly/lang/test/ToAsciiTest.cpp | 266 ++ .../folly/folly/lang/test/TypeInfoTest.cpp | 56 + vnext/external/folly/folly/memcpy.S | 292 ++ .../folly/folly/memcpy_select_aarch64.cpp | 145 + vnext/external/folly/folly/memory/Arena-inl.h | 83 + vnext/external/folly/folly/memory/Arena.h | 325 ++ vnext/external/folly/folly/memory/BUCK | 191 ++ .../memory/JemallocHugePageAllocator.cpp | 449 +++ .../folly/memory/JemallocHugePageAllocator.h | 105 + .../memory/JemallocHugePageAllocatorTest.cpp | 341 ++ .../folly/memory/JemallocNodumpAllocator.cpp | 176 + .../folly/memory/JemallocNodumpAllocator.h | 119 + .../memory/JemallocNodumpAllocatorTest.cpp | 61 + .../folly/folly/memory/MallctlHelper.cpp | 37 + .../folly/folly/memory/MallctlHelper.h | 167 + vnext/external/folly/folly/memory/Malloc.h | 551 +++ .../folly/folly/memory/MemoryResource.h | 57 + .../folly/folly/memory/ReentrantAllocator.cpp | 162 + .../folly/folly/memory/ReentrantAllocator.h | 261 ++ .../folly/folly/memory/SanitizeAddress.cpp | 75 + .../folly/folly/memory/SanitizeAddress.h | 117 + .../folly/folly/memory/SanitizeLeak.cpp | 119 + .../folly/folly/memory/SanitizeLeak.h | 108 + .../folly/folly/memory/ThreadCachedArena.cpp | 53 + .../folly/folly/memory/ThreadCachedArena.h | 90 + .../folly/memory/UninitializedMemoryHacks.h | 426 +++ vnext/external/folly/folly/memory/detail/BUCK | 10 + .../folly/folly/memory/detail/MallocImpl.cpp | 52 + .../folly/folly/memory/detail/MallocImpl.h | 97 + .../folly/folly/memory/not_null-inl.h | 522 +++ vnext/external/folly/folly/memory/not_null.h | 449 +++ .../folly/folly/memory/test/ArenaTest.cpp | 354 ++ vnext/external/folly/folly/memory/test/BUCK | 146 + .../folly/memory/test/MallctlHelperTest.cpp | 169 + .../folly/memory/test/MallocBenchmark.cpp | 91 + .../folly/folly/memory/test/MallocTest.cpp | 78 + .../folly/memory/test/MemoryResourceTest.cpp | 31 + .../memory/test/ReentrantAllocatorTest.cpp | 144 + .../folly/memory/test/SanitizeAddressTest.cpp | 67 + .../folly/memory/test/SanitizeLeakTest.cpp | 139 + .../memory/test/ThreadCachedArenaTest.cpp | 276 ++ .../test/UninitializedMemoryHacksODR.cpp | 21 + .../test/UninitializedMemoryHacksTest.cpp | 327 ++ .../folly/folly/memory/test/not_null_test.cpp | 608 ++++ vnext/external/folly/folly/memset.S | 245 ++ .../folly/folly/memset_select_aarch64.cpp | 72 + vnext/external/folly/folly/portability/Asm.h | 50 + .../external/folly/folly/portability/Atomic.h | 31 + vnext/external/folly/folly/portability/BUCK | 456 +++ .../folly/folly/portability/Builtins.cpp | 31 + .../folly/folly/portability/Builtins.h | 161 + .../external/folly/folly/portability/Config.h | 43 + .../folly/folly/portability/Constexpr.h | 145 + .../folly/folly/portability/Dirent.cpp | 140 + .../external/folly/folly/portability/Dirent.h | 41 + .../external/folly/folly/portability/Event.h | 44 + .../folly/folly/portability/Fcntl.cpp | 120 + .../external/folly/folly/portability/Fcntl.h | 67 + .../folly/folly/portability/Filesystem.cpp | 67 + .../folly/folly/portability/Filesystem.h | 114 + .../folly/folly/portability/FmtCompile.h | 40 + .../external/folly/folly/portability/GFlags.h | 139 + .../external/folly/folly/portability/GMock.h | 35 + .../external/folly/folly/portability/GTest.h | 35 + .../external/folly/folly/portability/IOVec.h | 34 + .../folly/folly/portability/Libgen.cpp | 59 + .../external/folly/folly/portability/Libgen.h | 29 + .../folly/folly/portability/Libunwind.h | 21 + .../folly/folly/portability/Malloc.cpp | 31 + .../external/folly/folly/portability/Malloc.h | 53 + vnext/external/folly/folly/portability/Math.h | 90 + .../external/folly/folly/portability/Memory.h | 26 + .../folly/folly/portability/OpenSSL.cpp | 17 + .../folly/folly/portability/OpenSSL.h | 102 + .../folly/folly/portability/PThread.cpp | 697 ++++ .../folly/folly/portability/PThread.h | 148 + .../folly/folly/portability/README.md | 21 + .../folly/folly/portability/Sched.cpp | 41 + .../external/folly/folly/portability/Sched.h | 45 + .../folly/folly/portability/Sockets.cpp | 245 ++ .../folly/folly/portability/Sockets.h | 155 + .../folly/folly/portability/SourceLocation.h | 49 + .../folly/folly/portability/Stdio.cpp | 77 + .../external/folly/folly/portability/Stdio.h | 32 + .../folly/folly/portability/Stdlib.cpp | 172 + .../external/folly/folly/portability/Stdlib.h | 64 + .../folly/folly/portability/String.cpp | 53 + .../external/folly/folly/portability/String.h | 39 + .../folly/folly/portability/SysFile.cpp | 46 + .../folly/folly/portability/SysFile.h | 27 + .../folly/folly/portability/SysMembarrier.cpp | 104 + .../folly/folly/portability/SysMembarrier.h | 26 + .../folly/folly/portability/SysMman.cpp | 242 ++ .../folly/folly/portability/SysMman.h | 68 + .../folly/folly/portability/SysResource.cpp | 108 + .../folly/folly/portability/SysResource.h | 71 + .../folly/folly/portability/SysStat.cpp | 66 + .../folly/folly/portability/SysStat.h | 52 + .../folly/folly/portability/SysSyscall.h | 73 + .../folly/folly/portability/SysTime.cpp | 62 + .../folly/folly/portability/SysTime.h | 50 + .../folly/folly/portability/SysTypes.h | 44 + .../folly/folly/portability/SysUio.cpp | 179 + .../external/folly/folly/portability/SysUio.h | 51 + .../external/folly/folly/portability/Syslog.h | 39 + .../external/folly/folly/portability/Time.cpp | 357 ++ vnext/external/folly/folly/portability/Time.h | 74 + .../folly/folly}/portability/Unistd.cpp | 0 .../external/folly/folly/portability/Unistd.h | 111 + .../folly/folly/portability/Windows.h | 108 + .../folly/folly/portability/openat2.c | 30 + .../folly/folly/portability/openat2.h | 39 + .../folly/folly/portability/test/BUCK | 59 + .../folly/portability/test/ConstexprTest.cpp | 102 + .../folly/portability/test/FilesystemTest.cpp | 35 + .../folly/portability/test/LibgenTest.cpp | 35 + .../test/OpenSSLPortabilityTest.cpp | 108 + .../folly/portability/test/PThreadTest.cpp | 80 + .../folly/folly/portability/test/TimeTest.cpp | 90 + vnext/external/folly/folly/small_vector.h | 17 + vnext/external/folly/folly/somerge_defs.bzl | 399 +++ .../folly/folly/sorted_vector_types.h | 17 + vnext/external/folly/folly/stop_watch.h | 317 ++ .../synchronization/AsymmetricThreadFence.cpp | 91 + .../synchronization/AsymmetricThreadFence.h | 60 + .../synchronization/AtomicNotification-inl.h | 146 + .../synchronization/AtomicNotification.cpp | 34 + .../synchronization/AtomicNotification.h | 117 + .../folly/folly/synchronization/AtomicRef.h | 181 + .../folly/synchronization/AtomicStruct.h | 150 + .../folly/synchronization/AtomicUtil-inl.h | 482 +++ .../folly/folly/synchronization/AtomicUtil.h | 179 + .../external/folly/folly/synchronization/BUCK | 418 +++ .../folly/folly/synchronization/Baton.h | 419 +++ .../folly/folly/synchronization/CallOnce.h | 263 ++ .../folly/folly/synchronization/DelayedInit.h | 179 + .../synchronization/DistributedMutex-inl.h | 1745 ++++++++++ .../synchronization/DistributedMutex.cpp | 27 + .../folly/synchronization/DistributedMutex.h | 342 ++ .../folly/folly/synchronization/EventCount.h | 200 ++ .../folly/synchronization/FlatCombining.h | 629 ++++ .../folly/folly/synchronization/Hazptr-fwd.h | 217 ++ .../folly/folly/synchronization/Hazptr.cpp | 36 + .../folly/folly/synchronization/Hazptr.h | 209 ++ .../folly/synchronization/HazptrDomain.cpp | 68 + .../folly/synchronization/HazptrDomain.h | 832 +++++ .../folly/synchronization/HazptrHolder.h | 431 +++ .../folly/folly/synchronization/HazptrObj.h | 533 +++ .../folly/synchronization/HazptrObjLinked.h | 315 ++ .../folly/folly/synchronization/HazptrRec.h | 68 + .../folly/synchronization/HazptrThrLocal.h | 180 + .../HazptrThreadPoolExecutor.cpp | 46 + .../HazptrThreadPoolExecutor.h | 25 + .../folly/folly/synchronization/Latch.h | 160 + .../folly/folly/synchronization/LifoSem.h | 767 +++++ .../folly/folly/synchronization/Lock.h | 887 +++++ .../folly/synchronization/MicroSpinLock.h | 154 + .../folly/synchronization/NativeSemaphore.h | 187 ++ .../folly/synchronization/ParkingLot.cpp | 37 + .../folly/folly/synchronization/ParkingLot.h | 330 ++ .../folly/synchronization/PicoSpinLock.h | 167 + .../folly/folly/synchronization/RWSpinLock.h | 549 +++ .../folly/folly/synchronization/Rcu.cpp | 26 + .../folly/folly/synchronization/Rcu.h | 553 +++ .../folly/synchronization/RelaxedAtomic.h | 336 ++ .../folly/synchronization/SanitizeThread.cpp | 141 + .../folly/synchronization/SanitizeThread.h | 166 + .../synchronization/SaturatingSemaphore.h | 324 ++ .../folly/folly/synchronization/SmallLocks.h | 36 + .../folly/synchronization/ThrottledLifoSem.h | 362 ++ .../folly/synchronization/WaitOptions.cpp | 25 + .../folly/folly/synchronization/WaitOptions.h | 75 + .../synchronization/detail/AtomicUtils.h | 59 + .../folly/folly/synchronization/detail/BUCK | 104 + .../folly/synchronization/detail/Hardware.cpp | 192 ++ .../folly/synchronization/detail/Hardware.h | 75 + .../synchronization/detail/HazptrUtils.h | 339 ++ .../detail/InlineFunctionRef.h | 229 ++ .../folly/synchronization/detail/Sleeper.cpp | 27 + .../folly/synchronization/detail/Sleeper.h | 62 + .../folly/folly/synchronization/detail/Spin.h | 96 + .../detail/ThreadCachedLists.h | 174 + .../detail/ThreadCachedReaders.h | 189 ++ .../synchronization/detail/ThreadCachedTag.h | 26 + .../folly/synchronization/detail/test/BUCK | 28 + .../detail/test/HardwareTest.cpp | 74 + .../detail/test/InlineFunctionRefTest.cpp | 286 ++ .../folly/folly/synchronization/example/BUCK | 27 + .../example/HazptrLockFreeLIFO.h | 88 + .../synchronization/example/HazptrSWMRSet.h | 133 + .../synchronization/example/HazptrWideCAS.h | 62 + .../test/AtomicNotificationTest.cpp | 236 ++ .../synchronization/test/AtomicRefTest.cpp | 170 + .../synchronization/test/AtomicStructTest.cpp | 65 + .../synchronization/test/AtomicUtilBench.cpp | 457 +++ .../synchronization/test/AtomicUtilTest.cpp | 650 ++++ .../folly/folly/synchronization/test/BUCK | 495 +++ .../folly/synchronization/test/Barrier.h | 52 + .../synchronization/test/BarrierTest.cpp | 56 + .../synchronization/test/BatonBenchmark.cpp | 77 + .../folly/synchronization/test/BatonTest.cpp | 164 + .../synchronization/test/BatonTestHelpers.h | 118 + .../test/CallOnceBenchmark.cpp | 72 + .../synchronization/test/CallOnceTest.cpp | 153 + .../synchronization/test/DelayedInitTest.cpp | 281 ++ .../test/DistributedMutexTest.cpp | 2074 ++++++++++++ .../synchronization/test/EventCountTest.cpp | 124 + .../test/FlatCombiningBenchmark.cpp | 1789 ++++++++++ .../test/FlatCombiningExamples.h | 222 ++ .../test/FlatCombiningTest.cpp | 121 + .../test/FlatCombiningTestHelpers.h | 227 ++ .../folly/synchronization/test/HazptrTest.cpp | 1689 ++++++++++ .../folly/synchronization/test/LatchTest.cpp | 224 ++ .../synchronization/test/LifoSemBench.cpp | 185 + .../synchronization/test/LifoSemTests.cpp | 353 ++ .../folly/synchronization/test/LockTest.cpp | 1239 +++++++ .../test/NativeSemaphoreTest.cpp | 37 + .../test/ParkingLotBenchmark.cpp | 239 ++ .../synchronization/test/ParkingLotTest.cpp | 170 + .../synchronization/test/RWSpinLockTest.cpp | 235 ++ .../folly/synchronization/test/RcuBench.cpp | 66 + .../folly/synchronization/test/RcuTest.cpp | 330 ++ .../test/RelaxedAtomicTest.cpp | 389 +++ .../test/SaturatingSemaphoreTest.cpp | 166 + .../folly/synchronization/test/Semaphore.h | 242 ++ .../synchronization/test/SemaphoreTest.cpp | 271 ++ .../test/SmallLocksBenchmark.cpp | 1296 +++++++ .../synchronization/test/SmallLocksTest.cpp | 510 +++ .../test/ThreadCachedEpochBench.h | 67 + .../test/ThreadCachedReadersBench.cpp | 42 + .../test/ThreadCachedReadersTest.cpp | 52 + .../test/ThrottledLifoSemTest.cpp | 243 ++ vnext/external/folly/folly/system/AtFork.cpp | 205 ++ vnext/external/folly/folly/system/AtFork.h | 116 + vnext/external/folly/folly/system/AuxVector.h | 198 ++ vnext/external/folly/folly/system/BUCK | 144 + vnext/external/folly/folly/system/EnvUtil.cpp | 93 + vnext/external/folly/folly/system/EnvUtil.h | 113 + .../folly/system/HardwareConcurrency.cpp | 39 + .../folly/folly/system/HardwareConcurrency.h | 23 + .../folly/folly/system/MemoryMapping.cpp | 477 +++ .../folly/folly/system/MemoryMapping.h | 287 ++ vnext/external/folly/folly/system/Pid.cpp | 87 + vnext/external/folly/folly/system/Pid.h | 34 + vnext/external/folly/folly/system/Shell.cpp | 33 + vnext/external/folly/folly/system/Shell.h | 93 + .../external/folly/folly/system/ThreadId.cpp | 89 + vnext/external/folly/folly/system/ThreadId.h | 62 + .../folly/folly/system/ThreadName.cpp | 330 ++ .../external/folly/folly/system/ThreadName.h | 72 + .../folly/folly/system/test/AtForkTest.cpp | 309 ++ .../folly/folly/system/test/AuxVectorTest.cpp | 55 + vnext/external/folly/folly/system/test/BUCK | 120 + .../folly/system/test/EnvUtilSubprocess.cpp | 26 + .../folly/folly/system/test/EnvUtilTest.cpp | 197 ++ .../folly/system/test/MemoryMappingTest.cpp | 179 + .../folly/folly/system/test/PidTest.cpp | 46 + .../folly/folly/system/test/ShellTest.cpp | 66 + .../folly/folly/system/test/ThreadIdTest.cpp | 114 + .../folly/system/test/ThreadNameTest.cpp | 85 + vnext/external/folly/sync-config.json | 8 + vnext/template/cpp-lib/proj/MyLib.sln | 16 - vnext/template/cs-lib/proj/MyLib.sln | 16 - vnext/templates/cpp-app/windows/MyApp.sln | 16 - vnext/templates/cpp-lib/windows/MyLib.sln | 16 - 884 files changed, 238767 insertions(+), 1674 deletions(-) delete mode 100644 vnext/Folly/Folly.vcxproj delete mode 100644 vnext/Folly/Folly.vcxproj.filters delete mode 100644 vnext/Folly/packages.lock.json delete mode 100644 vnext/FollyWin32/FollyWin32.vcxproj delete mode 100644 vnext/FollyWin32/FollyWin32.vcxproj.filters delete mode 100644 vnext/FollyWin32/README.md create mode 100644 vnext/external/fast-float/.syncignore create mode 100644 vnext/external/fast-float/cgmanifest.json create mode 100644 vnext/external/fast-float/fast-float.vcxitems create mode 100644 vnext/external/fast-float/include/fast_float/ascii_number.h create mode 100644 vnext/external/fast-float/include/fast_float/bigint.h create mode 100644 vnext/external/fast-float/include/fast_float/constexpr_feature_detect.h create mode 100644 vnext/external/fast-float/include/fast_float/decimal_to_binary.h create mode 100644 vnext/external/fast-float/include/fast_float/digit_comparison.h create mode 100644 vnext/external/fast-float/include/fast_float/fast_float.h create mode 100644 vnext/external/fast-float/include/fast_float/fast_table.h create mode 100644 vnext/external/fast-float/include/fast_float/float_common.h create mode 100644 vnext/external/fast-float/include/fast_float/parse_number.h create mode 100644 vnext/external/fast-float/sync-config.json create mode 100644 vnext/external/folly/.syncignore rename vnext/{Folly => external/folly}/Folly.natvis (100%) rename vnext/{Folly => external/folly}/cgmanifest.json (100%) create mode 100644 vnext/external/folly/folly.vcxitems rename vnext/{Folly => external/folly/folly}/.clang-format (51%) create mode 100644 vnext/external/folly/folly/AtomicHashArray-inl.h create mode 100644 vnext/external/folly/folly/AtomicHashArray.h create mode 100644 vnext/external/folly/folly/AtomicHashMap-inl.h create mode 100644 vnext/external/folly/folly/AtomicHashMap.h create mode 100644 vnext/external/folly/folly/AtomicIntrusiveLinkedList.h create mode 100644 vnext/external/folly/folly/AtomicLinkedList.h create mode 100644 vnext/external/folly/folly/AtomicUnorderedMap.h create mode 100644 vnext/external/folly/folly/BUCK create mode 100644 vnext/external/folly/folly/BUILD_MODE.bzl create mode 100644 vnext/external/folly/folly/Benchmark.cpp create mode 100644 vnext/external/folly/folly/Benchmark.h create mode 100644 vnext/external/folly/folly/BenchmarkUtil.h create mode 100644 vnext/external/folly/folly/Bits.h create mode 100644 vnext/external/folly/folly/CMakeLists.txt create mode 100644 vnext/external/folly/folly/CPortability.h create mode 100644 vnext/external/folly/folly/CancellationToken-inl.h create mode 100644 vnext/external/folly/folly/CancellationToken.cpp create mode 100644 vnext/external/folly/folly/CancellationToken.h create mode 100644 vnext/external/folly/folly/Chrono.h create mode 100644 vnext/external/folly/folly/ClockGettimeWrappers.cpp create mode 100644 vnext/external/folly/folly/ClockGettimeWrappers.h create mode 100644 vnext/external/folly/folly/ConcurrentBitSet.h create mode 100644 vnext/external/folly/folly/ConcurrentLazy.h create mode 100644 vnext/external/folly/folly/ConcurrentSkipList-inl.h create mode 100644 vnext/external/folly/folly/ConcurrentSkipList.h rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/ConstexprMath.h (100%) create mode 100644 vnext/external/folly/folly/ConstructorCallbackList.h rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/Conv.cpp (100%) create mode 100644 vnext/external/folly/folly/Conv.h create mode 100644 vnext/external/folly/folly/CppAttributes.h create mode 100644 vnext/external/folly/folly/CpuId.h create mode 100644 vnext/external/folly/folly/DefaultKeepAliveExecutor.h create mode 100644 vnext/external/folly/folly/Demangle.cpp create mode 100644 vnext/external/folly/folly/Demangle.h create mode 100644 vnext/external/folly/folly/DiscriminatedPtr.h create mode 100644 vnext/external/folly/folly/DynamicConverter.h create mode 100644 vnext/external/folly/folly/Exception.h create mode 100644 vnext/external/folly/folly/ExceptionString.cpp create mode 100644 vnext/external/folly/folly/ExceptionString.h create mode 100644 vnext/external/folly/folly/ExceptionWrapper-inl.h create mode 100644 vnext/external/folly/folly/ExceptionWrapper.cpp create mode 100644 vnext/external/folly/folly/ExceptionWrapper.h create mode 100644 vnext/external/folly/folly/Executor.cpp create mode 100644 vnext/external/folly/folly/Executor.h create mode 100644 vnext/external/folly/folly/Expected.h create mode 100644 vnext/external/folly/folly/FBString.h create mode 100644 vnext/external/folly/folly/FBVector.h create mode 100644 vnext/external/folly/folly/File.cpp create mode 100644 vnext/external/folly/folly/File.h create mode 100644 vnext/external/folly/folly/FileUtil.cpp create mode 100644 vnext/external/folly/folly/FileUtil.h create mode 100644 vnext/external/folly/folly/Fingerprint.cpp create mode 100644 vnext/external/folly/folly/Fingerprint.h create mode 100644 vnext/external/folly/folly/FixedString.h create mode 100644 vnext/external/folly/folly/FollyMemcpy.cpp create mode 100644 vnext/external/folly/folly/FollyMemcpy.h create mode 100644 vnext/external/folly/folly/FollyMemset.cpp create mode 100644 vnext/external/folly/folly/FollyMemset.h create mode 100644 vnext/external/folly/folly/Format-inl.h create mode 100644 vnext/external/folly/folly/Format.cpp create mode 100644 vnext/external/folly/folly/Format.h create mode 100644 vnext/external/folly/folly/FormatArg.h create mode 100644 vnext/external/folly/folly/FormatTraits.h create mode 100644 vnext/external/folly/folly/Function.h create mode 100644 vnext/external/folly/folly/GLog.h create mode 100644 vnext/external/folly/folly/GroupVarint.cpp create mode 100644 vnext/external/folly/folly/GroupVarint.h create mode 100644 vnext/external/folly/folly/Hash.h create mode 100644 vnext/external/folly/folly/IPAddress.cpp create mode 100644 vnext/external/folly/folly/IPAddress.h create mode 100644 vnext/external/folly/folly/IPAddressException.h create mode 100644 vnext/external/folly/folly/IPAddressV4.cpp create mode 100644 vnext/external/folly/folly/IPAddressV4.h create mode 100644 vnext/external/folly/folly/IPAddressV6.cpp create mode 100644 vnext/external/folly/folly/IPAddressV6.h create mode 100644 vnext/external/folly/folly/Indestructible.h create mode 100644 vnext/external/folly/folly/IndexedMemPool.h create mode 100644 vnext/external/folly/folly/IntrusiveList.h create mode 100644 vnext/external/folly/folly/Lazy.h create mode 100644 vnext/external/folly/folly/Likely.h create mode 100644 vnext/external/folly/folly/MPMCPipeline.h create mode 100644 vnext/external/folly/folly/MPMCQueue.h create mode 100644 vnext/external/folly/folly/MacAddress.cpp create mode 100644 vnext/external/folly/folly/MacAddress.h create mode 100644 vnext/external/folly/folly/MapUtil.h create mode 100644 vnext/external/folly/folly/Math.h create mode 100644 vnext/external/folly/folly/MaybeManagedPtr.h create mode 100644 vnext/external/folly/folly/Memory.h create mode 100644 vnext/external/folly/folly/MicroLock.cpp create mode 100644 vnext/external/folly/folly/MicroLock.h create mode 100644 vnext/external/folly/folly/MicroSpinLock.h create mode 100644 vnext/external/folly/folly/MoveWrapper.h create mode 100644 vnext/external/folly/folly/ObserverContainer.h create mode 100644 vnext/external/folly/folly/Optional.h create mode 100644 vnext/external/folly/folly/Overload.h create mode 100644 vnext/external/folly/folly/PackedSyncPtr.h create mode 100644 vnext/external/folly/folly/Padded.h create mode 100644 vnext/external/folly/folly/Poly-inl.h create mode 100644 vnext/external/folly/folly/Poly.h create mode 100644 vnext/external/folly/folly/PolyException.h create mode 100644 vnext/external/folly/folly/Portability.h create mode 100644 vnext/external/folly/folly/Preprocessor.h create mode 100644 vnext/external/folly/folly/ProducerConsumerQueue.h create mode 100644 vnext/external/folly/folly/RWSpinLock.h create mode 100644 vnext/external/folly/folly/Random-inl.h create mode 100644 vnext/external/folly/folly/Random.cpp create mode 100644 vnext/external/folly/folly/Random.h create mode 100644 vnext/external/folly/folly/Range.h create mode 100644 vnext/external/folly/folly/Replaceable.h create mode 100644 vnext/external/folly/folly/ScopeGuard.cpp create mode 100644 vnext/external/folly/folly/ScopeGuard.h create mode 100644 vnext/external/folly/folly/SharedMutex.cpp create mode 100644 vnext/external/folly/folly/SharedMutex.h create mode 100644 vnext/external/folly/folly/Singleton-inl.h create mode 100644 vnext/external/folly/folly/Singleton.cpp create mode 100644 vnext/external/folly/folly/Singleton.h create mode 100644 vnext/external/folly/folly/SingletonThreadLocal.cpp create mode 100644 vnext/external/folly/folly/SingletonThreadLocal.h create mode 100644 vnext/external/folly/folly/SocketAddress.cpp create mode 100644 vnext/external/folly/folly/SocketAddress.h create mode 100644 vnext/external/folly/folly/SpinLock.h create mode 100644 vnext/external/folly/folly/String-inl.h create mode 100644 vnext/external/folly/folly/String.cpp create mode 100644 vnext/external/folly/folly/String.h create mode 100644 vnext/external/folly/folly/Subprocess.cpp create mode 100644 vnext/external/folly/folly/Subprocess.h create mode 100644 vnext/external/folly/folly/Synchronized.h create mode 100644 vnext/external/folly/folly/SynchronizedPtr.h create mode 100644 vnext/external/folly/folly/ThreadCachedInt.h create mode 100644 vnext/external/folly/folly/ThreadLocal.h create mode 100644 vnext/external/folly/folly/TimeoutQueue.cpp create mode 100644 vnext/external/folly/folly/TimeoutQueue.h create mode 100644 vnext/external/folly/folly/TokenBucket.h create mode 100644 vnext/external/folly/folly/Traits.h create mode 100644 vnext/external/folly/folly/Try-inl.h create mode 100644 vnext/external/folly/folly/Try.cpp create mode 100644 vnext/external/folly/folly/Try.h create mode 100644 vnext/external/folly/folly/UTF8String.h create mode 100644 vnext/external/folly/folly/Unicode.cpp create mode 100644 vnext/external/folly/folly/Unicode.h create mode 100644 vnext/external/folly/folly/Unit.h create mode 100644 vnext/external/folly/folly/Uri-inl.h create mode 100644 vnext/external/folly/folly/Uri.cpp create mode 100644 vnext/external/folly/folly/Uri.h create mode 100644 vnext/external/folly/folly/Utility.h create mode 100644 vnext/external/folly/folly/VERSION create mode 100644 vnext/external/folly/folly/Varint.h create mode 100644 vnext/external/folly/folly/VirtualExecutor.h create mode 100644 vnext/external/folly/folly/algorithm/simd/BUCK create mode 100644 vnext/external/folly/folly/algorithm/simd/Contains.cpp create mode 100644 vnext/external/folly/folly/algorithm/simd/Contains.h create mode 100644 vnext/external/folly/folly/algorithm/simd/FindFixed.h create mode 100644 vnext/external/folly/folly/algorithm/simd/Ignore.h create mode 100644 vnext/external/folly/folly/algorithm/simd/Movemask.h create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/BUCK create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/ContainsImpl.h create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/SimdAnyOf.h create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/SimdForEach.h create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/SimdPlatform.h create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/Traits.h create mode 100644 vnext/external/folly/folly/algorithm/simd/detail/UnrollUtils.h create mode 100644 vnext/external/folly/folly/base64.h create mode 100644 vnext/external/folly/folly/chrono/BUCK create mode 100644 vnext/external/folly/folly/chrono/Clock.h create mode 100644 vnext/external/folly/folly/chrono/Conv.h rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/chrono/Hardware.h (100%) create mode 100644 vnext/external/folly/folly/chrono/test/BUCK create mode 100644 vnext/external/folly/folly/chrono/test/ClockTest.cpp create mode 100644 vnext/external/folly/folly/chrono/test/ConvTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/AtomicSharedPtr.h create mode 100644 vnext/external/folly/folly/concurrency/BUCK rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/concurrency/CacheLocality.cpp (100%) create mode 100644 vnext/external/folly/folly/concurrency/CacheLocality.h create mode 100644 vnext/external/folly/folly/concurrency/ConcurrentHashMap.h create mode 100644 vnext/external/folly/folly/concurrency/CoreCachedSharedPtr.h create mode 100644 vnext/external/folly/folly/concurrency/DeadlockDetector.cpp create mode 100644 vnext/external/folly/folly/concurrency/DeadlockDetector.h create mode 100644 vnext/external/folly/folly/concurrency/DynamicBoundedQueue.h create mode 100644 vnext/external/folly/folly/concurrency/PriorityUnboundedQueueSet.h create mode 100644 vnext/external/folly/folly/concurrency/ProcessLocalUniqueId.cpp create mode 100644 vnext/external/folly/folly/concurrency/ProcessLocalUniqueId.h create mode 100644 vnext/external/folly/folly/concurrency/SingletonRelaxedCounter.h create mode 100644 vnext/external/folly/folly/concurrency/ThreadCachedSynchronized.h create mode 100644 vnext/external/folly/folly/concurrency/UnboundedQueue.h create mode 100644 vnext/external/folly/folly/concurrency/container/BUCK create mode 100644 vnext/external/folly/folly/concurrency/container/FlatCombiningPriorityQueue.h create mode 100644 vnext/external/folly/folly/concurrency/container/LockFreeRingBuffer.h create mode 100644 vnext/external/folly/folly/concurrency/container/RelaxedConcurrentPriorityQueue.h create mode 100644 vnext/external/folly/folly/concurrency/container/SingleWriterFixedHashMap.h create mode 100644 vnext/external/folly/folly/concurrency/container/atomic_grow_array.h create mode 100644 vnext/external/folly/folly/concurrency/container/test/BUCK create mode 100644 vnext/external/folly/folly/concurrency/container/test/FlatCombiningPriorityQueueTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/container/test/LockFreeRingBufferTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/container/test/RelaxedConcurrentPriorityQueueTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/container/test/SingleWriterFixedHashMapTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/container/test/atomic_grow_array_test.cpp create mode 100644 vnext/external/folly/folly/concurrency/detail/AtomicSharedPtr-detail.h create mode 100644 vnext/external/folly/folly/concurrency/detail/ConcurrentHashMap-detail.h create mode 100644 vnext/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/AtomicReadMostlyMainPtr.h create mode 100644 vnext/external/folly/folly/concurrency/memory/BUCK create mode 100644 vnext/external/folly/folly/concurrency/memory/PrimaryPtr.h create mode 100644 vnext/external/folly/folly/concurrency/memory/ReadMostlySharedPtr.h create mode 100644 vnext/external/folly/folly/concurrency/memory/TLRefCount.h create mode 100644 vnext/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrBenchmark.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/AtomicReadMostlyMainPtrTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/BUCK create mode 100644 vnext/external/folly/folly/concurrency/memory/test/PrimaryPtrTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrBenchmark.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrStressTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/ReadMostlySharedPtrTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/RefCountBenchmark.cpp create mode 100644 vnext/external/folly/folly/concurrency/memory/test/RefCountTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/AtomicSharedPtrCounted.h create mode 100644 vnext/external/folly/folly/concurrency/test/AtomicSharedPtrPerformance.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/AtomicSharedPtrTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/BUCK create mode 100644 vnext/external/folly/folly/concurrency/test/CacheLocalityBenchmark.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/CacheLocalityTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/ConcurrentHashMapBench.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/ConcurrentHashMapTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/CoreCachedSharedPtrTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/DynamicBoundedQueueTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/PriorityUnboundedQueueSetTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/ProcessLocalUniqueIdTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/SingletonRelaxedCounterBench.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/SingletonRelaxedCounterTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/ThreadCachedSynchronizedBench.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/ThreadCachedSynchronizedTest.cpp create mode 100644 vnext/external/folly/folly/concurrency/test/UnboundedQueueTest.cpp create mode 100644 vnext/external/folly/folly/container/Access.h create mode 100644 vnext/external/folly/folly/container/Array.h create mode 100644 vnext/external/folly/folly/container/BUCK create mode 100644 vnext/external/folly/folly/container/BitIterator.h create mode 100644 vnext/external/folly/folly/container/Enumerate.h create mode 100644 vnext/external/folly/folly/container/EvictingCacheMap.h create mode 100644 vnext/external/folly/folly/container/F14.md create mode 100644 vnext/external/folly/folly/container/F14Map-fwd.h create mode 100644 vnext/external/folly/folly/container/F14Map.h create mode 100644 vnext/external/folly/folly/container/F14Set-fwd.h create mode 100644 vnext/external/folly/folly/container/F14Set.h create mode 100644 vnext/external/folly/folly/container/FBVector.h create mode 100644 vnext/external/folly/folly/container/Foreach-inl.h create mode 100644 vnext/external/folly/folly/container/Foreach.h create mode 100644 vnext/external/folly/folly/container/HeterogeneousAccess-fwd.h create mode 100644 vnext/external/folly/folly/container/HeterogeneousAccess.h create mode 100644 vnext/external/folly/folly/container/IntrusiveHeap.h create mode 100644 vnext/external/folly/folly/container/IntrusiveList.h create mode 100644 vnext/external/folly/folly/container/Iterator.h create mode 100644 vnext/external/folly/folly/container/MapUtil.h create mode 100644 vnext/external/folly/folly/container/Merge.h create mode 100644 vnext/external/folly/folly/container/RegexMatchCache.cpp create mode 100644 vnext/external/folly/folly/container/RegexMatchCache.h create mode 100644 vnext/external/folly/folly/container/Reserve.h create mode 100644 vnext/external/folly/folly/container/SparseByteSet.h create mode 100644 vnext/external/folly/folly/container/View.h create mode 100644 vnext/external/folly/folly/container/WeightedEvictingCacheMap.h create mode 100644 vnext/external/folly/folly/container/detail/BUCK create mode 100644 vnext/external/folly/folly/container/detail/BitIteratorDetail.h create mode 100644 vnext/external/folly/folly/container/detail/F14Defaults.h create mode 100644 vnext/external/folly/folly/container/detail/F14IntrinsicsAvailability.h create mode 100644 vnext/external/folly/folly/container/detail/F14MapFallback.h create mode 100644 vnext/external/folly/folly/container/detail/F14Mask.h create mode 100644 vnext/external/folly/folly/container/detail/F14Policy.h create mode 100644 vnext/external/folly/folly/container/detail/F14SetFallback.h create mode 100644 vnext/external/folly/folly/container/detail/F14Table.cpp create mode 100644 vnext/external/folly/folly/container/detail/F14Table.h create mode 100644 vnext/external/folly/folly/container/detail/Util.h create mode 100644 vnext/external/folly/folly/container/detail/tape_detail.h create mode 100644 vnext/external/folly/folly/container/detail/test/BUCK create mode 100644 vnext/external/folly/folly/container/detail/test/F14DetailTest.cpp create mode 100644 vnext/external/folly/folly/container/heap_vector_types.h create mode 100644 vnext/external/folly/folly/container/range_traits.h create mode 100644 vnext/external/folly/folly/container/small_vector.h create mode 100644 vnext/external/folly/folly/container/sorted_vector_types.h create mode 100644 vnext/external/folly/folly/container/span.h create mode 100644 vnext/external/folly/folly/container/tape.h create mode 100644 vnext/external/folly/folly/container/test/.clang-tidy create mode 100644 vnext/external/folly/folly/container/test/AccessTest.cpp create mode 100644 vnext/external/folly/folly/container/test/ArrayTest.cpp create mode 100644 vnext/external/folly/folly/container/test/BUCK create mode 100644 vnext/external/folly/folly/container/test/BitIteratorBench.cpp create mode 100644 vnext/external/folly/folly/container/test/BitIteratorTest.cpp create mode 100644 vnext/external/folly/folly/container/test/EnumerateTest.cpp create mode 100644 vnext/external/folly/folly/container/test/EvictingCacheMapBench.cpp create mode 100644 vnext/external/folly/folly/container/test/EvictingCacheMapTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14AsanSupportTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14FwdTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14InterprocessTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14MapTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14PolicyTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14SetTest.cpp create mode 100644 vnext/external/folly/folly/container/test/F14SmallOverheads.cpp create mode 100644 vnext/external/folly/folly/container/test/F14TestUtil.h create mode 100644 vnext/external/folly/folly/container/test/FBVectorBenchmark.cpp create mode 100644 vnext/external/folly/folly/container/test/FBVectorBenchmarks.cpp.h create mode 100644 vnext/external/folly/folly/container/test/FBVectorTest.cpp create mode 100644 vnext/external/folly/folly/container/test/FBVectorTests.cpp.h create mode 100644 vnext/external/folly/folly/container/test/ForeachBenchmark.cpp create mode 100644 vnext/external/folly/folly/container/test/ForeachTest.cpp create mode 100644 vnext/external/folly/folly/container/test/HashMapsBench.cpp create mode 100644 vnext/external/folly/folly/container/test/HeterogeneousAccessTest.cpp create mode 100644 vnext/external/folly/folly/container/test/IntrusiveHeapTest.cpp create mode 100644 vnext/external/folly/folly/container/test/IteratorTest.cpp create mode 100644 vnext/external/folly/folly/container/test/MapUtilTest.cpp create mode 100644 vnext/external/folly/folly/container/test/MergeTest.cpp create mode 100644 vnext/external/folly/folly/container/test/RegexMatchCacheTest.cpp create mode 100644 vnext/external/folly/folly/container/test/ReserveTest.cpp create mode 100644 vnext/external/folly/folly/container/test/SparseByteSetBenchmark.cpp create mode 100644 vnext/external/folly/folly/container/test/SparseByteSetTest.cpp create mode 100644 vnext/external/folly/folly/container/test/TrackingTypes.h create mode 100644 vnext/external/folly/folly/container/test/UtilTest.cpp create mode 100644 vnext/external/folly/folly/container/test/WeightedEvictingCacheMapTest.cpp create mode 100644 vnext/external/folly/folly/container/test/heap_vector_types_test.cpp create mode 100644 vnext/external/folly/folly/container/test/range_traits_test.cpp create mode 100644 vnext/external/folly/folly/container/test/small_vector_test.cpp create mode 100644 vnext/external/folly/folly/container/test/sorted_vector_test.cpp create mode 100644 vnext/external/folly/folly/container/test/span_test.cpp create mode 100644 vnext/external/folly/folly/container/test/tape_bench.cpp create mode 100644 vnext/external/folly/folly/container/test/tape_test.cpp create mode 100644 vnext/external/folly/folly/defs.bzl create mode 100644 vnext/external/folly/folly/detail/AsyncTrace.cpp create mode 100644 vnext/external/folly/folly/detail/AsyncTrace.h create mode 100644 vnext/external/folly/folly/detail/AtomicHashUtils.h create mode 100644 vnext/external/folly/folly/detail/AtomicUnorderedMapUtils.h create mode 100644 vnext/external/folly/folly/detail/BUCK create mode 100644 vnext/external/folly/folly/detail/DiscriminatedPtrDetail.h create mode 100644 vnext/external/folly/folly/detail/FileUtilDetail.cpp create mode 100644 vnext/external/folly/folly/detail/FileUtilDetail.h create mode 100644 vnext/external/folly/folly/detail/FileUtilVectorDetail.h create mode 100644 vnext/external/folly/folly/detail/FingerprintPolynomial.h create mode 100644 vnext/external/folly/folly/detail/Futex-inl.h create mode 100644 vnext/external/folly/folly/detail/Futex.cpp create mode 100644 vnext/external/folly/folly/detail/Futex.h create mode 100644 vnext/external/folly/folly/detail/GroupVarintDetail.h create mode 100644 vnext/external/folly/folly/detail/IPAddress.cpp create mode 100644 vnext/external/folly/folly/detail/IPAddress.h create mode 100644 vnext/external/folly/folly/detail/IPAddressSource.h create mode 100644 vnext/external/folly/folly/detail/Iterators.h create mode 100644 vnext/external/folly/folly/detail/MPMCPipelineDetail.h create mode 100644 vnext/external/folly/folly/detail/MemoryIdler.cpp create mode 100644 vnext/external/folly/folly/detail/MemoryIdler.h create mode 100644 vnext/external/folly/folly/detail/PerfScoped.cpp create mode 100644 vnext/external/folly/folly/detail/PerfScoped.h create mode 100644 vnext/external/folly/folly/detail/PolyDetail.h create mode 100644 vnext/external/folly/folly/detail/RangeCommon.cpp create mode 100644 vnext/external/folly/folly/detail/RangeCommon.h create mode 100644 vnext/external/folly/folly/detail/RangeSse42.cpp create mode 100644 vnext/external/folly/folly/detail/RangeSse42.h create mode 100644 vnext/external/folly/folly/detail/SimpleSimdStringUtils.cpp create mode 100644 vnext/external/folly/folly/detail/SimpleSimdStringUtils.h create mode 100644 vnext/external/folly/folly/detail/SimpleSimdStringUtilsImpl.h create mode 100644 vnext/external/folly/folly/detail/Singleton.h create mode 100644 vnext/external/folly/folly/detail/SlowFingerprint.h create mode 100644 vnext/external/folly/folly/detail/SocketFastOpen.cpp create mode 100644 vnext/external/folly/folly/detail/SocketFastOpen.h create mode 100644 vnext/external/folly/folly/detail/SplitStringSimd.cpp create mode 100644 vnext/external/folly/folly/detail/SplitStringSimd.h create mode 100644 vnext/external/folly/folly/detail/SplitStringSimdImpl.h create mode 100644 vnext/external/folly/folly/detail/Sse.cpp create mode 100644 vnext/external/folly/folly/detail/Sse.h create mode 100644 vnext/external/folly/folly/detail/StaticSingletonManager.cpp create mode 100644 vnext/external/folly/folly/detail/StaticSingletonManager.h create mode 100644 vnext/external/folly/folly/detail/ThreadLocalDetail.cpp create mode 100644 vnext/external/folly/folly/detail/ThreadLocalDetail.h create mode 100644 vnext/external/folly/folly/detail/TrapOnAvx512.cpp create mode 100644 vnext/external/folly/folly/detail/TrapOnAvx512.h create mode 100644 vnext/external/folly/folly/detail/TurnSequencer.h create mode 100644 vnext/external/folly/folly/detail/TypeList.h create mode 100644 vnext/external/folly/folly/detail/UniqueInstance.cpp create mode 100644 vnext/external/folly/folly/detail/UniqueInstance.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/BUCK create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64Api.cpp create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64Api.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64Common.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64Constants.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64HiddenConstants.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64SWAR.cpp create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64SWAR.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64Scalar.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64Simd.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64_SSE4_2.cpp create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64_SSE4_2.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/Base64_SSE4_2_Platform.h create mode 100644 vnext/external/folly/folly/detail/base64_detail/README.md create mode 100644 vnext/external/folly/folly/detail/base64_detail/tests/BUCK create mode 100644 vnext/external/folly/folly/detail/base64_detail/tests/Base64AgainstScalarTest.cpp create mode 100644 vnext/external/folly/folly/detail/base64_detail/tests/Base64PlatformTest.cpp create mode 100644 vnext/external/folly/folly/detail/base64_detail/tests/Base64SpecialCasesTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/AsyncTraceTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/BUCK create mode 100644 vnext/external/folly/folly/detail/test/FileUtilDetailTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/PerfScopedTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/SimpleSimdStringUtilsTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/SplitStringSimdTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/StaticSingletonManagerTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/ThreadLocalBenchmark.cpp create mode 100644 vnext/external/folly/folly/detail/test/ThreadLocalDetailTest.cpp create mode 100644 vnext/external/folly/folly/detail/test/TrapOnAvx512TestNegative.cpp create mode 100644 vnext/external/folly/folly/detail/test/UniqueInstanceTest.cpp create mode 100644 vnext/external/folly/folly/detail/thread_local_globals.cpp create mode 100644 vnext/external/folly/folly/detail/thread_local_globals.h create mode 100644 vnext/external/folly/folly/dynamic-inl.h create mode 100644 vnext/external/folly/folly/dynamic.h create mode 100644 vnext/external/folly/folly/folly_extended_library.bzl create mode 100644 vnext/external/folly/folly/functional/ApplyTuple.h create mode 100644 vnext/external/folly/folly/functional/BUCK create mode 100644 vnext/external/folly/folly/functional/Invoke.h create mode 100644 vnext/external/folly/folly/functional/Partial.h create mode 100644 vnext/external/folly/folly/functional/protocol.h create mode 100644 vnext/external/folly/folly/functional/test/ApplyTupleTest.cpp create mode 100644 vnext/external/folly/folly/functional/test/BUCK create mode 100644 vnext/external/folly/folly/functional/test/InvokeTest.cpp create mode 100644 vnext/external/folly/folly/functional/test/PartialTest.cpp create mode 100644 vnext/external/folly/folly/functional/test/protocol_test.cpp create mode 100644 vnext/external/folly/folly/functional/test/traits_test.cpp create mode 100644 vnext/external/folly/folly/functional/traits.h create mode 100644 vnext/external/folly/folly/hash/BUCK create mode 100644 vnext/external/folly/folly/hash/Checksum.cpp create mode 100644 vnext/external/folly/folly/hash/Checksum.h create mode 100644 vnext/external/folly/folly/hash/FarmHash.h create mode 100644 vnext/external/folly/folly/hash/Hash.h create mode 100644 vnext/external/folly/folly/hash/MurmurHash.h create mode 100644 vnext/external/folly/folly/hash/SpookyHashV1.cpp create mode 100644 vnext/external/folly/folly/hash/SpookyHashV1.h create mode 100644 vnext/external/folly/folly/hash/SpookyHashV2.cpp create mode 100644 vnext/external/folly/folly/hash/SpookyHashV2.h create mode 100644 vnext/external/folly/folly/hash/detail/BUCK create mode 100644 vnext/external/folly/folly/hash/detail/ChecksumDetail.cpp create mode 100644 vnext/external/folly/folly/hash/detail/ChecksumDetail.h create mode 100644 vnext/external/folly/folly/hash/detail/Crc32CombineDetail.cpp create mode 100644 vnext/external/folly/folly/hash/detail/Crc32cDetail.cpp create mode 100644 vnext/external/folly/folly/hash/test/BUCK create mode 100644 vnext/external/folly/folly/hash/test/ChecksumBenchmark.cpp create mode 100644 vnext/external/folly/folly/hash/test/ChecksumTest.cpp create mode 100644 vnext/external/folly/folly/hash/test/FarmHashTest.cpp create mode 100644 vnext/external/folly/folly/hash/test/HashBenchmark.cpp create mode 100644 vnext/external/folly/folly/hash/test/HashTest.cpp create mode 100644 vnext/external/folly/folly/hash/test/MurmurHashTest.cpp create mode 100644 vnext/external/folly/folly/hash/test/SpookyHashV1Test.cpp create mode 100644 vnext/external/folly/folly/hash/test/SpookyHashV2Test.cpp create mode 100644 vnext/external/folly/folly/hash/test/traits_test.cpp create mode 100644 vnext/external/folly/folly/hash/traits.h create mode 100644 vnext/external/folly/folly/json.h create mode 100644 vnext/external/folly/folly/json/BUCK create mode 100644 vnext/external/folly/folly/json/DynamicConverter.h create mode 100644 vnext/external/folly/folly/json/DynamicParser-inl.h create mode 100644 vnext/external/folly/folly/json/DynamicParser.cpp create mode 100644 vnext/external/folly/folly/json/DynamicParser.h create mode 100644 vnext/external/folly/folly/json/JSONSchema.cpp create mode 100644 vnext/external/folly/folly/json/JSONSchema.h create mode 100644 vnext/external/folly/folly/json/JsonMockUtil.h create mode 100644 vnext/external/folly/folly/json/JsonTestUtil.cpp create mode 100644 vnext/external/folly/folly/json/JsonTestUtil.h create mode 100644 vnext/external/folly/folly/json/bser/BUCK create mode 100644 vnext/external/folly/folly/json/bser/Bser.h create mode 100644 vnext/external/folly/folly/json/bser/Dump.cpp create mode 100644 vnext/external/folly/folly/json/bser/Load.cpp create mode 100644 vnext/external/folly/folly/json/bser/test/BUCK create mode 100644 vnext/external/folly/folly/json/bser/test/BserTest.cpp rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/json/dynamic-inl.h (100%) create mode 100644 vnext/external/folly/folly/json/dynamic.cpp create mode 100644 vnext/external/folly/folly/json/dynamic.h rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/json/json.cpp (100%) create mode 100644 vnext/external/folly/folly/json/json.h create mode 100644 vnext/external/folly/folly/json/json_patch.cpp create mode 100644 vnext/external/folly/folly/json/json_patch.h create mode 100644 vnext/external/folly/folly/json/json_pointer.cpp create mode 100644 vnext/external/folly/folly/json/json_pointer.h create mode 100644 vnext/external/folly/folly/json/test/BUCK create mode 100644 vnext/external/folly/folly/json/test/DynamicBenchmark.cpp create mode 100644 vnext/external/folly/folly/json/test/DynamicConverterTest.cpp create mode 100644 vnext/external/folly/folly/json/test/DynamicOtherTest.cpp create mode 100644 vnext/external/folly/folly/json/test/DynamicParserTest.cpp create mode 100644 vnext/external/folly/folly/json/test/DynamicTest.cpp create mode 100644 vnext/external/folly/folly/json/test/JSONSchemaTest.cpp create mode 100644 vnext/external/folly/folly/json/test/JsonBenchmark.cpp create mode 100644 vnext/external/folly/folly/json/test/JsonOtherTest.cpp create mode 100644 vnext/external/folly/folly/json/test/JsonTest.cpp create mode 100644 vnext/external/folly/folly/json/test/JsonTestUtilTest.cpp create mode 100644 vnext/external/folly/folly/json/test/json_patch_test.cpp create mode 100644 vnext/external/folly/folly/json/test/json_pointer_test.cpp create mode 100644 vnext/external/folly/folly/json/tool/BUCK create mode 100644 vnext/external/folly/folly/json/tool/JSONSchemaTester.cpp create mode 100644 vnext/external/folly/folly/json_patch.h create mode 100644 vnext/external/folly/folly/json_pointer.h create mode 100644 vnext/external/folly/folly/lang/Access.h create mode 100644 vnext/external/folly/folly/lang/Align.h create mode 100644 vnext/external/folly/folly/lang/Aligned.h create mode 100644 vnext/external/folly/folly/lang/Assume.h create mode 100644 vnext/external/folly/folly/lang/BUCK create mode 100644 vnext/external/folly/folly/lang/Badge.h create mode 100644 vnext/external/folly/folly/lang/Bits.h create mode 100644 vnext/external/folly/folly/lang/BitsClass.h create mode 100644 vnext/external/folly/folly/lang/Builtin.h create mode 100644 vnext/external/folly/folly/lang/CArray.h create mode 100644 vnext/external/folly/folly/lang/CString.cpp create mode 100644 vnext/external/folly/folly/lang/CString.h create mode 100644 vnext/external/folly/folly/lang/Cast.h create mode 100644 vnext/external/folly/folly/lang/CheckedMath.h create mode 100644 vnext/external/folly/folly/lang/CustomizationPoint.h create mode 100644 vnext/external/folly/folly/lang/Exception.cpp create mode 100644 vnext/external/folly/folly/lang/Exception.h create mode 100644 vnext/external/folly/folly/lang/Extern.h create mode 100644 vnext/external/folly/folly/lang/Hint-inl.h create mode 100644 vnext/external/folly/folly/lang/Hint.h create mode 100644 vnext/external/folly/folly/lang/Keep.h create mode 100644 vnext/external/folly/folly/lang/New.h create mode 100644 vnext/external/folly/folly/lang/Ordering.h create mode 100644 vnext/external/folly/folly/lang/Pretty.h create mode 100644 vnext/external/folly/folly/lang/PropagateConst.h create mode 100644 vnext/external/folly/folly/lang/RValueReferenceWrapper.h create mode 100644 vnext/external/folly/folly/lang/SafeAssert.cpp rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/lang/SafeAssert.h (100%) create mode 100644 vnext/external/folly/folly/lang/StaticConst.h create mode 100644 vnext/external/folly/folly/lang/Thunk.h rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/lang/ToAscii.cpp (100%) rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/lang/ToAscii.h (100%) create mode 100644 vnext/external/folly/folly/lang/TypeInfo.h create mode 100644 vnext/external/folly/folly/lang/UncaughtExceptions.cpp create mode 100644 vnext/external/folly/folly/lang/UncaughtExceptions.h create mode 100644 vnext/external/folly/folly/lang/test/AlignTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/AlignedTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/BUCK create mode 100644 vnext/external/folly/folly/lang/test/BadgeTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/BitsBenchmark.cpp create mode 100644 vnext/external/folly/folly/lang/test/BitsClassBenchmark.cpp create mode 100644 vnext/external/folly/folly/lang/test/BitsClassTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/BitsTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/CStringTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/CastTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/CheckedMathTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/ExceptionBench.cpp create mode 100644 vnext/external/folly/folly/lang/test/ExceptionTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/ExternTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/HintTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/NewTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/OrderingTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/PrettyTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/PropagateConstTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/RValueReferenceWrapperTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/SafeAssertTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/ThunkTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/ToAsciiBench.cpp create mode 100644 vnext/external/folly/folly/lang/test/ToAsciiTest.cpp create mode 100644 vnext/external/folly/folly/lang/test/TypeInfoTest.cpp create mode 100644 vnext/external/folly/folly/memcpy.S create mode 100644 vnext/external/folly/folly/memcpy_select_aarch64.cpp create mode 100644 vnext/external/folly/folly/memory/Arena-inl.h create mode 100644 vnext/external/folly/folly/memory/Arena.h create mode 100644 vnext/external/folly/folly/memory/BUCK create mode 100644 vnext/external/folly/folly/memory/JemallocHugePageAllocator.cpp create mode 100644 vnext/external/folly/folly/memory/JemallocHugePageAllocator.h create mode 100644 vnext/external/folly/folly/memory/JemallocHugePageAllocatorTest.cpp create mode 100644 vnext/external/folly/folly/memory/JemallocNodumpAllocator.cpp create mode 100644 vnext/external/folly/folly/memory/JemallocNodumpAllocator.h create mode 100644 vnext/external/folly/folly/memory/JemallocNodumpAllocatorTest.cpp create mode 100644 vnext/external/folly/folly/memory/MallctlHelper.cpp create mode 100644 vnext/external/folly/folly/memory/MallctlHelper.h create mode 100644 vnext/external/folly/folly/memory/Malloc.h create mode 100644 vnext/external/folly/folly/memory/MemoryResource.h create mode 100644 vnext/external/folly/folly/memory/ReentrantAllocator.cpp create mode 100644 vnext/external/folly/folly/memory/ReentrantAllocator.h create mode 100644 vnext/external/folly/folly/memory/SanitizeAddress.cpp create mode 100644 vnext/external/folly/folly/memory/SanitizeAddress.h create mode 100644 vnext/external/folly/folly/memory/SanitizeLeak.cpp create mode 100644 vnext/external/folly/folly/memory/SanitizeLeak.h create mode 100644 vnext/external/folly/folly/memory/ThreadCachedArena.cpp create mode 100644 vnext/external/folly/folly/memory/ThreadCachedArena.h create mode 100644 vnext/external/folly/folly/memory/UninitializedMemoryHacks.h create mode 100644 vnext/external/folly/folly/memory/detail/BUCK create mode 100644 vnext/external/folly/folly/memory/detail/MallocImpl.cpp create mode 100644 vnext/external/folly/folly/memory/detail/MallocImpl.h create mode 100644 vnext/external/folly/folly/memory/not_null-inl.h create mode 100644 vnext/external/folly/folly/memory/not_null.h create mode 100644 vnext/external/folly/folly/memory/test/ArenaTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/BUCK create mode 100644 vnext/external/folly/folly/memory/test/MallctlHelperTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/MallocBenchmark.cpp create mode 100644 vnext/external/folly/folly/memory/test/MallocTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/MemoryResourceTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/ReentrantAllocatorTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/SanitizeAddressTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/SanitizeLeakTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/ThreadCachedArenaTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/UninitializedMemoryHacksODR.cpp create mode 100644 vnext/external/folly/folly/memory/test/UninitializedMemoryHacksTest.cpp create mode 100644 vnext/external/folly/folly/memory/test/not_null_test.cpp create mode 100644 vnext/external/folly/folly/memset.S create mode 100644 vnext/external/folly/folly/memset_select_aarch64.cpp create mode 100644 vnext/external/folly/folly/portability/Asm.h create mode 100644 vnext/external/folly/folly/portability/Atomic.h create mode 100644 vnext/external/folly/folly/portability/BUCK create mode 100644 vnext/external/folly/folly/portability/Builtins.cpp create mode 100644 vnext/external/folly/folly/portability/Builtins.h create mode 100644 vnext/external/folly/folly/portability/Config.h create mode 100644 vnext/external/folly/folly/portability/Constexpr.h create mode 100644 vnext/external/folly/folly/portability/Dirent.cpp create mode 100644 vnext/external/folly/folly/portability/Dirent.h create mode 100644 vnext/external/folly/folly/portability/Event.h create mode 100644 vnext/external/folly/folly/portability/Fcntl.cpp create mode 100644 vnext/external/folly/folly/portability/Fcntl.h create mode 100644 vnext/external/folly/folly/portability/Filesystem.cpp create mode 100644 vnext/external/folly/folly/portability/Filesystem.h create mode 100644 vnext/external/folly/folly/portability/FmtCompile.h create mode 100644 vnext/external/folly/folly/portability/GFlags.h create mode 100644 vnext/external/folly/folly/portability/GMock.h create mode 100644 vnext/external/folly/folly/portability/GTest.h create mode 100644 vnext/external/folly/folly/portability/IOVec.h create mode 100644 vnext/external/folly/folly/portability/Libgen.cpp create mode 100644 vnext/external/folly/folly/portability/Libgen.h create mode 100644 vnext/external/folly/folly/portability/Libunwind.h create mode 100644 vnext/external/folly/folly/portability/Malloc.cpp create mode 100644 vnext/external/folly/folly/portability/Malloc.h create mode 100644 vnext/external/folly/folly/portability/Math.h create mode 100644 vnext/external/folly/folly/portability/Memory.h create mode 100644 vnext/external/folly/folly/portability/OpenSSL.cpp create mode 100644 vnext/external/folly/folly/portability/OpenSSL.h create mode 100644 vnext/external/folly/folly/portability/PThread.cpp create mode 100644 vnext/external/folly/folly/portability/PThread.h create mode 100644 vnext/external/folly/folly/portability/README.md create mode 100644 vnext/external/folly/folly/portability/Sched.cpp create mode 100644 vnext/external/folly/folly/portability/Sched.h create mode 100644 vnext/external/folly/folly/portability/Sockets.cpp create mode 100644 vnext/external/folly/folly/portability/Sockets.h create mode 100644 vnext/external/folly/folly/portability/SourceLocation.h create mode 100644 vnext/external/folly/folly/portability/Stdio.cpp create mode 100644 vnext/external/folly/folly/portability/Stdio.h create mode 100644 vnext/external/folly/folly/portability/Stdlib.cpp create mode 100644 vnext/external/folly/folly/portability/Stdlib.h create mode 100644 vnext/external/folly/folly/portability/String.cpp create mode 100644 vnext/external/folly/folly/portability/String.h create mode 100644 vnext/external/folly/folly/portability/SysFile.cpp create mode 100644 vnext/external/folly/folly/portability/SysFile.h create mode 100644 vnext/external/folly/folly/portability/SysMembarrier.cpp create mode 100644 vnext/external/folly/folly/portability/SysMembarrier.h create mode 100644 vnext/external/folly/folly/portability/SysMman.cpp create mode 100644 vnext/external/folly/folly/portability/SysMman.h create mode 100644 vnext/external/folly/folly/portability/SysResource.cpp create mode 100644 vnext/external/folly/folly/portability/SysResource.h create mode 100644 vnext/external/folly/folly/portability/SysStat.cpp create mode 100644 vnext/external/folly/folly/portability/SysStat.h create mode 100644 vnext/external/folly/folly/portability/SysSyscall.h create mode 100644 vnext/external/folly/folly/portability/SysTime.cpp create mode 100644 vnext/external/folly/folly/portability/SysTime.h create mode 100644 vnext/external/folly/folly/portability/SysTypes.h create mode 100644 vnext/external/folly/folly/portability/SysUio.cpp create mode 100644 vnext/external/folly/folly/portability/SysUio.h create mode 100644 vnext/external/folly/folly/portability/Syslog.h create mode 100644 vnext/external/folly/folly/portability/Time.cpp create mode 100644 vnext/external/folly/folly/portability/Time.h rename vnext/{Folly/TEMP_UntilFollyUpdate => external/folly/folly}/portability/Unistd.cpp (100%) create mode 100644 vnext/external/folly/folly/portability/Unistd.h create mode 100644 vnext/external/folly/folly/portability/Windows.h create mode 100644 vnext/external/folly/folly/portability/openat2.c create mode 100644 vnext/external/folly/folly/portability/openat2.h create mode 100644 vnext/external/folly/folly/portability/test/BUCK create mode 100644 vnext/external/folly/folly/portability/test/ConstexprTest.cpp create mode 100644 vnext/external/folly/folly/portability/test/FilesystemTest.cpp create mode 100644 vnext/external/folly/folly/portability/test/LibgenTest.cpp create mode 100644 vnext/external/folly/folly/portability/test/OpenSSLPortabilityTest.cpp create mode 100644 vnext/external/folly/folly/portability/test/PThreadTest.cpp create mode 100644 vnext/external/folly/folly/portability/test/TimeTest.cpp create mode 100644 vnext/external/folly/folly/small_vector.h create mode 100644 vnext/external/folly/folly/somerge_defs.bzl create mode 100644 vnext/external/folly/folly/sorted_vector_types.h create mode 100644 vnext/external/folly/folly/stop_watch.h create mode 100644 vnext/external/folly/folly/synchronization/AsymmetricThreadFence.cpp create mode 100644 vnext/external/folly/folly/synchronization/AsymmetricThreadFence.h create mode 100644 vnext/external/folly/folly/synchronization/AtomicNotification-inl.h create mode 100644 vnext/external/folly/folly/synchronization/AtomicNotification.cpp create mode 100644 vnext/external/folly/folly/synchronization/AtomicNotification.h create mode 100644 vnext/external/folly/folly/synchronization/AtomicRef.h create mode 100644 vnext/external/folly/folly/synchronization/AtomicStruct.h create mode 100644 vnext/external/folly/folly/synchronization/AtomicUtil-inl.h create mode 100644 vnext/external/folly/folly/synchronization/AtomicUtil.h create mode 100644 vnext/external/folly/folly/synchronization/BUCK create mode 100644 vnext/external/folly/folly/synchronization/Baton.h create mode 100644 vnext/external/folly/folly/synchronization/CallOnce.h create mode 100644 vnext/external/folly/folly/synchronization/DelayedInit.h create mode 100644 vnext/external/folly/folly/synchronization/DistributedMutex-inl.h create mode 100644 vnext/external/folly/folly/synchronization/DistributedMutex.cpp create mode 100644 vnext/external/folly/folly/synchronization/DistributedMutex.h create mode 100644 vnext/external/folly/folly/synchronization/EventCount.h create mode 100644 vnext/external/folly/folly/synchronization/FlatCombining.h create mode 100644 vnext/external/folly/folly/synchronization/Hazptr-fwd.h create mode 100644 vnext/external/folly/folly/synchronization/Hazptr.cpp create mode 100644 vnext/external/folly/folly/synchronization/Hazptr.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrDomain.cpp create mode 100644 vnext/external/folly/folly/synchronization/HazptrDomain.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrHolder.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrObj.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrObjLinked.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrRec.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrThrLocal.h create mode 100644 vnext/external/folly/folly/synchronization/HazptrThreadPoolExecutor.cpp create mode 100644 vnext/external/folly/folly/synchronization/HazptrThreadPoolExecutor.h create mode 100644 vnext/external/folly/folly/synchronization/Latch.h create mode 100644 vnext/external/folly/folly/synchronization/LifoSem.h create mode 100644 vnext/external/folly/folly/synchronization/Lock.h create mode 100644 vnext/external/folly/folly/synchronization/MicroSpinLock.h create mode 100644 vnext/external/folly/folly/synchronization/NativeSemaphore.h create mode 100644 vnext/external/folly/folly/synchronization/ParkingLot.cpp create mode 100644 vnext/external/folly/folly/synchronization/ParkingLot.h create mode 100644 vnext/external/folly/folly/synchronization/PicoSpinLock.h create mode 100644 vnext/external/folly/folly/synchronization/RWSpinLock.h create mode 100644 vnext/external/folly/folly/synchronization/Rcu.cpp create mode 100644 vnext/external/folly/folly/synchronization/Rcu.h create mode 100644 vnext/external/folly/folly/synchronization/RelaxedAtomic.h create mode 100644 vnext/external/folly/folly/synchronization/SanitizeThread.cpp create mode 100644 vnext/external/folly/folly/synchronization/SanitizeThread.h create mode 100644 vnext/external/folly/folly/synchronization/SaturatingSemaphore.h create mode 100644 vnext/external/folly/folly/synchronization/SmallLocks.h create mode 100644 vnext/external/folly/folly/synchronization/ThrottledLifoSem.h create mode 100644 vnext/external/folly/folly/synchronization/WaitOptions.cpp create mode 100644 vnext/external/folly/folly/synchronization/WaitOptions.h create mode 100644 vnext/external/folly/folly/synchronization/detail/AtomicUtils.h create mode 100644 vnext/external/folly/folly/synchronization/detail/BUCK create mode 100644 vnext/external/folly/folly/synchronization/detail/Hardware.cpp create mode 100644 vnext/external/folly/folly/synchronization/detail/Hardware.h create mode 100644 vnext/external/folly/folly/synchronization/detail/HazptrUtils.h create mode 100644 vnext/external/folly/folly/synchronization/detail/InlineFunctionRef.h create mode 100644 vnext/external/folly/folly/synchronization/detail/Sleeper.cpp create mode 100644 vnext/external/folly/folly/synchronization/detail/Sleeper.h create mode 100644 vnext/external/folly/folly/synchronization/detail/Spin.h create mode 100644 vnext/external/folly/folly/synchronization/detail/ThreadCachedLists.h create mode 100644 vnext/external/folly/folly/synchronization/detail/ThreadCachedReaders.h create mode 100644 vnext/external/folly/folly/synchronization/detail/ThreadCachedTag.h create mode 100644 vnext/external/folly/folly/synchronization/detail/test/BUCK create mode 100644 vnext/external/folly/folly/synchronization/detail/test/HardwareTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/detail/test/InlineFunctionRefTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/example/BUCK create mode 100644 vnext/external/folly/folly/synchronization/example/HazptrLockFreeLIFO.h create mode 100644 vnext/external/folly/folly/synchronization/example/HazptrSWMRSet.h create mode 100644 vnext/external/folly/folly/synchronization/example/HazptrWideCAS.h create mode 100644 vnext/external/folly/folly/synchronization/test/AtomicNotificationTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/AtomicRefTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/AtomicStructTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/AtomicUtilBench.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/AtomicUtilTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/BUCK create mode 100644 vnext/external/folly/folly/synchronization/test/Barrier.h create mode 100644 vnext/external/folly/folly/synchronization/test/BarrierTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/BatonBenchmark.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/BatonTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/BatonTestHelpers.h create mode 100644 vnext/external/folly/folly/synchronization/test/CallOnceBenchmark.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/CallOnceTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/DelayedInitTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/DistributedMutexTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/EventCountTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/FlatCombiningBenchmark.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/FlatCombiningExamples.h create mode 100644 vnext/external/folly/folly/synchronization/test/FlatCombiningTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/FlatCombiningTestHelpers.h create mode 100644 vnext/external/folly/folly/synchronization/test/HazptrTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/LatchTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/LifoSemBench.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/LifoSemTests.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/LockTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/NativeSemaphoreTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/ParkingLotBenchmark.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/ParkingLotTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/RWSpinLockTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/RcuBench.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/RcuTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/RelaxedAtomicTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/SaturatingSemaphoreTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/Semaphore.h create mode 100644 vnext/external/folly/folly/synchronization/test/SemaphoreTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/SmallLocksBenchmark.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/SmallLocksTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/ThreadCachedEpochBench.h create mode 100644 vnext/external/folly/folly/synchronization/test/ThreadCachedReadersBench.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/ThreadCachedReadersTest.cpp create mode 100644 vnext/external/folly/folly/synchronization/test/ThrottledLifoSemTest.cpp create mode 100644 vnext/external/folly/folly/system/AtFork.cpp create mode 100644 vnext/external/folly/folly/system/AtFork.h create mode 100644 vnext/external/folly/folly/system/AuxVector.h create mode 100644 vnext/external/folly/folly/system/BUCK create mode 100644 vnext/external/folly/folly/system/EnvUtil.cpp create mode 100644 vnext/external/folly/folly/system/EnvUtil.h create mode 100644 vnext/external/folly/folly/system/HardwareConcurrency.cpp create mode 100644 vnext/external/folly/folly/system/HardwareConcurrency.h create mode 100644 vnext/external/folly/folly/system/MemoryMapping.cpp create mode 100644 vnext/external/folly/folly/system/MemoryMapping.h create mode 100644 vnext/external/folly/folly/system/Pid.cpp create mode 100644 vnext/external/folly/folly/system/Pid.h create mode 100644 vnext/external/folly/folly/system/Shell.cpp create mode 100644 vnext/external/folly/folly/system/Shell.h create mode 100644 vnext/external/folly/folly/system/ThreadId.cpp create mode 100644 vnext/external/folly/folly/system/ThreadId.h create mode 100644 vnext/external/folly/folly/system/ThreadName.cpp create mode 100644 vnext/external/folly/folly/system/ThreadName.h create mode 100644 vnext/external/folly/folly/system/test/AtForkTest.cpp create mode 100644 vnext/external/folly/folly/system/test/AuxVectorTest.cpp create mode 100644 vnext/external/folly/folly/system/test/BUCK create mode 100644 vnext/external/folly/folly/system/test/EnvUtilSubprocess.cpp create mode 100644 vnext/external/folly/folly/system/test/EnvUtilTest.cpp create mode 100644 vnext/external/folly/folly/system/test/MemoryMappingTest.cpp create mode 100644 vnext/external/folly/folly/system/test/PidTest.cpp create mode 100644 vnext/external/folly/folly/system/test/ShellTest.cpp create mode 100644 vnext/external/folly/folly/system/test/ThreadIdTest.cpp create mode 100644 vnext/external/folly/folly/system/test/ThreadNameTest.cpp create mode 100644 vnext/external/folly/sync-config.json diff --git a/packages/@react-native-windows/automation-channel/windows/AutomationChannel.sln b/packages/@react-native-windows/automation-channel/windows/AutomationChannel.sln index 208d1641e40..967ef978c6d 100644 --- a/packages/@react-native-windows/automation-channel/windows/AutomationChannel.sln +++ b/packages/@react-native-windows/automation-channel/windows/AutomationChannel.sln @@ -8,11 +8,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "AutomationChannel", "Automa {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\..\..\..\vnext\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" @@ -66,18 +63,6 @@ Global {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.ActiveCfg = Release|Win32 {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.Build.0 = Release|Win32 {C0A69310-6119-46DC-A6D6-0BAB7826DC92}.Release|x86.Deploy.0 = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -119,7 +104,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} diff --git a/packages/@react-native-windows/automation-channel/windows/AutomationChannel/packages.lock.json b/packages/@react-native-windows/automation-channel/windows/AutomationChannel/packages.lock.json index 629ac432f62..2b9c2196f29 100644 --- a/packages/@react-native-windows/automation-channel/windows/AutomationChannel/packages.lock.json +++ b/packages/@react-native-windows/automation-channel/windows/AutomationChannel/packages.lock.json @@ -161,17 +161,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -182,7 +175,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/packages/@react-native-windows/cli/src/e2etest/projects/WithIndirectDependency/windows/WithIndirectDependency.sln b/packages/@react-native-windows/cli/src/e2etest/projects/WithIndirectDependency/windows/WithIndirectDependency.sln index 265a04c7fe8..7b2ccd73c51 100644 --- a/packages/@react-native-windows/cli/src/e2etest/projects/WithIndirectDependency/windows/WithIndirectDependency.sln +++ b/packages/@react-native-windows/cli/src/e2etest/projects/WithIndirectDependency/windows/WithIndirectDependency.sln @@ -8,11 +8,9 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WithIndirectDependency", "W {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\node_modules\react-native-windows\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\node_modules\react-native-windows\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Chakra", "..\node_modules\react-native-windows\Chakra\Chakra.vcxitems", "{C38970C0-5FBF-4D69-90D8-CBAC225AE895}" @@ -70,18 +68,6 @@ Global {416476D5-974A-4EE2-8145-4E331297247E}.Release|x86.ActiveCfg = Release|Win32 {416476D5-974A-4EE2-8145-4E331297247E}.Release|x86.Build.0 = Release|Win32 {416476D5-974A-4EE2-8145-4E331297247E}.Release|x86.Deploy.0 = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -123,7 +109,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {C38970C0-5FBF-4D69-90D8-CBAC225AE895} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} diff --git a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.Package/packages.lock.json b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.Package/packages.lock.json index 60c43bee483..6704dc3d2b9 100644 --- a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.Package/packages.lock.json +++ b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.Package/packages.lock.json @@ -161,17 +161,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -182,7 +175,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.sln b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.sln index 129082dbdcd..84aa2355ce6 100644 --- a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.sln +++ b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric.sln @@ -10,11 +10,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "RNTesterApp-Fabric", "RNTes {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\..\..\vnext\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" @@ -90,18 +87,6 @@ Global {3719BE61-52D1-4F42-8A4C-E575BA16E65F}.Release|ARM64.ActiveCfg = Release|ARM64 {3719BE61-52D1-4F42-8A4C-E575BA16E65F}.Release|ARM64.Build.0 = Release|ARM64 {3719BE61-52D1-4F42-8A4C-E575BA16E65F}.Release|ARM64.Deploy.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -171,7 +156,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} diff --git a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/packages.lock.json b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/packages.lock.json index 0f821d61026..30e6c4fdc93 100644 --- a/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/packages.lock.json +++ b/packages/e2e-test-app-fabric/windows/RNTesterApp-Fabric/packages.lock.json @@ -171,17 +171,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -192,7 +185,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/playground/windows/playground-composition.Package/packages.experimentalwinui3.lock.json b/packages/playground/windows/playground-composition.Package/packages.experimentalwinui3.lock.json index 6f721bf7a8a..60d0057017d 100644 --- a/packages/playground/windows/playground-composition.Package/packages.experimentalwinui3.lock.json +++ b/packages/playground/windows/playground-composition.Package/packages.experimentalwinui3.lock.json @@ -152,17 +152,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -184,7 +177,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/playground/windows/playground-composition.Package/packages.lock.json b/packages/playground/windows/playground-composition.Package/packages.lock.json index c2cef9fea98..7f665a6d853 100644 --- a/packages/playground/windows/playground-composition.Package/packages.lock.json +++ b/packages/playground/windows/playground-composition.Package/packages.lock.json @@ -152,17 +152,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -184,7 +177,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/playground/windows/playground-composition.sln b/packages/playground/windows/playground-composition.sln index 2f32c5cb143..76256ed5464 100644 --- a/packages/playground/windows/playground-composition.sln +++ b/packages/playground/windows/playground-composition.sln @@ -10,11 +10,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Playground-composition", "p {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\..\..\vnext\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" @@ -87,18 +84,6 @@ EndProject {F54A991F-5535-43DF-AE79-85821E001675}.Release|ARM64.ActiveCfg = Release|ARM64 {F54A991F-5535-43DF-AE79-85821E001675}.Release|ARM64.Build.0 = Release|ARM64 {F54A991F-5535-43DF-AE79-85821E001675}.Release|ARM64.Deploy.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -156,7 +141,6 @@ EndProject HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} diff --git a/packages/playground/windows/playground-composition/packages.experimentalwinui3.lock.json b/packages/playground/windows/playground-composition/packages.experimentalwinui3.lock.json index b4923dc9447..50166ddf409 100644 --- a/packages/playground/windows/playground-composition/packages.experimentalwinui3.lock.json +++ b/packages/playground/windows/playground-composition/packages.experimentalwinui3.lock.json @@ -162,17 +162,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -183,7 +176,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/playground/windows/playground-composition/packages.lock.json b/packages/playground/windows/playground-composition/packages.lock.json index b1f604a694c..f9c93f0a73c 100644 --- a/packages/playground/windows/playground-composition/packages.lock.json +++ b/packages/playground/windows/playground-composition/packages.lock.json @@ -162,17 +162,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -183,7 +176,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/sample-app-fabric/windows/SampleAppFabric.Package/packages.lock.json b/packages/sample-app-fabric/windows/SampleAppFabric.Package/packages.lock.json index affc68baa46..aba01459d6f 100644 --- a/packages/sample-app-fabric/windows/SampleAppFabric.Package/packages.lock.json +++ b/packages/sample-app-fabric/windows/SampleAppFabric.Package/packages.lock.json @@ -152,17 +152,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -173,7 +166,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, diff --git a/packages/sample-app-fabric/windows/SampleAppFabric.sln b/packages/sample-app-fabric/windows/SampleAppFabric.sln index fa18a0baf32..ee1cbfa411b 100644 --- a/packages/sample-app-fabric/windows/SampleAppFabric.sln +++ b/packages/sample-app-fabric/windows/SampleAppFabric.sln @@ -10,11 +10,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleAppFabric", "SampleAp {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\..\..\vnext\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" @@ -86,18 +83,6 @@ Global {E278ABE5-5A88-48C5-A949-CA00B489643F}.Release|ARM64.ActiveCfg = Release|ARM64 {E278ABE5-5A88-48C5-A949-CA00B489643F}.Release|ARM64.Build.0 = Release|ARM64 {E278ABE5-5A88-48C5-A949-CA00B489643F}.Release|ARM64.Deploy.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -139,7 +124,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} diff --git a/packages/sample-app-fabric/windows/SampleAppFabric/packages.lock.json b/packages/sample-app-fabric/windows/SampleAppFabric/packages.lock.json index 73d1d955370..e611092fc09 100644 --- a/packages/sample-app-fabric/windows/SampleAppFabric/packages.lock.json +++ b/packages/sample-app-fabric/windows/SampleAppFabric/packages.lock.json @@ -162,17 +162,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -183,7 +176,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/packages/sample-custom-component/windows/SampleCustomComponent.sln b/packages/sample-custom-component/windows/SampleCustomComponent.sln index c6349884662..5d9d627d124 100644 --- a/packages/sample-custom-component/windows/SampleCustomComponent.sln +++ b/packages/sample-custom-component/windows/SampleCustomComponent.sln @@ -8,11 +8,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SampleCustomComponent", "Sa {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {F7D32BD0-2749-483E-9A0D-1635EF7E3136} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "..\..\..\vnext\Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "..\..\..\vnext\ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "..\..\..\vnext\Microsoft.ReactNative\Microsoft.ReactNative.vcxproj", "{F7D32BD0-2749-483E-9A0D-1635EF7E3136}" @@ -53,18 +50,6 @@ Global {A8DA218C-4CB5-48CB-A9EE-9E6337165D07}.Release|x86.ActiveCfg = Release|Win32 {A8DA218C-4CB5-48CB-A9EE-9E6337165D07}.Release|x86.Build.0 = Release|Win32 {A8DA218C-4CB5-48CB-A9EE-9E6337165D07}.Release|x86.Deploy.0 = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|x64.ActiveCfg = Debug|x64 @@ -106,7 +91,6 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {F7D32BD0-2749-483E-9A0D-1635EF7E3136} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} {DA8B35B3-DA00-4B02-BDE6-6A397B3FD46B} = {5EA20F54-880A-49F3-99FA-4B3FE54E8AB1} diff --git a/packages/sample-custom-component/windows/SampleCustomComponent/packages.experimentalwinui3.lock.json b/packages/sample-custom-component/windows/SampleCustomComponent/packages.experimentalwinui3.lock.json index eff4be7784b..2f59fdca57d 100644 --- a/packages/sample-custom-component/windows/SampleCustomComponent/packages.experimentalwinui3.lock.json +++ b/packages/sample-custom-component/windows/SampleCustomComponent/packages.experimentalwinui3.lock.json @@ -161,17 +161,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -182,7 +175,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/packages/sample-custom-component/windows/SampleCustomComponent/packages.lock.json b/packages/sample-custom-component/windows/SampleCustomComponent/packages.lock.json index ca3fc07c2bc..00283c2b5cf 100644 --- a/packages/sample-custom-component/windows/SampleCustomComponent/packages.lock.json +++ b/packages/sample-custom-component/windows/SampleCustomComponent/packages.lock.json @@ -161,17 +161,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -182,7 +175,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/sync-manifest.json b/sync-manifest.json index 92d851327fe..95907cd7a1c 100644 --- a/sync-manifest.json +++ b/sync-manifest.json @@ -5,6 +5,8 @@ "model": "haiku" }, "dependencies": [ - { "name": "fmt", "localPath": "vnext/external/fmt" } + { "name": "fmt", "localPath": "vnext/external/fmt" }, + { "name": "folly", "localPath": "vnext/external/folly" }, + { "name": "fast-float", "localPath": "vnext/external/fast-float" } ] } diff --git a/vnext/Desktop.ABITests/packages.experimentalwinui3.lock.json b/vnext/Desktop.ABITests/packages.experimentalwinui3.lock.json index 4d3f1d4ade0..9adce4983a6 100644 --- a/vnext/Desktop.ABITests/packages.experimentalwinui3.lock.json +++ b/vnext/Desktop.ABITests/packages.experimentalwinui3.lock.json @@ -164,24 +164,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -203,7 +189,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.ABITests/packages.lock.json b/vnext/Desktop.ABITests/packages.lock.json index 182b25a5096..58541d6191e 100644 --- a/vnext/Desktop.ABITests/packages.lock.json +++ b/vnext/Desktop.ABITests/packages.lock.json @@ -164,24 +164,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -203,7 +189,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.DLL/packages.experimentalwinui3.lock.json b/vnext/Desktop.DLL/packages.experimentalwinui3.lock.json index 835f368bacf..c8b4144be69 100644 --- a/vnext/Desktop.DLL/packages.experimentalwinui3.lock.json +++ b/vnext/Desktop.DLL/packages.experimentalwinui3.lock.json @@ -156,24 +156,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -185,7 +171,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.DLL/packages.lock.json b/vnext/Desktop.DLL/packages.lock.json index e98b007231c..8eeda270686 100644 --- a/vnext/Desktop.DLL/packages.lock.json +++ b/vnext/Desktop.DLL/packages.lock.json @@ -156,24 +156,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -185,7 +171,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json b/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json index 8dc90aa6678..aa21da55b54 100644 --- a/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json +++ b/vnext/Desktop.IntegrationTests/packages.experimentalwinui3.lock.json @@ -160,24 +160,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -200,14 +186,12 @@ "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.IntegrationTests/packages.lock.json b/vnext/Desktop.IntegrationTests/packages.lock.json index 9275c21fbb7..4b723ed496a 100644 --- a/vnext/Desktop.IntegrationTests/packages.lock.json +++ b/vnext/Desktop.IntegrationTests/packages.lock.json @@ -160,24 +160,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -200,14 +186,12 @@ "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.UnitTests/packages.experimentalwinui3.lock.json b/vnext/Desktop.UnitTests/packages.experimentalwinui3.lock.json index 469d1741897..8fda2cf0f86 100644 --- a/vnext/Desktop.UnitTests/packages.experimentalwinui3.lock.json +++ b/vnext/Desktop.UnitTests/packages.experimentalwinui3.lock.json @@ -159,24 +159,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -188,7 +174,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop.UnitTests/packages.lock.json b/vnext/Desktop.UnitTests/packages.lock.json index 36854f9cbcf..b1ca3b61d7f 100644 --- a/vnext/Desktop.UnitTests/packages.lock.json +++ b/vnext/Desktop.UnitTests/packages.lock.json @@ -159,24 +159,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -188,7 +174,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop/React.Windows.Desktop.vcxproj b/vnext/Desktop/React.Windows.Desktop.vcxproj index 7b4d89f19b4..f1ed6c4c821 100644 --- a/vnext/Desktop/React.Windows.Desktop.vcxproj +++ b/vnext/Desktop/React.Windows.Desktop.vcxproj @@ -257,12 +257,6 @@ {fca38f3c-7c73-4c47-be4e-32f77fa8538d} - - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} - - - {74085F13-2DDE-45E5-A0CA-927AC9D0B953} - {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} diff --git a/vnext/Desktop/packages.experimentalwinui3.lock.json b/vnext/Desktop/packages.experimentalwinui3.lock.json index 473590f9c4b..d81aba2080b 100644 --- a/vnext/Desktop/packages.experimentalwinui3.lock.json +++ b/vnext/Desktop/packages.experimentalwinui3.lock.json @@ -163,22 +163,9 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Desktop/packages.lock.json b/vnext/Desktop/packages.lock.json index 9c8737a80a6..6ad83e3cb9a 100644 --- a/vnext/Desktop/packages.lock.json +++ b/vnext/Desktop/packages.lock.json @@ -163,22 +163,9 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Directory.Build.props b/vnext/Directory.Build.props index 236002b17a2..932db5c1d69 100644 --- a/vnext/Directory.Build.props +++ b/vnext/Directory.Build.props @@ -25,11 +25,6 @@ pdbonly true false - - 2024.10.14.00 - 8.0.0 - ad90720829db5ba0c3d0e44994856dcce33d7940 - 77cc847c842c49e7e3477c1e95da2b6540166d66 4b8a4a59c4e1b7b988b809dedffd89a7662aa785 @@ -46,12 +41,6 @@ $(ReactNativeDir)ReactCommon\yoga - $(ReactNativeDir)..\..\node_modules\.folly\folly-$(FollyVersion) - $([MSBuild]::NormalizeDirectory($(FollyDir))) - - $(ReactNativeDir)..\..\node_modules\.fastfloat\fast_float-$(FastFloatVersion) - $([MSBuild]::NormalizeDirectory($(FastFloatDir))) - $(ReactNativeWindowsDir)external\ $(ReactNativeDir)..\..\node_modules\.node-api-jsi\node-api-jsi-$(NodeApiJsiCommitHash) diff --git a/vnext/Folly/Folly.vcxproj b/vnext/Folly/Folly.vcxproj deleted file mode 100644 index 89cbfd6403a..00000000000 --- a/vnext/Folly/Folly.vcxproj +++ /dev/null @@ -1,375 +0,0 @@ - - - - {a990658c-ce31-4bcc-976f-0fc6b1af693d} - StaticLibrary - Folly - Folly - en-US - Windows Store - 10.0 - true - - - - - - Debug - ARM64 - - - Debug - ARM64EC - - - Release - ARM64 - - - Debug - x64 - - - Release - ARM64EC - - - Release - x64 - - - Debug - Win32 - - - Release - Win32 - - - - StaticLibrary - - - - - - - - - - - - - - - - - - - - - $(IntDir)\portabilityString.obj - - - - - - - - - - - - Create - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Designer - - - - - - - - - - - - - - - false - - - - - Use - false - true - $(ReactNativeWindowsDir)stubs;$(FollyDir);$(FastFloatDir)\include;$(ExternalDir)fmt\include;%(AdditionalIncludeDirectories) - FOLLY_CFG_NO_COROUTINES;FOLLY_NO_CONFIG;NOMINMAX;_CRT_SECURE_NO_WARNINGS;WINAPI_PARTITION_APP;%(PreprocessorDefinitions) - - 4251;4293;4305;4800;4804;4310;%(DisableSpecificWarnings) - /Zc:__cplusplus %(AdditionalOptions) - pch.h - - - false - false - - - - - - - $(FollyDir)..\.follyzip - $(FollyZipDir)\folly-$(FollyVersion).zip - $(MSBuildThisFileDirectory)cgmanifest.json - - - $(FastFloatDir)..\.fastfloatzip - $(FastFloatZipDir)\fastfloat.zip - - - - - - - - - - - - - - - - - - - - { - "$schema": "https://json.schemastore.org/component-detection-manifest.json", - "Registrations": [ - { - "Component": { - "Type": "git", - "Git": { - "RepositoryUrl": "https://github.com/facebook/folly", - "CommitHash": "$(FollyCommitHash)" - } - }, - "DevelopmentDependency": false - }, - { - "Component": { - "Type": "git", - "Git": { - "RepositoryUrl": "https://github.com/fastfloat/fast_float", - "CommitHash": "$(FastFloatCommitHash)" - } - }, - "DevelopmentDependency": false - } - ] -} - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/vnext/Folly/Folly.vcxproj.filters b/vnext/Folly/Folly.vcxproj.filters deleted file mode 100644 index 67f1bd0e4a1..00000000000 --- a/vnext/Folly/Folly.vcxproj.filters +++ /dev/null @@ -1,558 +0,0 @@ - - - - - {7de8a65b-754e-48e7-b880-4d0aed31f89c} - - - {eca0f8ea-38e0-46ea-a510-afbfbf7c73cc} - - - {e61723ff-a0c1-4851-b100-ce4c55f60c74} - - - {63127dad-d9d4-4d1c-b1e9-324c019c19ed} - - - {7b8a9cd1-6e21-4cf3-bf60-8671576701be} - - - {5688ffb2-cdbc-4f52-810c-e060e9604c78} - - - {ba62e8f4-e5b4-4664-8c6c-59dbbbdafb9f} - - - {426f4ae4-b292-4f39-aaf9-37e4b880b729} - - - {9ad1fbe7-56fb-40d8-b0a2-ac0d6d0799e3} - - - {ed8c80f6-ff7c-4f61-b7ec-a2aee564d575} - - - - - Source Files\lang - - - Source Files\lang - - - Source Files\lang - - - Source Files - - - Source Files - - - Source Files - - - Source Files\container\detail - - - Source Files - - - Source Files - - - Source Files - - - Source Files\container\detail - - - Source Files - - - Source Files\hash - - - Source Files\portability - - - Source Files - - - Source Files - - - - - - - Header Files\portability - - - Header Files\portability - - - Header Files\detail - - - Header Files\detail - - - Header Files\portability - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\portability - - - Header Files - - - Header Files - - - Header Files - - - Header Files\portability - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\detail - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\portability - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\portability - - - Header Files - - - Header Files - - - Header Files\detail - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\portability - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - Header Files\detail - - - - Header Files\lang - - - - - - \ No newline at end of file diff --git a/vnext/Folly/ThreadNameStub.cpp b/vnext/Folly/ThreadNameStub.cpp index d4216832bb1..507c67d0b7e 100644 --- a/vnext/Folly/ThreadNameStub.cpp +++ b/vnext/Folly/ThreadNameStub.cpp @@ -2,9 +2,7 @@ // Avoid bringing in a bunch of folly threading just for setThreadName namespace folly { - bool setThreadName(StringPiece) - { - return false; - } - } - \ No newline at end of file +bool setThreadName(StringPiece) { + return false; +} +} // namespace folly diff --git a/vnext/Folly/packages.lock.json b/vnext/Folly/packages.lock.json deleted file mode 100644 index 669b0b4b521..00000000000 --- a/vnext/Folly/packages.lock.json +++ /dev/null @@ -1,20 +0,0 @@ -{ - "version": 1, - "dependencies": { - "native,Version=v0.0": { - "boost": { - "type": "Direct", - "requested": "[1.84.0, )", - "resolved": "1.84.0", - "contentHash": "4el2YP3cNJDVFPdzOso+LxGvdWP2rHxML4siq8VdonNypW2m4q503tHfCj6vK0L1UfxioE2hpFGb4ITEua73tg==" - } - }, - "native,Version=v0.0/win10-arm": {}, - "native,Version=v0.0/win10-arm-aot": {}, - "native,Version=v0.0/win10-arm64-aot": {}, - "native,Version=v0.0/win10-x64": {}, - "native,Version=v0.0/win10-x64-aot": {}, - "native,Version=v0.0/win10-x86": {}, - "native,Version=v0.0/win10-x86-aot": {} - } -} \ No newline at end of file diff --git a/vnext/FollyWin32/FollyWin32.vcxproj b/vnext/FollyWin32/FollyWin32.vcxproj deleted file mode 100644 index ef49708a792..00000000000 --- a/vnext/FollyWin32/FollyWin32.vcxproj +++ /dev/null @@ -1,90 +0,0 @@ - - - - {74085F13-2DDE-45E5-A0CA-927AC9D0B953} - StaticLibrary - FollyWin32 - - - - - - Debug - ARM64 - - - Debug - ARM64EC - - - Debug - x64 - - - Release - ARM64 - - - Release - ARM64EC - - - Release - x64 - - - Debug - Win32 - - - Release - Win32 - - - - StaticLibrary - - - - - - - - - - - - - - - - - - - - - - - - - - - _HAS_AUTO_PTR_ETC=1; - FOLLY_CFG_NO_COROUTINES; - FOLLY_NO_CONFIG; - NOMINMAX; - WIN32; - %(PreprocessorDefinitions) - - $(FollyDir) - 4293;%(DisableSpecificWarnings) - - - - - - - - - - \ No newline at end of file diff --git a/vnext/FollyWin32/FollyWin32.vcxproj.filters b/vnext/FollyWin32/FollyWin32.vcxproj.filters deleted file mode 100644 index 02e5a161cf8..00000000000 --- a/vnext/FollyWin32/FollyWin32.vcxproj.filters +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - - {5d5a5cf5-5ff8-4fc2-808b-e3c331873c55} - - - - - portability - - - - - portability - - - \ No newline at end of file diff --git a/vnext/FollyWin32/README.md b/vnext/FollyWin32/README.md deleted file mode 100644 index 702c6746782..00000000000 --- a/vnext/FollyWin32/README.md +++ /dev/null @@ -1 +0,0 @@ -This project is for parts of folly that are win32 only and are necessary for react-native-win32.dll \ No newline at end of file diff --git a/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj b/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj index b57a7440f60..79ae0290a63 100644 --- a/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj +++ b/vnext/IntegrationTests/React.Windows.IntegrationTests.vcxproj @@ -71,9 +71,6 @@ {fca38f3c-7c73-4c47-be4e-32f77fa8538d} - - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} - diff --git a/vnext/IntegrationTests/packages.lock.json b/vnext/IntegrationTests/packages.lock.json index 6148fe67e7e..83590ff79bf 100644 --- a/vnext/IntegrationTests/packages.lock.json +++ b/vnext/IntegrationTests/packages.lock.json @@ -13,12 +13,6 @@ "dependencies": { "boost": "[1.84.0, )" } - }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } } }, "native,Version=v0.0/win": {}, diff --git a/vnext/Microsoft.ReactNative.CsWinRT/packages.experimentalwinui3.lock.json b/vnext/Microsoft.ReactNative.CsWinRT/packages.experimentalwinui3.lock.json index d25c135cf5b..588f1ea5c4f 100644 --- a/vnext/Microsoft.ReactNative.CsWinRT/packages.experimentalwinui3.lock.json +++ b/vnext/Microsoft.ReactNative.CsWinRT/packages.experimentalwinui3.lock.json @@ -154,17 +154,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -175,7 +168,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Microsoft.ReactNative.CsWinRT/packages.lock.json b/vnext/Microsoft.ReactNative.CsWinRT/packages.lock.json index cb77e819ec5..e3b63e5ac90 100644 --- a/vnext/Microsoft.ReactNative.CsWinRT/packages.lock.json +++ b/vnext/Microsoft.ReactNative.CsWinRT/packages.lock.json @@ -154,17 +154,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -175,7 +168,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Microsoft.ReactNative.IntegrationTests/packages.experimentalwinui3.lock.json b/vnext/Microsoft.ReactNative.IntegrationTests/packages.experimentalwinui3.lock.json index e0b8730cdc0..25c0b3872a7 100644 --- a/vnext/Microsoft.ReactNative.IntegrationTests/packages.experimentalwinui3.lock.json +++ b/vnext/Microsoft.ReactNative.IntegrationTests/packages.experimentalwinui3.lock.json @@ -167,17 +167,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -188,7 +181,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Microsoft.ReactNative.IntegrationTests/packages.lock.json b/vnext/Microsoft.ReactNative.IntegrationTests/packages.lock.json index d799ed05e7a..9e8ba532462 100644 --- a/vnext/Microsoft.ReactNative.IntegrationTests/packages.lock.json +++ b/vnext/Microsoft.ReactNative.IntegrationTests/packages.lock.json @@ -167,17 +167,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "microsoft.reactnative": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -188,7 +181,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Microsoft.ReactNative.NewArch.Publish.slnf b/vnext/Microsoft.ReactNative.NewArch.Publish.slnf index f66f2caccf0..cde20d62839 100644 --- a/vnext/Microsoft.ReactNative.NewArch.Publish.slnf +++ b/vnext/Microsoft.ReactNative.NewArch.Publish.slnf @@ -3,7 +3,6 @@ "path": "Microsoft.ReactNative.NewArch.sln", "projects": [ "Common\\Common.vcxproj", - "Folly\\Folly.vcxproj", "Microsoft.ReactNative\\Microsoft.ReactNative.vcxproj", "Microsoft.ReactNative.CsWinRT\\Microsoft.ReactNative.CsWinRT.csproj", "ReactCommon\\ReactCommon.vcxproj" diff --git a/vnext/Microsoft.ReactNative.NewArch.sln b/vnext/Microsoft.ReactNative.NewArch.sln index ef85e50c06d..9ae89cca183 100644 --- a/vnext/Microsoft.ReactNative.NewArch.sln +++ b/vnext/Microsoft.ReactNative.NewArch.sln @@ -9,8 +9,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative", "Mi EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Common", "Common\Common.vcxproj", "{FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Include", "include\Include.vcxitems", "{EF074BA1-2D54-4D49-A28E-5E040B47CD2E}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Microsoft.ReactNative.Cxx.UnitTests", "Microsoft.ReactNative.Cxx.UnitTests\Microsoft.ReactNative.Cxx.UnitTests.vcxproj", "{6C60E295-C8CA-4DC5-B8BE-09888F58B249}" @@ -140,18 +138,6 @@ Global {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x64.Build.0 = Release|x64 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.ActiveCfg = Release|Win32 {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D}.Release|x86.Build.0 = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {6C60E295-C8CA-4DC5-B8BE-09888F58B249}.Debug|ARM64.ActiveCfg = Debug|Win32 {6C60E295-C8CA-4DC5-B8BE-09888F58B249}.Debug|x64.ActiveCfg = Debug|x64 {6C60E295-C8CA-4DC5-B8BE-09888F58B249}.Debug|x64.Build.0 = Debug|x64 @@ -212,7 +198,6 @@ Global EndGlobalSection GlobalSection(NestedProjects) = preSolution {FCA38F3C-7C73-4C47-BE4E-32F77FA8538D} = {6348365C-E58A-4CB4-96CA-E2A6C1201DD6} - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {814A1893-F3C3-45BA-8C80-5377CFD86C5F} {EF074BA1-2D54-4D49-A28E-5E040B47CD2E} = {6348365C-E58A-4CB4-96CA-E2A6C1201DD6} {6C60E295-C8CA-4DC5-B8BE-09888F58B249} = {25C4DA8C-A4D2-4D5F-950A-E5371A8AB659} {84E05BFA-CBAF-4F0D-BFB6-4CE85742A57E} = {6348365C-E58A-4CB4-96CA-E2A6C1201DD6} diff --git a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj index 54e88d81607..f30c1e60de7 100644 --- a/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +++ b/vnext/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj @@ -412,15 +412,12 @@ - + {fca38f3c-7c73-4c47-be4e-32f77fa8538d} - - {a990658c-ce31-4bcc-976f-0fc6b1af693d} - {a9d95a91-4db7-4f72-beb6-fe8a5c89bfbd} diff --git a/vnext/Microsoft.ReactNative/packages.experimentalwinui3.lock.json b/vnext/Microsoft.ReactNative/packages.experimentalwinui3.lock.json index bdbbace5db8..5ee89bc64be 100644 --- a/vnext/Microsoft.ReactNative/packages.experimentalwinui3.lock.json +++ b/vnext/Microsoft.ReactNative/packages.experimentalwinui3.lock.json @@ -157,16 +157,9 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/Microsoft.ReactNative/packages.lock.json b/vnext/Microsoft.ReactNative/packages.lock.json index 1048682e974..b8d8cf1ae32 100644 --- a/vnext/Microsoft.ReactNative/packages.lock.json +++ b/vnext/Microsoft.ReactNative/packages.lock.json @@ -157,16 +157,9 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/PropertySheets/React.Cpp.props b/vnext/PropertySheets/React.Cpp.props index 5d93b4044fc..84f365ce060 100644 --- a/vnext/PropertySheets/React.Cpp.props +++ b/vnext/PropertySheets/React.Cpp.props @@ -142,9 +142,9 @@ - $(FollyDir); + $(ExternalDir)folly; $(ExternalDir)fmt\include; - $(FastFloatDir)include; + $(ExternalDir)fast-float\include; $(ReactNativeDir)\ReactCommon; $(ReactNativeDir)\ReactCommon\callinvoker; $(ReactNativeDir)\ReactCommon\jsi; diff --git a/vnext/ReactCommon.UnitTests/packages.experimentalwinui3.lock.json b/vnext/ReactCommon.UnitTests/packages.experimentalwinui3.lock.json index 8f72cb5618c..3606d2ad3f9 100644 --- a/vnext/ReactCommon.UnitTests/packages.experimentalwinui3.lock.json +++ b/vnext/ReactCommon.UnitTests/packages.experimentalwinui3.lock.json @@ -160,24 +160,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[2.0.0-experimental3, )", @@ -189,7 +175,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/ReactCommon.UnitTests/packages.lock.json b/vnext/ReactCommon.UnitTests/packages.lock.json index e7e6709c7e1..3b6e73b1f24 100644 --- a/vnext/ReactCommon.UnitTests/packages.lock.json +++ b/vnext/ReactCommon.UnitTests/packages.lock.json @@ -160,24 +160,10 @@ "boost": "[1.84.0, )" } }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } - }, - "follywin32": { - "type": "Project", - "dependencies": { - "Folly": "[1.0.0, )" - } - }, "react.windows.desktop": { "type": "Project", "dependencies": { "Common": "[1.0.0, )", - "Folly": "[1.0.0, )", - "FollyWin32": "[1.0.0, )", "Microsoft.JavaScript.Hermes": "[0.0.0-2512.22001-bc3d0ed7, )", "Microsoft.SourceLink.GitHub": "[1.1.1, )", "Microsoft.WindowsAppSDK": "[1.8.260209005, )", @@ -189,7 +175,6 @@ "reactcommon": { "type": "Project", "dependencies": { - "Folly": "[1.0.0, )", "boost": "[1.84.0, )" } } diff --git a/vnext/ReactCommon/ReactCommon.vcxproj b/vnext/ReactCommon/ReactCommon.vcxproj index 7a053eda7fc..2e7e289541e 100644 --- a/vnext/ReactCommon/ReactCommon.vcxproj +++ b/vnext/ReactCommon/ReactCommon.vcxproj @@ -239,11 +239,6 @@ - - - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} - - diff --git a/vnext/ReactCommon/packages.lock.json b/vnext/ReactCommon/packages.lock.json index a08a1916575..7cfe05b6c48 100644 --- a/vnext/ReactCommon/packages.lock.json +++ b/vnext/ReactCommon/packages.lock.json @@ -13,12 +13,6 @@ "requested": "[2.0.230706.1, )", "resolved": "2.0.230706.1", "contentHash": "l0D7oCw/5X+xIKHqZTi62TtV+1qeSz7KVluNFdrJ9hXsst4ghvqQ/Yhura7JqRdZWBXAuDS0G0KwALptdoxweQ==" - }, - "folly": { - "type": "Project", - "dependencies": { - "boost": "[1.84.0, )" - } } }, "native,Version=v0.0/win10-arm": {}, diff --git a/vnext/ReactWindows-Desktop.Publish.slnf b/vnext/ReactWindows-Desktop.Publish.slnf index 0fe3c29c540..649e0e0a119 100644 --- a/vnext/ReactWindows-Desktop.Publish.slnf +++ b/vnext/ReactWindows-Desktop.Publish.slnf @@ -5,8 +5,6 @@ "Common\\Common.vcxproj", "Desktop\\React.Windows.Desktop.vcxproj", "Desktop.DLL\\React.Windows.Desktop.DLL.vcxproj", - "Folly\\Folly.vcxproj", - "FollyWin32\\FollyWin32.vcxproj", "ReactCommon\\ReactCommon.vcxproj" ] } diff --git a/vnext/ReactWindows-Desktop.sln b/vnext/ReactWindows-Desktop.sln index 91f549530d8..cfddcb84673 100644 --- a/vnext/ReactWindows-Desktop.sln +++ b/vnext/ReactWindows-Desktop.sln @@ -2,18 +2,12 @@ # Visual Studio Version 18 VisualStudioVersion = 18.2.11415.280 MinimumVisualStudioVersion = 10.0.40219.1 -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Folly", "Folly\Folly.vcxproj", "{A990658C-CE31-4BCC-976F-0FC6B1AF693D}" -EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ReactCommon", "ReactCommon\ReactCommon.vcxproj", "{A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}" ProjectSection(ProjectDependencies) = postProject - {74085F13-2DDE-45E5-A0CA-927AC9D0B953} = {74085F13-2DDE-45E5-A0CA-927AC9D0B953} - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} EndProjectSection EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "React.Windows.Desktop.DLL", "Desktop.DLL\React.Windows.Desktop.DLL.vcxproj", "{88BAB0FA-E1AC-4DA7-A30C-F91702A8EADB}" ProjectSection(ProjectDependencies) = postProject - {74085F13-2DDE-45E5-A0CA-927AC9D0B953} = {74085F13-2DDE-45E5-A0CA-927AC9D0B953} - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {A990658C-CE31-4BCC-976F-0FC6B1AF693D} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} EndProjectSection EndProject @@ -28,8 +22,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution README.md = README.md EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "FollyWin32", "FollyWin32\FollyWin32.vcxproj", "{74085F13-2DDE-45E5-A0CA-927AC9D0B953}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "PropertySheets", "PropertySheets", "{6F24927E-EE45-4DB2-91DA-DCC6E98B0C42}" ProjectSection(SolutionItems) = preProject PropertySheets\Debug.props = PropertySheets\Debug.props @@ -115,22 +107,6 @@ Global Release|ARM64EC = Release|ARM64EC EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64.Build.0 = Debug|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|ARM64EC.Build.0 = Debug|ARM64EC - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.ActiveCfg = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x64.Build.0 = Debug|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.ActiveCfg = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Debug|x86.Build.0 = Debug|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.ActiveCfg = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64.Build.0 = Release|ARM64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64EC.ActiveCfg = Release|ARM64EC - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|ARM64EC.Build.0 = Release|ARM64EC - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.ActiveCfg = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x64.Build.0 = Release|x64 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.ActiveCfg = Release|Win32 - {A990658C-CE31-4BCC-976F-0FC6B1AF693D}.Release|x86.Build.0 = Release|Win32 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.ActiveCfg = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64.Build.0 = Debug|ARM64 {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC @@ -175,22 +151,6 @@ Global {96CD24DC-91C2-480A-BC26-EE2250DA80D7}.Release|x64.Build.0 = Release|x64 {96CD24DC-91C2-480A-BC26-EE2250DA80D7}.Release|x86.ActiveCfg = Release|Win32 {96CD24DC-91C2-480A-BC26-EE2250DA80D7}.Release|x86.Build.0 = Release|Win32 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|ARM64.ActiveCfg = Debug|ARM64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|ARM64.Build.0 = Debug|ARM64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|ARM64EC.Build.0 = Debug|ARM64EC - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|x64.ActiveCfg = Debug|x64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|x64.Build.0 = Debug|x64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|x86.ActiveCfg = Debug|Win32 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Debug|x86.Build.0 = Debug|Win32 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|ARM64.ActiveCfg = Release|ARM64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|ARM64.Build.0 = Release|ARM64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|ARM64EC.ActiveCfg = Release|ARM64EC - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|ARM64EC.Build.0 = Release|ARM64EC - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|x64.ActiveCfg = Release|x64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|x64.Build.0 = Release|x64 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|x86.ActiveCfg = Release|Win32 - {74085F13-2DDE-45E5-A0CA-927AC9D0B953}.Release|x86.Build.0 = Release|Win32 {95048601-C3DC-475F-ADF8-7C0C764C10D5}.Debug|ARM64.ActiveCfg = Debug|ARM64 {95048601-C3DC-475F-ADF8-7C0C764C10D5}.Debug|ARM64.Build.0 = Debug|ARM64 {95048601-C3DC-475F-ADF8-7C0C764C10D5}.Debug|ARM64EC.ActiveCfg = Debug|ARM64EC @@ -304,9 +264,7 @@ Global HideSolutionNode = FALSE EndGlobalSection GlobalSection(NestedProjects) = preSolution - {A990658C-CE31-4BCC-976F-0FC6B1AF693D} = {41F31595-2F20-4D6B-A6CF-60444415012A} {A9D95A91-4DB7-4F72-BEB6-FE8A5C89BFBD} = {F90FDFD1-2C76-4DCD-B248-F6FB2BB15BDF} - {74085F13-2DDE-45E5-A0CA-927AC9D0B953} = {41F31595-2F20-4D6B-A6CF-60444415012A} {43A78B84-278B-4B99-8887-4029D551173E} = {6F24927E-EE45-4DB2-91DA-DCC6E98B0C42} {102E37B8-4BE5-4DC1-A650-16706EFB3306} = {6F24927E-EE45-4DB2-91DA-DCC6E98B0C42} {2EB5E646-7EB4-4FED-B1A8-0AEEF2D32268} = {6F24927E-EE45-4DB2-91DA-DCC6E98B0C42} diff --git a/vnext/Scripts/Tfs/Layout-Desktop-Headers.ps1 b/vnext/Scripts/Tfs/Layout-Desktop-Headers.ps1 index bdb5468bd2f..ab515dea1a0 100644 --- a/vnext/Scripts/Tfs/Layout-Desktop-Headers.ps1 +++ b/vnext/Scripts/Tfs/Layout-Desktop-Headers.ps1 @@ -9,27 +9,10 @@ param( [string[]] $Extensions = ('h', 'hpp', 'def') ) -[xml]$props = gc $PSScriptRoot\..\..\Directory.Build.props -[string] $FollyVersion = $props.Project.PropertyGroup.FollyVersion; -$FollyVersion = $FollyVersion.Trim() # The extracted FollyVersion contains a space at the end that isn't actually present, issue #6216 -$FollyRoot = "$SourceRoot\node_modules\.folly"; -$FollyOverrideRoot = "$ReactWindowsRoot\Folly\TEMP_UntilFollyUpdate"; - +# Folly and fmt source are committed in vnext/external/ — no download needed +$FollyRoot = "$ReactWindowsRoot\external\folly"; $FmtRoot = "$ReactWindowsRoot\external\fmt"; -# Download Folly if running on a machine which hasn't run native build logic to acquire it -if (!(Test-Path $FollyRoot)) { - Write-Host "Downloading Folly $FollyVersion" - $FollyZip = "$SourceRoot\node_modules\.folly\folly-${FollyVersion}.zip" - $FollyDest = "$SourceRoot\node_modules\.folly" - - New-Item $FollyRoot -ItemType Directory - Invoke-RestMethod -Uri "https://github.com/facebook/folly/archive/v$FollyVersion.zip" -OutFile $FollyZip - Expand-Archive -LiteralPath $FollyZip -DestinationPath $FollyRoot -} - -# Fmt source is committed in vnext/external/fmt/ — no download needed - Write-Host "Source root: [$SourceRoot]" Write-Host "Destination root: [$TargetRoot]" Write-Host "React Native root: [$ReactNativeRoot]" @@ -59,13 +42,6 @@ Get-ChildItem -Path $FollyRoot -Name -Recurse -Include $patterns | ForEach-Objec -Force } -# Folly overrides -Get-ChildItem -Path $FollyOverrideRoot -Name -Recurse -Include $patterns | ForEach-Object { Copy-Item ` - -Path $FollyOverrideRoot\$_ ` - -Destination (New-Item -ItemType Directory $TargetRoot\inc\folly\folly-$FollyVersion\folly\$(Split-Path $_) -Force) ` - -Force -} - # Fmt headers Get-ChildItem -Path $FmtRoot\include -Name -Recurse -Include $patterns | ForEach-Object { Copy-Item ` -Path $FmtRoot\include\$_ ` @@ -104,4 +80,4 @@ Get-ChildItem -Path $ReactWindowsRoot\Desktop.DLL -Recurse -Include '*.def' | Fo Copy-Item -Force -Recurse -Path $ReactWindowsRoot\include -Destination $TargetRoot\inc # Natvis files -Copy-Item -Force -Path $ReactWindowsRoot\Folly\Folly.natvis -Destination (New-Item -ItemType Directory $TargetRoot\natvis -Force) +Copy-Item -Force -Path $ReactWindowsRoot\external\folly\Folly.natvis -Destination (New-Item -ItemType Directory $TargetRoot\natvis -Force) diff --git a/vnext/external/External.vcxitems b/vnext/external/External.vcxitems index bb92959e565..9a26423a73b 100644 --- a/vnext/external/External.vcxitems +++ b/vnext/external/External.vcxitems @@ -5,4 +5,6 @@ --> + + diff --git a/vnext/external/fast-float/.syncignore b/vnext/external/fast-float/.syncignore new file mode 100644 index 00000000000..d1ef4566536 --- /dev/null +++ b/vnext/external/fast-float/.syncignore @@ -0,0 +1,12 @@ +/sync-config.json +/.syncignore +/cgmanifest.json +/CMakeLists.txt +/cmake/ +/tests/ +/benchmarks/ +/script/ +/.github/ +/CONTRIBUTORS +/README.md +/LICENSE* diff --git a/vnext/external/fast-float/cgmanifest.json b/vnext/external/fast-float/cgmanifest.json new file mode 100644 index 00000000000..f5029846788 --- /dev/null +++ b/vnext/external/fast-float/cgmanifest.json @@ -0,0 +1,15 @@ +{ + "$schema": "https://json.schemastore.org/component-detection-manifest.json", + "Registrations": [ + { + "Component": { + "Type": "git", + "Git": { + "RepositoryUrl": "https://github.com/fastfloat/fast_float", + "CommitHash": "77cc847c842c49e7e3477c1e95da2b6540166d66" + } + }, + "DevelopmentDependency": false + } + ] +} diff --git a/vnext/external/fast-float/fast-float.vcxitems b/vnext/external/fast-float/fast-float.vcxitems new file mode 100644 index 00000000000..68207f7a2b0 --- /dev/null +++ b/vnext/external/fast-float/fast-float.vcxitems @@ -0,0 +1,14 @@ + + + + + + + + + + + + + + diff --git a/vnext/external/fast-float/include/fast_float/ascii_number.h b/vnext/external/fast-float/include/fast_float/ascii_number.h new file mode 100644 index 00000000000..9001016ac61 --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/ascii_number.h @@ -0,0 +1,588 @@ +#ifndef FASTFLOAT_ASCII_NUMBER_H +#define FASTFLOAT_ASCII_NUMBER_H + +#include +#include +#include +#include +#include +#include + +#include "float_common.h" + +#ifdef FASTFLOAT_SSE2 +#include +#endif + +#ifdef FASTFLOAT_NEON +#include +#endif + +namespace fast_float { + +template fastfloat_really_inline constexpr bool has_simd_opt() { +#ifdef FASTFLOAT_HAS_SIMD + return std::is_same::value; +#else + return false; +#endif +} + +// Next function can be micro-optimized, but compilers are entirely +// able to optimize it well. +template +fastfloat_really_inline constexpr bool is_integer(UC c) noexcept { + return !(c > UC('9') || c < UC('0')); +} + +fastfloat_really_inline constexpr uint64_t byteswap(uint64_t val) { + return (val & 0xFF00000000000000) >> 56 | (val & 0x00FF000000000000) >> 40 | + (val & 0x0000FF0000000000) >> 24 | (val & 0x000000FF00000000) >> 8 | + (val & 0x00000000FF000000) << 8 | (val & 0x0000000000FF0000) << 24 | + (val & 0x000000000000FF00) << 40 | (val & 0x00000000000000FF) << 56; +} + +// Read 8 UC into a u64. Truncates UC if not char. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +read8_to_u64(UC const *chars) { + if (cpp20_and_in_constexpr() || !std::is_same::value) { + uint64_t val = 0; + for (int i = 0; i < 8; ++i) { + val |= uint64_t(uint8_t(*chars)) << (i * 8); + ++chars; + } + return val; + } + uint64_t val; + ::memcpy(&val, chars, sizeof(uint64_t)); +#if FASTFLOAT_IS_BIG_ENDIAN == 1 + // Need to read as-if the number was in little-endian order. + val = byteswap(val); +#endif + return val; +} + +#ifdef FASTFLOAT_SSE2 + +fastfloat_really_inline uint64_t simd_read8_to_u64(__m128i const data) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + __m128i const packed = _mm_packus_epi16(data, data); +#ifdef FASTFLOAT_64BIT + return uint64_t(_mm_cvtsi128_si64(packed)); +#else + uint64_t value; + // Visual Studio + older versions of GCC don't support _mm_storeu_si64 + _mm_storel_epi64(reinterpret_cast<__m128i *>(&value), packed); + return value; +#endif + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + return simd_read8_to_u64( + _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars))); + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +#elif defined(FASTFLOAT_NEON) + +fastfloat_really_inline uint64_t simd_read8_to_u64(uint16x8_t const data) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + uint8x8_t utf8_packed = vmovn_u16(data); + return vget_lane_u64(vreinterpret_u64_u8(utf8_packed), 0); + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +fastfloat_really_inline uint64_t simd_read8_to_u64(char16_t const *chars) { + FASTFLOAT_SIMD_DISABLE_WARNINGS + return simd_read8_to_u64( + vld1q_u16(reinterpret_cast(chars))); + FASTFLOAT_SIMD_RESTORE_WARNINGS +} + +#endif // FASTFLOAT_SSE2 + +// MSVC SFINAE is broken pre-VS2017 +#if defined(_MSC_VER) && _MSC_VER <= 1900 +template +#else +template ()) = 0> +#endif +// dummy for compile +uint64_t simd_read8_to_u64(UC const *) { + return 0; +} + +// credit @aqrit +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint32_t +parse_eight_digits_unrolled(uint64_t val) { + uint64_t const mask = 0x000000FF000000FF; + uint64_t const mul1 = 0x000F424000000064; // 100 + (1000000ULL << 32) + uint64_t const mul2 = 0x0000271000000001; // 1 + (10000ULL << 32) + val -= 0x3030303030303030; + val = (val * 10) + (val >> 8); // val = (val * 2561) >> 8; + val = (((val & mask) * mul1) + (((val >> 16) & mask) * mul2)) >> 32; + return uint32_t(val); +} + +// Call this if chars are definitely 8 digits. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint32_t +parse_eight_digits_unrolled(UC const *chars) noexcept { + if (cpp20_and_in_constexpr() || !has_simd_opt()) { + return parse_eight_digits_unrolled(read8_to_u64(chars)); // truncation okay + } + return parse_eight_digits_unrolled(simd_read8_to_u64(chars)); +} + +// credit @aqrit +fastfloat_really_inline constexpr bool +is_made_of_eight_digits_fast(uint64_t val) noexcept { + return !((((val + 0x4646464646464646) | (val - 0x3030303030303030)) & + 0x8080808080808080)); +} + +#ifdef FASTFLOAT_HAS_SIMD + +// Call this if chars might not be 8 digits. +// Using this style (instead of is_made_of_eight_digits_fast() then +// parse_eight_digits_unrolled()) ensures we don't load SIMD registers twice. +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +simd_parse_if_eight_digits_unrolled(char16_t const *chars, + uint64_t &i) noexcept { + if (cpp20_and_in_constexpr()) { + return false; + } +#ifdef FASTFLOAT_SSE2 + FASTFLOAT_SIMD_DISABLE_WARNINGS + __m128i const data = + _mm_loadu_si128(reinterpret_cast<__m128i const *>(chars)); + + // (x - '0') <= 9 + // http://0x80.pl/articles/simd-parsing-int-sequences.html + __m128i const t0 = _mm_add_epi16(data, _mm_set1_epi16(32720)); + __m128i const t1 = _mm_cmpgt_epi16(t0, _mm_set1_epi16(-32759)); + + if (_mm_movemask_epi8(t1) == 0) { + i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); + return true; + } else + return false; + FASTFLOAT_SIMD_RESTORE_WARNINGS +#elif defined(FASTFLOAT_NEON) + FASTFLOAT_SIMD_DISABLE_WARNINGS + uint16x8_t const data = vld1q_u16(reinterpret_cast(chars)); + + // (x - '0') <= 9 + // http://0x80.pl/articles/simd-parsing-int-sequences.html + uint16x8_t const t0 = vsubq_u16(data, vmovq_n_u16('0')); + uint16x8_t const mask = vcltq_u16(t0, vmovq_n_u16('9' - '0' + 1)); + + if (vminvq_u16(mask) == 0xFFFF) { + i = i * 100000000 + parse_eight_digits_unrolled(simd_read8_to_u64(data)); + return true; + } else + return false; + FASTFLOAT_SIMD_RESTORE_WARNINGS +#else + (void)chars; + (void)i; + return false; +#endif // FASTFLOAT_SSE2 +} + +#endif // FASTFLOAT_HAS_SIMD + +// MSVC SFINAE is broken pre-VS2017 +#if defined(_MSC_VER) && _MSC_VER <= 1900 +template +#else +template ()) = 0> +#endif +// dummy for compile +bool simd_parse_if_eight_digits_unrolled(UC const *, uint64_t &) { + return 0; +} + +template ::value) = 0> +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +loop_parse_if_eight_digits(UC const *&p, UC const *const pend, uint64_t &i) { + if (!has_simd_opt()) { + return; + } + while ((std::distance(p, pend) >= 8) && + simd_parse_if_eight_digits_unrolled( + p, i)) { // in rare cases, this will overflow, but that's ok + p += 8; + } +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +loop_parse_if_eight_digits(char const *&p, char const *const pend, + uint64_t &i) { + // optimizes better than parse_if_eight_digits_unrolled() for UC = char. + while ((std::distance(p, pend) >= 8) && + is_made_of_eight_digits_fast(read8_to_u64(p))) { + i = i * 100000000 + + parse_eight_digits_unrolled(read8_to_u64( + p)); // in rare cases, this will overflow, but that's ok + p += 8; + } +} + +enum class parse_error { + no_error, + // [JSON-only] The minus sign must be followed by an integer. + missing_integer_after_sign, + // A sign must be followed by an integer or dot. + missing_integer_or_dot_after_sign, + // [JSON-only] The integer part must not have leading zeros. + leading_zeros_in_integer_part, + // [JSON-only] The integer part must have at least one digit. + no_digits_in_integer_part, + // [JSON-only] If there is a decimal point, there must be digits in the + // fractional part. + no_digits_in_fractional_part, + // The mantissa must have at least one digit. + no_digits_in_mantissa, + // Scientific notation requires an exponential part. + missing_exponential_part, +}; + +template struct parsed_number_string_t { + int64_t exponent{0}; + uint64_t mantissa{0}; + UC const *lastmatch{nullptr}; + bool negative{false}; + bool valid{false}; + bool too_many_digits{false}; + // contains the range of the significant digits + span integer{}; // non-nullable + span fraction{}; // nullable + parse_error error{parse_error::no_error}; +}; + +using byte_span = span; +using parsed_number_string = parsed_number_string_t; + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t +report_parse_error(UC const *p, parse_error error) { + parsed_number_string_t answer; + answer.valid = false; + answer.lastmatch = p; + answer.error = error; + return answer; +} + +// Assuming that you use no more than 19 digits, this will +// parse an ASCII string. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 parsed_number_string_t +parse_number_string(UC const *p, UC const *pend, + parse_options_t options) noexcept { + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + UC const decimal_point = options.decimal_point; + + parsed_number_string_t answer; + answer.valid = false; + answer.too_many_digits = false; + // assume p < pend, so dereference without checks; + answer.negative = (*p == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*p == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && + !uint64_t(fmt & detail::basic_json_fmt) && *p == UC('+'))) { + ++p; + if (p == pend) { + return report_parse_error( + p, parse_error::missing_integer_or_dot_after_sign); + } + if (uint64_t(fmt & detail::basic_json_fmt)) { + if (!is_integer(*p)) { // a sign must be followed by an integer + return report_parse_error(p, + parse_error::missing_integer_after_sign); + } + } else { + if (!is_integer(*p) && + (*p != + decimal_point)) { // a sign must be followed by an integer or the dot + return report_parse_error( + p, parse_error::missing_integer_or_dot_after_sign); + } + } + } + UC const *const start_digits = p; + + uint64_t i = 0; // an unsigned int avoids signed overflows (which are bad) + + while ((p != pend) && is_integer(*p)) { + // a multiplication by 10 is cheaper than an arbitrary integer + // multiplication + i = 10 * i + + uint64_t(*p - + UC('0')); // might overflow, we will handle the overflow later + ++p; + } + UC const *const end_of_integer_part = p; + int64_t digit_count = int64_t(end_of_integer_part - start_digits); + answer.integer = span(start_digits, size_t(digit_count)); + if (uint64_t(fmt & detail::basic_json_fmt)) { + // at least 1 digit in integer part, without leading zeros + if (digit_count == 0) { + return report_parse_error(p, parse_error::no_digits_in_integer_part); + } + if ((start_digits[0] == UC('0') && digit_count > 1)) { + return report_parse_error(start_digits, + parse_error::leading_zeros_in_integer_part); + } + } + + int64_t exponent = 0; + bool const has_decimal_point = (p != pend) && (*p == decimal_point); + if (has_decimal_point) { + ++p; + UC const *before = p; + // can occur at most twice without overflowing, but let it occur more, since + // for integers with many digits, digit parsing is the primary bottleneck. + loop_parse_if_eight_digits(p, pend, i); + + while ((p != pend) && is_integer(*p)) { + uint8_t digit = uint8_t(*p - UC('0')); + ++p; + i = i * 10 + digit; // in rare cases, this will overflow, but that's ok + } + exponent = before - p; + answer.fraction = span(before, size_t(p - before)); + digit_count -= exponent; + } + if (uint64_t(fmt & detail::basic_json_fmt)) { + // at least 1 digit in fractional part + if (has_decimal_point && exponent == 0) { + return report_parse_error(p, + parse_error::no_digits_in_fractional_part); + } + } else if (digit_count == + 0) { // we must have encountered at least one integer! + return report_parse_error(p, parse_error::no_digits_in_mantissa); + } + int64_t exp_number = 0; // explicit exponential part + if ((uint64_t(fmt & chars_format::scientific) && (p != pend) && + ((UC('e') == *p) || (UC('E') == *p))) || + (uint64_t(fmt & detail::basic_fortran_fmt) && (p != pend) && + ((UC('+') == *p) || (UC('-') == *p) || (UC('d') == *p) || + (UC('D') == *p)))) { + UC const *location_of_e = p; + if ((UC('e') == *p) || (UC('E') == *p) || (UC('d') == *p) || + (UC('D') == *p)) { + ++p; + } + bool neg_exp = false; + if ((p != pend) && (UC('-') == *p)) { + neg_exp = true; + ++p; + } else if ((p != pend) && + (UC('+') == + *p)) { // '+' on exponent is allowed by C++17 20.19.3.(7.1) + ++p; + } + if ((p == pend) || !is_integer(*p)) { + if (!uint64_t(fmt & chars_format::fixed)) { + // The exponential part is invalid for scientific notation, so it must + // be a trailing token for fixed notation. However, fixed notation is + // disabled, so report a scientific notation error. + return report_parse_error(p, parse_error::missing_exponential_part); + } + // Otherwise, we will be ignoring the 'e'. + p = location_of_e; + } else { + while ((p != pend) && is_integer(*p)) { + uint8_t digit = uint8_t(*p - UC('0')); + if (exp_number < 0x10000000) { + exp_number = 10 * exp_number + digit; + } + ++p; + } + if (neg_exp) { + exp_number = -exp_number; + } + exponent += exp_number; + } + } else { + // If it scientific and not fixed, we have to bail out. + if (uint64_t(fmt & chars_format::scientific) && + !uint64_t(fmt & chars_format::fixed)) { + return report_parse_error(p, parse_error::missing_exponential_part); + } + } + answer.lastmatch = p; + answer.valid = true; + + // If we frequently had to deal with long strings of digits, + // we could extend our code by using a 128-bit integer instead + // of a 64-bit integer. However, this is uncommon. + // + // We can deal with up to 19 digits. + if (digit_count > 19) { // this is uncommon + // It is possible that the integer had an overflow. + // We have to handle the case where we have 0.0000somenumber. + // We need to be mindful of the case where we only have zeroes... + // E.g., 0.000000000...000. + UC const *start = start_digits; + while ((start != pend) && (*start == UC('0') || *start == decimal_point)) { + if (*start == UC('0')) { + digit_count--; + } + start++; + } + + if (digit_count > 19) { + answer.too_many_digits = true; + // Let us start again, this time, avoiding overflows. + // We don't need to check if is_integer, since we use the + // pre-tokenized spans from above. + i = 0; + p = answer.integer.ptr; + UC const *int_end = p + answer.integer.len(); + uint64_t const minimal_nineteen_digit_integer{1000000000000000000}; + while ((i < minimal_nineteen_digit_integer) && (p != int_end)) { + i = i * 10 + uint64_t(*p - UC('0')); + ++p; + } + if (i >= minimal_nineteen_digit_integer) { // We have a big integers + exponent = end_of_integer_part - p + exp_number; + } else { // We have a value with a fractional component. + p = answer.fraction.ptr; + UC const *frac_end = p + answer.fraction.len(); + while ((i < minimal_nineteen_digit_integer) && (p != frac_end)) { + i = i * 10 + uint64_t(*p - UC('0')); + ++p; + } + exponent = answer.fraction.ptr - p + exp_number; + } + // We have now corrected both exponent and i, to a truncated value + } + } + answer.exponent = exponent; + answer.mantissa = i; + return answer; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 from_chars_result_t +parse_int_string(UC const *p, UC const *pend, T &value, + parse_options_t options) { + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + int const base = options.base; + + from_chars_result_t answer; + + UC const *const first = p; + + bool const negative = (*p == UC('-')); +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(push) +#pragma warning(disable : 4127) +#endif + if (!std::is_signed::value && negative) { +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(pop) +#endif + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + if ((*p == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && (*p == UC('+')))) { + ++p; + } + + UC const *const start_num = p; + + while (p != pend && *p == UC('0')) { + ++p; + } + + bool const has_leading_zeros = p > start_num; + + UC const *const start_digits = p; + + uint64_t i = 0; + if (base == 10) { + loop_parse_if_eight_digits(p, pend, i); // use SIMD if possible + } + while (p != pend) { + uint8_t digit = ch_to_digit(*p); + if (digit >= base) { + break; + } + i = uint64_t(base) * i + digit; // might overflow, check this later + p++; + } + + size_t digit_count = size_t(p - start_digits); + + if (digit_count == 0) { + if (has_leading_zeros) { + value = 0; + answer.ec = std::errc(); + answer.ptr = p; + } else { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + } + return answer; + } + + answer.ptr = p; + + // check u64 overflow + size_t max_digits = max_digits_u64(base); + if (digit_count > max_digits) { + answer.ec = std::errc::result_out_of_range; + return answer; + } + // this check can be eliminated for all other types, but they will all require + // a max_digits(base) equivalent + if (digit_count == max_digits && i < min_safe_u64(base)) { + answer.ec = std::errc::result_out_of_range; + return answer; + } + + // check other types overflow + if (!std::is_same::value) { + if (i > uint64_t(std::numeric_limits::max()) + uint64_t(negative)) { + answer.ec = std::errc::result_out_of_range; + return answer; + } + } + + if (negative) { +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(push) +#pragma warning(disable : 4146) +#endif + // this weird workaround is required because: + // - converting unsigned to signed when its value is greater than signed max + // is UB pre-C++23. + // - reinterpret_casting (~i + 1) would work, but it is not constexpr + // this is always optimized into a neg instruction (note: T is an integer + // type) + value = T(-std::numeric_limits::max() - + T(i - uint64_t(std::numeric_limits::max()))); +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(pop) +#endif + } else { + value = T(i); + } + + answer.ec = std::errc(); + return answer; +} + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/include/fast_float/bigint.h b/vnext/external/fast-float/include/fast_float/bigint.h new file mode 100644 index 00000000000..74901e3956f --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/bigint.h @@ -0,0 +1,638 @@ +#ifndef FASTFLOAT_BIGINT_H +#define FASTFLOAT_BIGINT_H + +#include +#include +#include +#include + +#include "float_common.h" + +namespace fast_float { + +// the limb width: we want efficient multiplication of double the bits in +// limb, or for 64-bit limbs, at least 64-bit multiplication where we can +// extract the high and low parts efficiently. this is every 64-bit +// architecture except for sparc, which emulates 128-bit multiplication. +// we might have platforms where `CHAR_BIT` is not 8, so let's avoid +// doing `8 * sizeof(limb)`. +#if defined(FASTFLOAT_64BIT) && !defined(__sparc) +#define FASTFLOAT_64BIT_LIMB 1 +typedef uint64_t limb; +constexpr size_t limb_bits = 64; +#else +#define FASTFLOAT_32BIT_LIMB +typedef uint32_t limb; +constexpr size_t limb_bits = 32; +#endif + +typedef span limb_span; + +// number of bits in a bigint. this needs to be at least the number +// of bits required to store the largest bigint, which is +// `log2(10**(digits + max_exp))`, or `log2(10**(767 + 342))`, or +// ~3600 bits, so we round to 4000. +constexpr size_t bigint_bits = 4000; +constexpr size_t bigint_limbs = bigint_bits / limb_bits; + +// vector-like type that is allocated on the stack. the entire +// buffer is pre-allocated, and only the length changes. +template struct stackvec { + limb data[size]; + // we never need more than 150 limbs + uint16_t length{0}; + + stackvec() = default; + stackvec(stackvec const &) = delete; + stackvec &operator=(stackvec const &) = delete; + stackvec(stackvec &&) = delete; + stackvec &operator=(stackvec &&other) = delete; + + // create stack vector from existing limb span. + FASTFLOAT_CONSTEXPR20 stackvec(limb_span s) { + FASTFLOAT_ASSERT(try_extend(s)); + } + + FASTFLOAT_CONSTEXPR14 limb &operator[](size_t index) noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + return data[index]; + } + + FASTFLOAT_CONSTEXPR14 const limb &operator[](size_t index) const noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + return data[index]; + } + + // index from the end of the container + FASTFLOAT_CONSTEXPR14 const limb &rindex(size_t index) const noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + size_t rindex = length - index - 1; + return data[rindex]; + } + + // set the length, without bounds checking. + FASTFLOAT_CONSTEXPR14 void set_len(size_t len) noexcept { + length = uint16_t(len); + } + + constexpr size_t len() const noexcept { return length; } + + constexpr bool is_empty() const noexcept { return length == 0; } + + constexpr size_t capacity() const noexcept { return size; } + + // append item to vector, without bounds checking + FASTFLOAT_CONSTEXPR14 void push_unchecked(limb value) noexcept { + data[length] = value; + length++; + } + + // append item to vector, returning if item was added + FASTFLOAT_CONSTEXPR14 bool try_push(limb value) noexcept { + if (len() < capacity()) { + push_unchecked(value); + return true; + } else { + return false; + } + } + + // add items to the vector, from a span, without bounds checking + FASTFLOAT_CONSTEXPR20 void extend_unchecked(limb_span s) noexcept { + limb *ptr = data + length; + std::copy_n(s.ptr, s.len(), ptr); + set_len(len() + s.len()); + } + + // try to add items to the vector, returning if items were added + FASTFLOAT_CONSTEXPR20 bool try_extend(limb_span s) noexcept { + if (len() + s.len() <= capacity()) { + extend_unchecked(s); + return true; + } else { + return false; + } + } + + // resize the vector, without bounds checking + // if the new size is longer than the vector, assign value to each + // appended item. + FASTFLOAT_CONSTEXPR20 + void resize_unchecked(size_t new_len, limb value) noexcept { + if (new_len > len()) { + size_t count = new_len - len(); + limb *first = data + len(); + limb *last = first + count; + ::std::fill(first, last, value); + set_len(new_len); + } else { + set_len(new_len); + } + } + + // try to resize the vector, returning if the vector was resized. + FASTFLOAT_CONSTEXPR20 bool try_resize(size_t new_len, limb value) noexcept { + if (new_len > capacity()) { + return false; + } else { + resize_unchecked(new_len, value); + return true; + } + } + + // check if any limbs are non-zero after the given index. + // this needs to be done in reverse order, since the index + // is relative to the most significant limbs. + FASTFLOAT_CONSTEXPR14 bool nonzero(size_t index) const noexcept { + while (index < len()) { + if (rindex(index) != 0) { + return true; + } + index++; + } + return false; + } + + // normalize the big integer, so most-significant zero limbs are removed. + FASTFLOAT_CONSTEXPR14 void normalize() noexcept { + while (len() > 0 && rindex(0) == 0) { + length--; + } + } +}; + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +empty_hi64(bool &truncated) noexcept { + truncated = false; + return 0; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint64_hi64(uint64_t r0, bool &truncated) noexcept { + truncated = false; + int shl = leading_zeroes(r0); + return r0 << shl; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint64_hi64(uint64_t r0, uint64_t r1, bool &truncated) noexcept { + int shl = leading_zeroes(r0); + if (shl == 0) { + truncated = r1 != 0; + return r0; + } else { + int shr = 64 - shl; + truncated = (r1 << shl) != 0; + return (r0 << shl) | (r1 >> shr); + } +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint32_hi64(uint32_t r0, bool &truncated) noexcept { + return uint64_hi64(r0, truncated); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint32_hi64(uint32_t r0, uint32_t r1, bool &truncated) noexcept { + uint64_t x0 = r0; + uint64_t x1 = r1; + return uint64_hi64((x0 << 32) | x1, truncated); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 uint64_t +uint32_hi64(uint32_t r0, uint32_t r1, uint32_t r2, bool &truncated) noexcept { + uint64_t x0 = r0; + uint64_t x1 = r1; + uint64_t x2 = r2; + return uint64_hi64(x0, (x1 << 32) | x2, truncated); +} + +// add two small integers, checking for overflow. +// we want an efficient operation. for msvc, where +// we don't have built-in intrinsics, this is still +// pretty fast. +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb +scalar_add(limb x, limb y, bool &overflow) noexcept { + limb z; +// gcc and clang +#if defined(__has_builtin) +#if __has_builtin(__builtin_add_overflow) + if (!cpp20_and_in_constexpr()) { + overflow = __builtin_add_overflow(x, y, &z); + return z; + } +#endif +#endif + + // generic, this still optimizes correctly on MSVC. + z = x + y; + overflow = z < x; + return z; +} + +// multiply two small integers, getting both the high and low bits. +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 limb +scalar_mul(limb x, limb y, limb &carry) noexcept { +#ifdef FASTFLOAT_64BIT_LIMB +#if defined(__SIZEOF_INT128__) + // GCC and clang both define it as an extension. + __uint128_t z = __uint128_t(x) * __uint128_t(y) + __uint128_t(carry); + carry = limb(z >> limb_bits); + return limb(z); +#else + // fallback, no native 128-bit integer multiplication with carry. + // on msvc, this optimizes identically, somehow. + value128 z = full_multiplication(x, y); + bool overflow; + z.low = scalar_add(z.low, carry, overflow); + z.high += uint64_t(overflow); // cannot overflow + carry = z.high; + return z.low; +#endif +#else + uint64_t z = uint64_t(x) * uint64_t(y) + uint64_t(carry); + carry = limb(z >> limb_bits); + return limb(z); +#endif +} + +// add scalar value to bigint starting from offset. +// used in grade school multiplication +template +inline FASTFLOAT_CONSTEXPR20 bool small_add_from(stackvec &vec, limb y, + size_t start) noexcept { + size_t index = start; + limb carry = y; + bool overflow; + while (carry != 0 && index < vec.len()) { + vec[index] = scalar_add(vec[index], carry, overflow); + carry = limb(overflow); + index += 1; + } + if (carry != 0) { + FASTFLOAT_TRY(vec.try_push(carry)); + } + return true; +} + +// add scalar value to bigint. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +small_add(stackvec &vec, limb y) noexcept { + return small_add_from(vec, y, 0); +} + +// multiply bigint by scalar value. +template +inline FASTFLOAT_CONSTEXPR20 bool small_mul(stackvec &vec, + limb y) noexcept { + limb carry = 0; + for (size_t index = 0; index < vec.len(); index++) { + vec[index] = scalar_mul(vec[index], y, carry); + } + if (carry != 0) { + FASTFLOAT_TRY(vec.try_push(carry)); + } + return true; +} + +// add bigint to bigint starting from index. +// used in grade school multiplication +template +FASTFLOAT_CONSTEXPR20 bool large_add_from(stackvec &x, limb_span y, + size_t start) noexcept { + // the effective x buffer is from `xstart..x.len()`, so exit early + // if we can't get that current range. + if (x.len() < start || y.len() > x.len() - start) { + FASTFLOAT_TRY(x.try_resize(y.len() + start, 0)); + } + + bool carry = false; + for (size_t index = 0; index < y.len(); index++) { + limb xi = x[index + start]; + limb yi = y[index]; + bool c1 = false; + bool c2 = false; + xi = scalar_add(xi, yi, c1); + if (carry) { + xi = scalar_add(xi, 1, c2); + } + x[index + start] = xi; + carry = c1 | c2; + } + + // handle overflow + if (carry) { + FASTFLOAT_TRY(small_add_from(x, 1, y.len() + start)); + } + return true; +} + +// add bigint to bigint. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +large_add_from(stackvec &x, limb_span y) noexcept { + return large_add_from(x, y, 0); +} + +// grade-school multiplication algorithm +template +FASTFLOAT_CONSTEXPR20 bool long_mul(stackvec &x, limb_span y) noexcept { + limb_span xs = limb_span(x.data, x.len()); + stackvec z(xs); + limb_span zs = limb_span(z.data, z.len()); + + if (y.len() != 0) { + limb y0 = y[0]; + FASTFLOAT_TRY(small_mul(x, y0)); + for (size_t index = 1; index < y.len(); index++) { + limb yi = y[index]; + stackvec zi; + if (yi != 0) { + // re-use the same buffer throughout + zi.set_len(0); + FASTFLOAT_TRY(zi.try_extend(zs)); + FASTFLOAT_TRY(small_mul(zi, yi)); + limb_span zis = limb_span(zi.data, zi.len()); + FASTFLOAT_TRY(large_add_from(x, zis, index)); + } + } + } + + x.normalize(); + return true; +} + +// grade-school multiplication algorithm +template +FASTFLOAT_CONSTEXPR20 bool large_mul(stackvec &x, limb_span y) noexcept { + if (y.len() == 1) { + FASTFLOAT_TRY(small_mul(x, y[0])); + } else { + FASTFLOAT_TRY(long_mul(x, y)); + } + return true; +} + +template struct pow5_tables { + static constexpr uint32_t large_step = 135; + static constexpr uint64_t small_power_of_5[] = { + 1UL, + 5UL, + 25UL, + 125UL, + 625UL, + 3125UL, + 15625UL, + 78125UL, + 390625UL, + 1953125UL, + 9765625UL, + 48828125UL, + 244140625UL, + 1220703125UL, + 6103515625UL, + 30517578125UL, + 152587890625UL, + 762939453125UL, + 3814697265625UL, + 19073486328125UL, + 95367431640625UL, + 476837158203125UL, + 2384185791015625UL, + 11920928955078125UL, + 59604644775390625UL, + 298023223876953125UL, + 1490116119384765625UL, + 7450580596923828125UL, + }; +#ifdef FASTFLOAT_64BIT_LIMB + constexpr static limb large_power_of_5[] = { + 1414648277510068013UL, 9180637584431281687UL, 4539964771860779200UL, + 10482974169319127550UL, 198276706040285095UL}; +#else + constexpr static limb large_power_of_5[] = { + 4279965485U, 329373468U, 4020270615U, 2137533757U, 4287402176U, + 1057042919U, 1071430142U, 2440757623U, 381945767U, 46164893U}; +#endif +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template constexpr uint32_t pow5_tables::large_step; + +template constexpr uint64_t pow5_tables::small_power_of_5[]; + +template constexpr limb pow5_tables::large_power_of_5[]; + +#endif + +// big integer type. implements a small subset of big integer +// arithmetic, using simple algorithms since asymptotically +// faster algorithms are slower for a small number of limbs. +// all operations assume the big-integer is normalized. +struct bigint : pow5_tables<> { + // storage of the limbs, in little-endian order. + stackvec vec; + + FASTFLOAT_CONSTEXPR20 bigint() : vec() {} + + bigint(bigint const &) = delete; + bigint &operator=(bigint const &) = delete; + bigint(bigint &&) = delete; + bigint &operator=(bigint &&other) = delete; + + FASTFLOAT_CONSTEXPR20 bigint(uint64_t value) : vec() { +#ifdef FASTFLOAT_64BIT_LIMB + vec.push_unchecked(value); +#else + vec.push_unchecked(uint32_t(value)); + vec.push_unchecked(uint32_t(value >> 32)); +#endif + vec.normalize(); + } + + // get the high 64 bits from the vector, and if bits were truncated. + // this is to get the significant digits for the float. + FASTFLOAT_CONSTEXPR20 uint64_t hi64(bool &truncated) const noexcept { +#ifdef FASTFLOAT_64BIT_LIMB + if (vec.len() == 0) { + return empty_hi64(truncated); + } else if (vec.len() == 1) { + return uint64_hi64(vec.rindex(0), truncated); + } else { + uint64_t result = uint64_hi64(vec.rindex(0), vec.rindex(1), truncated); + truncated |= vec.nonzero(2); + return result; + } +#else + if (vec.len() == 0) { + return empty_hi64(truncated); + } else if (vec.len() == 1) { + return uint32_hi64(vec.rindex(0), truncated); + } else if (vec.len() == 2) { + return uint32_hi64(vec.rindex(0), vec.rindex(1), truncated); + } else { + uint64_t result = + uint32_hi64(vec.rindex(0), vec.rindex(1), vec.rindex(2), truncated); + truncated |= vec.nonzero(3); + return result; + } +#endif + } + + // compare two big integers, returning the large value. + // assumes both are normalized. if the return value is + // negative, other is larger, if the return value is + // positive, this is larger, otherwise they are equal. + // the limbs are stored in little-endian order, so we + // must compare the limbs in ever order. + FASTFLOAT_CONSTEXPR20 int compare(bigint const &other) const noexcept { + if (vec.len() > other.vec.len()) { + return 1; + } else if (vec.len() < other.vec.len()) { + return -1; + } else { + for (size_t index = vec.len(); index > 0; index--) { + limb xi = vec[index - 1]; + limb yi = other.vec[index - 1]; + if (xi > yi) { + return 1; + } else if (xi < yi) { + return -1; + } + } + return 0; + } + } + + // shift left each limb n bits, carrying over to the new limb + // returns true if we were able to shift all the digits. + FASTFLOAT_CONSTEXPR20 bool shl_bits(size_t n) noexcept { + // Internally, for each item, we shift left by n, and add the previous + // right shifted limb-bits. + // For example, we transform (for u8) shifted left 2, to: + // b10100100 b01000010 + // b10 b10010001 b00001000 + FASTFLOAT_DEBUG_ASSERT(n != 0); + FASTFLOAT_DEBUG_ASSERT(n < sizeof(limb) * 8); + + size_t shl = n; + size_t shr = limb_bits - shl; + limb prev = 0; + for (size_t index = 0; index < vec.len(); index++) { + limb xi = vec[index]; + vec[index] = (xi << shl) | (prev >> shr); + prev = xi; + } + + limb carry = prev >> shr; + if (carry != 0) { + return vec.try_push(carry); + } + return true; + } + + // move the limbs left by `n` limbs. + FASTFLOAT_CONSTEXPR20 bool shl_limbs(size_t n) noexcept { + FASTFLOAT_DEBUG_ASSERT(n != 0); + if (n + vec.len() > vec.capacity()) { + return false; + } else if (!vec.is_empty()) { + // move limbs + limb *dst = vec.data + n; + limb const *src = vec.data; + std::copy_backward(src, src + vec.len(), dst + vec.len()); + // fill in empty limbs + limb *first = vec.data; + limb *last = first + n; + ::std::fill(first, last, 0); + vec.set_len(n + vec.len()); + return true; + } else { + return true; + } + } + + // move the limbs left by `n` bits. + FASTFLOAT_CONSTEXPR20 bool shl(size_t n) noexcept { + size_t rem = n % limb_bits; + size_t div = n / limb_bits; + if (rem != 0) { + FASTFLOAT_TRY(shl_bits(rem)); + } + if (div != 0) { + FASTFLOAT_TRY(shl_limbs(div)); + } + return true; + } + + // get the number of leading zeros in the bigint. + FASTFLOAT_CONSTEXPR20 int ctlz() const noexcept { + if (vec.is_empty()) { + return 0; + } else { +#ifdef FASTFLOAT_64BIT_LIMB + return leading_zeroes(vec.rindex(0)); +#else + // no use defining a specialized leading_zeroes for a 32-bit type. + uint64_t r0 = vec.rindex(0); + return leading_zeroes(r0 << 32); +#endif + } + } + + // get the number of bits in the bigint. + FASTFLOAT_CONSTEXPR20 int bit_length() const noexcept { + int lz = ctlz(); + return int(limb_bits * vec.len()) - lz; + } + + FASTFLOAT_CONSTEXPR20 bool mul(limb y) noexcept { return small_mul(vec, y); } + + FASTFLOAT_CONSTEXPR20 bool add(limb y) noexcept { return small_add(vec, y); } + + // multiply as if by 2 raised to a power. + FASTFLOAT_CONSTEXPR20 bool pow2(uint32_t exp) noexcept { return shl(exp); } + + // multiply as if by 5 raised to a power. + FASTFLOAT_CONSTEXPR20 bool pow5(uint32_t exp) noexcept { + // multiply by a power of 5 + size_t large_length = sizeof(large_power_of_5) / sizeof(limb); + limb_span large = limb_span(large_power_of_5, large_length); + while (exp >= large_step) { + FASTFLOAT_TRY(large_mul(vec, large)); + exp -= large_step; + } +#ifdef FASTFLOAT_64BIT_LIMB + uint32_t small_step = 27; + limb max_native = 7450580596923828125UL; +#else + uint32_t small_step = 13; + limb max_native = 1220703125U; +#endif + while (exp >= small_step) { + FASTFLOAT_TRY(small_mul(vec, max_native)); + exp -= small_step; + } + if (exp != 0) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + // This is similar to https://github.com/llvm/llvm-project/issues/47746, + // except the workaround described there don't work here + FASTFLOAT_TRY(small_mul( + vec, limb(((void)small_power_of_5[0], small_power_of_5[exp])))); + } + + return true; + } + + // multiply as if by 10 raised to a power. + FASTFLOAT_CONSTEXPR20 bool pow10(uint32_t exp) noexcept { + FASTFLOAT_TRY(pow5(exp)); + return pow2(exp); + } +}; + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/include/fast_float/constexpr_feature_detect.h b/vnext/external/fast-float/include/fast_float/constexpr_feature_detect.h new file mode 100644 index 00000000000..7624beafcac --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/constexpr_feature_detect.h @@ -0,0 +1,46 @@ +#ifndef FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H +#define FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H + +#ifdef __has_include +#if __has_include() +#include +#endif +#endif + +// Testing for https://wg21.link/N3652, adopted in C++14 +#if __cpp_constexpr >= 201304 +#define FASTFLOAT_CONSTEXPR14 constexpr +#else +#define FASTFLOAT_CONSTEXPR14 +#endif + +#if defined(__cpp_lib_bit_cast) && __cpp_lib_bit_cast >= 201806L +#define FASTFLOAT_HAS_BIT_CAST 1 +#else +#define FASTFLOAT_HAS_BIT_CAST 0 +#endif + +#if defined(__cpp_lib_is_constant_evaluated) && \ + __cpp_lib_is_constant_evaluated >= 201811L +#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 1 +#else +#define FASTFLOAT_HAS_IS_CONSTANT_EVALUATED 0 +#endif + +// Testing for relevant C++20 constexpr library features +#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED && FASTFLOAT_HAS_BIT_CAST && \ + __cpp_lib_constexpr_algorithms >= 201806L /*For std::copy and std::fill*/ +#define FASTFLOAT_CONSTEXPR20 constexpr +#define FASTFLOAT_IS_CONSTEXPR 1 +#else +#define FASTFLOAT_CONSTEXPR20 +#define FASTFLOAT_IS_CONSTEXPR 0 +#endif + +#if __cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 0 +#else +#define FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE 1 +#endif + +#endif // FASTFLOAT_CONSTEXPR_FEATURE_DETECT_H diff --git a/vnext/external/fast-float/include/fast_float/decimal_to_binary.h b/vnext/external/fast-float/include/fast_float/decimal_to_binary.h new file mode 100644 index 00000000000..948768265eb --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/decimal_to_binary.h @@ -0,0 +1,212 @@ +#ifndef FASTFLOAT_DECIMAL_TO_BINARY_H +#define FASTFLOAT_DECIMAL_TO_BINARY_H + +#include "float_common.h" +#include "fast_table.h" +#include +#include +#include +#include +#include +#include + +namespace fast_float { + +// This will compute or rather approximate w * 5**q and return a pair of 64-bit +// words approximating the result, with the "high" part corresponding to the +// most significant bits and the low part corresponding to the least significant +// bits. +// +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 +compute_product_approximation(int64_t q, uint64_t w) { + int const index = 2 * int(q - powers::smallest_power_of_five); + // For small values of q, e.g., q in [0,27], the answer is always exact + // because The line value128 firstproduct = full_multiplication(w, + // power_of_five_128[index]); gives the exact answer. + value128 firstproduct = + full_multiplication(w, powers::power_of_five_128[index]); + static_assert((bit_precision >= 0) && (bit_precision <= 64), + " precision should be in (0,64]"); + constexpr uint64_t precision_mask = + (bit_precision < 64) ? (uint64_t(0xFFFFFFFFFFFFFFFF) >> bit_precision) + : uint64_t(0xFFFFFFFFFFFFFFFF); + if ((firstproduct.high & precision_mask) == + precision_mask) { // could further guard with (lower + w < lower) + // regarding the second product, we only need secondproduct.high, but our + // expectation is that the compiler will optimize this extra work away if + // needed. + value128 secondproduct = + full_multiplication(w, powers::power_of_five_128[index + 1]); + firstproduct.low += secondproduct.high; + if (secondproduct.high > firstproduct.low) { + firstproduct.high++; + } + } + return firstproduct; +} + +namespace detail { +/** + * For q in (0,350), we have that + * f = (((152170 + 65536) * q ) >> 16); + * is equal to + * floor(p) + q + * where + * p = log(5**q)/log(2) = q * log(5)/log(2) + * + * For negative values of q in (-400,0), we have that + * f = (((152170 + 65536) * q ) >> 16); + * is equal to + * -ceil(p) + q + * where + * p = log(5**-q)/log(2) = -q * log(5)/log(2) + */ +constexpr fastfloat_really_inline int32_t power(int32_t q) noexcept { + return (((152170 + 65536) * q) >> 16) + 63; +} +} // namespace detail + +// create an adjusted mantissa, biased by the invalid power2 +// for significant digits already multiplied by 10 ** q. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 adjusted_mantissa +compute_error_scaled(int64_t q, uint64_t w, int lz) noexcept { + int hilz = int(w >> 63) ^ 1; + adjusted_mantissa answer; + answer.mantissa = w << hilz; + int bias = binary::mantissa_explicit_bits() - binary::minimum_exponent(); + answer.power2 = int32_t(detail::power(int32_t(q)) + bias - hilz - lz - 62 + + invalid_am_bias); + return answer; +} + +// w * 10 ** q, without rounding the representation up. +// the power2 in the exponent will be adjusted by invalid_am_bias. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +compute_error(int64_t q, uint64_t w) noexcept { + int lz = leading_zeroes(w); + w <<= lz; + value128 product = + compute_product_approximation(q, w); + return compute_error_scaled(q, product.high, lz); +} + +// Computers w * 10 ** q. +// The returned value should be a valid number that simply needs to be +// packed. However, in some very rare cases, the computation will fail. In such +// cases, we return an adjusted_mantissa with a negative power of 2: the caller +// should recompute in such cases. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +compute_float(int64_t q, uint64_t w) noexcept { + adjusted_mantissa answer; + if ((w == 0) || (q < binary::smallest_power_of_ten())) { + answer.power2 = 0; + answer.mantissa = 0; + // result should be zero + return answer; + } + if (q > binary::largest_power_of_ten()) { + // we want to get infinity: + answer.power2 = binary::infinite_power(); + answer.mantissa = 0; + return answer; + } + // At this point in time q is in [powers::smallest_power_of_five, + // powers::largest_power_of_five]. + + // We want the most significant bit of i to be 1. Shift if needed. + int lz = leading_zeroes(w); + w <<= lz; + + // The required precision is binary::mantissa_explicit_bits() + 3 because + // 1. We need the implicit bit + // 2. We need an extra bit for rounding purposes + // 3. We might lose a bit due to the "upperbit" routine (result too small, + // requiring a shift) + + value128 product = + compute_product_approximation(q, w); + // The computed 'product' is always sufficient. + // Mathematical proof: + // Noble Mushtak and Daniel Lemire, Fast Number Parsing Without Fallback (to + // appear) See script/mushtak_lemire.py + + // The "compute_product_approximation" function can be slightly slower than a + // branchless approach: value128 product = compute_product(q, w); but in + // practice, we can win big with the compute_product_approximation if its + // additional branch is easily predicted. Which is best is data specific. + int upperbit = int(product.high >> 63); + int shift = upperbit + 64 - binary::mantissa_explicit_bits() - 3; + + answer.mantissa = product.high >> shift; + + answer.power2 = int32_t(detail::power(int32_t(q)) + upperbit - lz - + binary::minimum_exponent()); + if (answer.power2 <= 0) { // we have a subnormal? + // Here have that answer.power2 <= 0 so -answer.power2 >= 0 + if (-answer.power2 + 1 >= + 64) { // if we have more than 64 bits below the minimum exponent, you + // have a zero for sure. + answer.power2 = 0; + answer.mantissa = 0; + // result should be zero + return answer; + } + // next line is safe because -answer.power2 + 1 < 64 + answer.mantissa >>= -answer.power2 + 1; + // Thankfully, we can't have both "round-to-even" and subnormals because + // "round-to-even" only occurs for powers close to 0 in the 32-bit and + // and 64-bit case (with no more than 19 digits). + answer.mantissa += (answer.mantissa & 1); // round up + answer.mantissa >>= 1; + // There is a weird scenario where we don't have a subnormal but just. + // Suppose we start with 2.2250738585072013e-308, we end up + // with 0x3fffffffffffff x 2^-1023-53 which is technically subnormal + // whereas 0x40000000000000 x 2^-1023-53 is normal. Now, we need to round + // up 0x3fffffffffffff x 2^-1023-53 and once we do, we are no longer + // subnormal, but we can only know this after rounding. + // So we only declare a subnormal if we are smaller than the threshold. + answer.power2 = + (answer.mantissa < (uint64_t(1) << binary::mantissa_explicit_bits())) + ? 0 + : 1; + return answer; + } + + // usually, we round *up*, but if we fall right in between and and we have an + // even basis, we need to round down + // We are only concerned with the cases where 5**q fits in single 64-bit word. + if ((product.low <= 1) && (q >= binary::min_exponent_round_to_even()) && + (q <= binary::max_exponent_round_to_even()) && + ((answer.mantissa & 3) == 1)) { // we may fall between two floats! + // To be in-between two floats we need that in doing + // answer.mantissa = product.high >> (upperbit + 64 - + // binary::mantissa_explicit_bits() - 3); + // ... we dropped out only zeroes. But if this happened, then we can go + // back!!! + if ((answer.mantissa << shift) == product.high) { + answer.mantissa &= ~uint64_t(1); // flip it so that we do not round up + } + } + + answer.mantissa += (answer.mantissa & 1); // round up + answer.mantissa >>= 1; + if (answer.mantissa >= (uint64_t(2) << binary::mantissa_explicit_bits())) { + answer.mantissa = (uint64_t(1) << binary::mantissa_explicit_bits()); + answer.power2++; // undo previous addition + } + + answer.mantissa &= ~(uint64_t(1) << binary::mantissa_explicit_bits()); + if (answer.power2 >= binary::infinite_power()) { // infinity + answer.power2 = binary::infinite_power(); + answer.mantissa = 0; + } + return answer; +} + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/include/fast_float/digit_comparison.h b/vnext/external/fast-float/include/fast_float/digit_comparison.h new file mode 100644 index 00000000000..d7ef3d9acc1 --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/digit_comparison.h @@ -0,0 +1,457 @@ +#ifndef FASTFLOAT_DIGIT_COMPARISON_H +#define FASTFLOAT_DIGIT_COMPARISON_H + +#include +#include +#include +#include + +#include "float_common.h" +#include "bigint.h" +#include "ascii_number.h" + +namespace fast_float { + +// 1e0 to 1e19 +constexpr static uint64_t powers_of_ten_uint64[] = {1UL, + 10UL, + 100UL, + 1000UL, + 10000UL, + 100000UL, + 1000000UL, + 10000000UL, + 100000000UL, + 1000000000UL, + 10000000000UL, + 100000000000UL, + 1000000000000UL, + 10000000000000UL, + 100000000000000UL, + 1000000000000000UL, + 10000000000000000UL, + 100000000000000000UL, + 1000000000000000000UL, + 10000000000000000000UL}; + +// calculate the exponent, in scientific notation, of the number. +// this algorithm is not even close to optimized, but it has no practical +// effect on performance: in order to have a faster algorithm, we'd need +// to slow down performance for faster algorithms, and this is still fast. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int32_t +scientific_exponent(parsed_number_string_t &num) noexcept { + uint64_t mantissa = num.mantissa; + int32_t exponent = int32_t(num.exponent); + while (mantissa >= 10000) { + mantissa /= 10000; + exponent += 4; + } + while (mantissa >= 100) { + mantissa /= 100; + exponent += 2; + } + while (mantissa >= 10) { + mantissa /= 10; + exponent += 1; + } + return exponent; +} + +// this converts a native floating-point number to an extended-precision float. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +to_extended(T value) noexcept { + using equiv_uint = equiv_uint_t; + constexpr equiv_uint exponent_mask = binary_format::exponent_mask(); + constexpr equiv_uint mantissa_mask = binary_format::mantissa_mask(); + constexpr equiv_uint hidden_bit_mask = binary_format::hidden_bit_mask(); + + adjusted_mantissa am; + int32_t bias = binary_format::mantissa_explicit_bits() - + binary_format::minimum_exponent(); + equiv_uint bits; +#if FASTFLOAT_HAS_BIT_CAST + bits = std::bit_cast(value); +#else + ::memcpy(&bits, &value, sizeof(T)); +#endif + if ((bits & exponent_mask) == 0) { + // denormal + am.power2 = 1 - bias; + am.mantissa = bits & mantissa_mask; + } else { + // normal + am.power2 = int32_t((bits & exponent_mask) >> + binary_format::mantissa_explicit_bits()); + am.power2 -= bias; + am.mantissa = (bits & mantissa_mask) | hidden_bit_mask; + } + + return am; +} + +// get the extended precision value of the halfway point between b and b+u. +// we are given a native float that represents b, so we need to adjust it +// halfway between b and b+u. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +to_extended_halfway(T value) noexcept { + adjusted_mantissa am = to_extended(value); + am.mantissa <<= 1; + am.mantissa += 1; + am.power2 -= 1; + return am; +} + +// round an extended-precision float to the nearest machine float. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void round(adjusted_mantissa &am, + callback cb) noexcept { + int32_t mantissa_shift = 64 - binary_format::mantissa_explicit_bits() - 1; + if (-am.power2 >= mantissa_shift) { + // have a denormal float + int32_t shift = -am.power2 + 1; + cb(am, std::min(shift, 64)); + // check for round-up: if rounding-nearest carried us to the hidden bit. + am.power2 = (am.mantissa < + (uint64_t(1) << binary_format::mantissa_explicit_bits())) + ? 0 + : 1; + return; + } + + // have a normal float, use the default shift. + cb(am, mantissa_shift); + + // check for carry + if (am.mantissa >= + (uint64_t(2) << binary_format::mantissa_explicit_bits())) { + am.mantissa = (uint64_t(1) << binary_format::mantissa_explicit_bits()); + am.power2++; + } + + // check for infinite: we could have carried to an infinite power + am.mantissa &= ~(uint64_t(1) << binary_format::mantissa_explicit_bits()); + if (am.power2 >= binary_format::infinite_power()) { + am.power2 = binary_format::infinite_power(); + am.mantissa = 0; + } +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void +round_nearest_tie_even(adjusted_mantissa &am, int32_t shift, + callback cb) noexcept { + uint64_t const mask = (shift == 64) ? UINT64_MAX : (uint64_t(1) << shift) - 1; + uint64_t const halfway = (shift == 0) ? 0 : uint64_t(1) << (shift - 1); + uint64_t truncated_bits = am.mantissa & mask; + bool is_above = truncated_bits > halfway; + bool is_halfway = truncated_bits == halfway; + + // shift digits into position + if (shift == 64) { + am.mantissa = 0; + } else { + am.mantissa >>= shift; + } + am.power2 += shift; + + bool is_odd = (am.mantissa & 1) == 1; + am.mantissa += uint64_t(cb(is_odd, is_halfway, is_above)); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void +round_down(adjusted_mantissa &am, int32_t shift) noexcept { + if (shift == 64) { + am.mantissa = 0; + } else { + am.mantissa >>= shift; + } + am.power2 += shift; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +skip_zeros(UC const *&first, UC const *last) noexcept { + uint64_t val; + while (!cpp20_and_in_constexpr() && + std::distance(first, last) >= int_cmp_len()) { + ::memcpy(&val, first, sizeof(uint64_t)); + if (val != int_cmp_zeros()) { + break; + } + first += int_cmp_len(); + } + while (first != last) { + if (*first != UC('0')) { + break; + } + first++; + } +} + +// determine if any non-zero digits were truncated. +// all characters must be valid digits. +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +is_truncated(UC const *first, UC const *last) noexcept { + // do 8-bit optimizations, can just compare to 8 literal 0s. + uint64_t val; + while (!cpp20_and_in_constexpr() && + std::distance(first, last) >= int_cmp_len()) { + ::memcpy(&val, first, sizeof(uint64_t)); + if (val != int_cmp_zeros()) { + return true; + } + first += int_cmp_len(); + } + while (first != last) { + if (*first != UC('0')) { + return true; + } + ++first; + } + return false; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 bool +is_truncated(span s) noexcept { + return is_truncated(s.ptr, s.ptr + s.len()); +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +parse_eight_digits(UC const *&p, limb &value, size_t &counter, + size_t &count) noexcept { + value = value * 100000000 + parse_eight_digits_unrolled(p); + p += 8; + counter += 8; + count += 8; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 void +parse_one_digit(UC const *&p, limb &value, size_t &counter, + size_t &count) noexcept { + value = value * 10 + limb(*p - UC('0')); + p++; + counter++; + count++; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +add_native(bigint &big, limb power, limb value) noexcept { + big.mul(power); + big.add(value); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +round_up_bigint(bigint &big, size_t &count) noexcept { + // need to round-up the digits, but need to avoid rounding + // ....9999 to ...10000, which could cause a false halfway point. + add_native(big, 10, 1); + count++; +} + +// parse the significant digits into a big integer +template +inline FASTFLOAT_CONSTEXPR20 void +parse_mantissa(bigint &result, parsed_number_string_t &num, + size_t max_digits, size_t &digits) noexcept { + // try to minimize the number of big integer and scalar multiplication. + // therefore, try to parse 8 digits at a time, and multiply by the largest + // scalar value (9 or 19 digits) for each step. + size_t counter = 0; + digits = 0; + limb value = 0; +#ifdef FASTFLOAT_64BIT_LIMB + size_t step = 19; +#else + size_t step = 9; +#endif + + // process all integer digits. + UC const *p = num.integer.ptr; + UC const *pend = p + num.integer.len(); + skip_zeros(p, pend); + // process all digits, in increments of step per loop + while (p != pend) { + while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && + (max_digits - digits >= 8)) { + parse_eight_digits(p, value, counter, digits); + } + while (counter < step && p != pend && digits < max_digits) { + parse_one_digit(p, value, counter, digits); + } + if (digits == max_digits) { + // add the temporary value, then check if we've truncated any digits + add_native(result, limb(powers_of_ten_uint64[counter]), value); + bool truncated = is_truncated(p, pend); + if (num.fraction.ptr != nullptr) { + truncated |= is_truncated(num.fraction); + } + if (truncated) { + round_up_bigint(result, digits); + } + return; + } else { + add_native(result, limb(powers_of_ten_uint64[counter]), value); + counter = 0; + value = 0; + } + } + + // add our fraction digits, if they're available. + if (num.fraction.ptr != nullptr) { + p = num.fraction.ptr; + pend = p + num.fraction.len(); + if (digits == 0) { + skip_zeros(p, pend); + } + // process all digits, in increments of step per loop + while (p != pend) { + while ((std::distance(p, pend) >= 8) && (step - counter >= 8) && + (max_digits - digits >= 8)) { + parse_eight_digits(p, value, counter, digits); + } + while (counter < step && p != pend && digits < max_digits) { + parse_one_digit(p, value, counter, digits); + } + if (digits == max_digits) { + // add the temporary value, then check if we've truncated any digits + add_native(result, limb(powers_of_ten_uint64[counter]), value); + bool truncated = is_truncated(p, pend); + if (truncated) { + round_up_bigint(result, digits); + } + return; + } else { + add_native(result, limb(powers_of_ten_uint64[counter]), value); + counter = 0; + value = 0; + } + } + } + + if (counter != 0) { + add_native(result, limb(powers_of_ten_uint64[counter]), value); + } +} + +template +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +positive_digit_comp(bigint &bigmant, int32_t exponent) noexcept { + FASTFLOAT_ASSERT(bigmant.pow10(uint32_t(exponent))); + adjusted_mantissa answer; + bool truncated; + answer.mantissa = bigmant.hi64(truncated); + int bias = binary_format::mantissa_explicit_bits() - + binary_format::minimum_exponent(); + answer.power2 = bigmant.bit_length() - 64 + bias; + + round(answer, [truncated](adjusted_mantissa &a, int32_t shift) { + round_nearest_tie_even( + a, shift, + [truncated](bool is_odd, bool is_halfway, bool is_above) -> bool { + return is_above || (is_halfway && truncated) || + (is_odd && is_halfway); + }); + }); + + return answer; +} + +// the scaling here is quite simple: we have, for the real digits `m * 10^e`, +// and for the theoretical digits `n * 2^f`. Since `e` is always negative, +// to scale them identically, we do `n * 2^f * 5^-f`, so we now have `m * 2^e`. +// we then need to scale by `2^(f- e)`, and then the two significant digits +// are of the same magnitude. +template +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa negative_digit_comp( + bigint &bigmant, adjusted_mantissa am, int32_t exponent) noexcept { + bigint &real_digits = bigmant; + int32_t real_exp = exponent; + + // get the value of `b`, rounded down, and get a bigint representation of b+h + adjusted_mantissa am_b = am; + // gcc7 buf: use a lambda to remove the noexcept qualifier bug with + // -Wnoexcept-type. + round(am_b, + [](adjusted_mantissa &a, int32_t shift) { round_down(a, shift); }); + T b; + to_float(false, am_b, b); + adjusted_mantissa theor = to_extended_halfway(b); + bigint theor_digits(theor.mantissa); + int32_t theor_exp = theor.power2; + + // scale real digits and theor digits to be same power. + int32_t pow2_exp = theor_exp - real_exp; + uint32_t pow5_exp = uint32_t(-real_exp); + if (pow5_exp != 0) { + FASTFLOAT_ASSERT(theor_digits.pow5(pow5_exp)); + } + if (pow2_exp > 0) { + FASTFLOAT_ASSERT(theor_digits.pow2(uint32_t(pow2_exp))); + } else if (pow2_exp < 0) { + FASTFLOAT_ASSERT(real_digits.pow2(uint32_t(-pow2_exp))); + } + + // compare digits, and use it to director rounding + int ord = real_digits.compare(theor_digits); + adjusted_mantissa answer = am; + round(answer, [ord](adjusted_mantissa &a, int32_t shift) { + round_nearest_tie_even( + a, shift, [ord](bool is_odd, bool _, bool __) -> bool { + (void)_; // not needed, since we've done our comparison + (void)__; // not needed, since we've done our comparison + if (ord > 0) { + return true; + } else if (ord < 0) { + return false; + } else { + return is_odd; + } + }); + }); + + return answer; +} + +// parse the significant digits as a big integer to unambiguously round the +// the significant digits. here, we are trying to determine how to round +// an extended float representation close to `b+h`, halfway between `b` +// (the float rounded-down) and `b+u`, the next positive float. this +// algorithm is always correct, and uses one of two approaches. when +// the exponent is positive relative to the significant digits (such as +// 1234), we create a big-integer representation, get the high 64-bits, +// determine if any lower bits are truncated, and use that to direct +// rounding. in case of a negative exponent relative to the significant +// digits (such as 1.2345), we create a theoretical representation of +// `b` as a big-integer type, scaled to the same binary exponent as +// the actual digits. we then compare the big integer representations +// of both, and use that to direct rounding. +template +inline FASTFLOAT_CONSTEXPR20 adjusted_mantissa +digit_comp(parsed_number_string_t &num, adjusted_mantissa am) noexcept { + // remove the invalid exponent bias + am.power2 -= invalid_am_bias; + + int32_t sci_exp = scientific_exponent(num); + size_t max_digits = binary_format::max_digits(); + size_t digits = 0; + bigint bigmant; + parse_mantissa(bigmant, num, max_digits, digits); + // can't underflow, since digits is at most max_digits. + int32_t exponent = sci_exp + 1 - int32_t(digits); + if (exponent >= 0) { + return positive_digit_comp(bigmant, exponent); + } else { + return negative_digit_comp(bigmant, am, exponent); + } +} + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/include/fast_float/fast_float.h b/vnext/external/fast-float/include/fast_float/fast_float.h new file mode 100644 index 00000000000..af65c96bde3 --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/fast_float.h @@ -0,0 +1,59 @@ + +#ifndef FASTFLOAT_FAST_FLOAT_H +#define FASTFLOAT_FAST_FLOAT_H + +#include "float_common.h" + +namespace fast_float { +/** + * This function parses the character sequence [first,last) for a number. It + * parses floating-point numbers expecting a locale-indepent format equivalent + * to what is used by std::strtod in the default ("C") locale. The resulting + * floating-point value is the closest floating-point values (using either float + * or double), using the "round to even" convention for values that would + * otherwise fall right in-between two values. That is, we provide exact parsing + * according to the IEEE standard. + * + * Given a successful parse, the pointer (`ptr`) in the returned value is set to + * point right after the parsed number, and the `value` referenced is set to the + * parsed value. In case of error, the returned `ec` contains a representative + * error, otherwise the default (`std::errc()`) value is stored. + * + * The implementation does not throw and does not allocate memory (e.g., with + * `new` or `malloc`). + * + * Like the C++17 standard, the `fast_float::from_chars` functions take an + * optional last argument of the type `fast_float::chars_format`. It is a bitset + * value: we check whether `fmt & fast_float::chars_format::fixed` and `fmt & + * fast_float::chars_format::scientific` are set to determine whether we allow + * the fixed point and scientific notation respectively. The default is + * `fast_float::chars_format::general` which allows both `fixed` and + * `scientific`. + */ +template ::value)> +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, + chars_format fmt = chars_format::general) noexcept; + +/** + * Like from_chars, but accepts an `options` argument to govern number parsing. + * Both for floating-point types and integer types. + */ +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept; + +/** + * from_chars for integer types. + */ +template ::value)> +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, int base = 10) noexcept; + +} // namespace fast_float + +#include "parse_number.h" +#endif // FASTFLOAT_FAST_FLOAT_H diff --git a/vnext/external/fast-float/include/fast_float/fast_table.h b/vnext/external/fast-float/include/fast_float/fast_table.h new file mode 100644 index 00000000000..69f9b2c9245 --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/fast_table.h @@ -0,0 +1,708 @@ +#ifndef FASTFLOAT_FAST_TABLE_H +#define FASTFLOAT_FAST_TABLE_H + +#include + +namespace fast_float { + +/** + * When mapping numbers from decimal to binary, + * we go from w * 10^q to m * 2^p but we have + * 10^q = 5^q * 2^q, so effectively + * we are trying to match + * w * 2^q * 5^q to m * 2^p. Thus the powers of two + * are not a concern since they can be represented + * exactly using the binary notation, only the powers of five + * affect the binary significand. + */ + +/** + * The smallest non-zero float (binary64) is 2^-1074. + * We take as input numbers of the form w x 10^q where w < 2^64. + * We have that w * 10^-343 < 2^(64-344) 5^-343 < 2^-1076. + * However, we have that + * (2^64-1) * 10^-342 = (2^64-1) * 2^-342 * 5^-342 > 2^-1074. + * Thus it is possible for a number of the form w * 10^-342 where + * w is a 64-bit value to be a non-zero floating-point number. + ********* + * Any number of form w * 10^309 where w>= 1 is going to be + * infinite in binary64 so we never need to worry about powers + * of 5 greater than 308. + */ +template struct powers_template { + + constexpr static int smallest_power_of_five = + binary_format::smallest_power_of_ten(); + constexpr static int largest_power_of_five = + binary_format::largest_power_of_ten(); + constexpr static int number_of_entries = + 2 * (largest_power_of_five - smallest_power_of_five + 1); + // Powers of five from 5^-342 all the way to 5^308 rounded toward one. + constexpr static uint64_t power_of_five_128[number_of_entries] = { + 0xeef453d6923bd65a, 0x113faa2906a13b3f, + 0x9558b4661b6565f8, 0x4ac7ca59a424c507, + 0xbaaee17fa23ebf76, 0x5d79bcf00d2df649, + 0xe95a99df8ace6f53, 0xf4d82c2c107973dc, + 0x91d8a02bb6c10594, 0x79071b9b8a4be869, + 0xb64ec836a47146f9, 0x9748e2826cdee284, + 0xe3e27a444d8d98b7, 0xfd1b1b2308169b25, + 0x8e6d8c6ab0787f72, 0xfe30f0f5e50e20f7, + 0xb208ef855c969f4f, 0xbdbd2d335e51a935, + 0xde8b2b66b3bc4723, 0xad2c788035e61382, + 0x8b16fb203055ac76, 0x4c3bcb5021afcc31, + 0xaddcb9e83c6b1793, 0xdf4abe242a1bbf3d, + 0xd953e8624b85dd78, 0xd71d6dad34a2af0d, + 0x87d4713d6f33aa6b, 0x8672648c40e5ad68, + 0xa9c98d8ccb009506, 0x680efdaf511f18c2, + 0xd43bf0effdc0ba48, 0x212bd1b2566def2, + 0x84a57695fe98746d, 0x14bb630f7604b57, + 0xa5ced43b7e3e9188, 0x419ea3bd35385e2d, + 0xcf42894a5dce35ea, 0x52064cac828675b9, + 0x818995ce7aa0e1b2, 0x7343efebd1940993, + 0xa1ebfb4219491a1f, 0x1014ebe6c5f90bf8, + 0xca66fa129f9b60a6, 0xd41a26e077774ef6, + 0xfd00b897478238d0, 0x8920b098955522b4, + 0x9e20735e8cb16382, 0x55b46e5f5d5535b0, + 0xc5a890362fddbc62, 0xeb2189f734aa831d, + 0xf712b443bbd52b7b, 0xa5e9ec7501d523e4, + 0x9a6bb0aa55653b2d, 0x47b233c92125366e, + 0xc1069cd4eabe89f8, 0x999ec0bb696e840a, + 0xf148440a256e2c76, 0xc00670ea43ca250d, + 0x96cd2a865764dbca, 0x380406926a5e5728, + 0xbc807527ed3e12bc, 0xc605083704f5ecf2, + 0xeba09271e88d976b, 0xf7864a44c633682e, + 0x93445b8731587ea3, 0x7ab3ee6afbe0211d, + 0xb8157268fdae9e4c, 0x5960ea05bad82964, + 0xe61acf033d1a45df, 0x6fb92487298e33bd, + 0x8fd0c16206306bab, 0xa5d3b6d479f8e056, + 0xb3c4f1ba87bc8696, 0x8f48a4899877186c, + 0xe0b62e2929aba83c, 0x331acdabfe94de87, + 0x8c71dcd9ba0b4925, 0x9ff0c08b7f1d0b14, + 0xaf8e5410288e1b6f, 0x7ecf0ae5ee44dd9, + 0xdb71e91432b1a24a, 0xc9e82cd9f69d6150, + 0x892731ac9faf056e, 0xbe311c083a225cd2, + 0xab70fe17c79ac6ca, 0x6dbd630a48aaf406, + 0xd64d3d9db981787d, 0x92cbbccdad5b108, + 0x85f0468293f0eb4e, 0x25bbf56008c58ea5, + 0xa76c582338ed2621, 0xaf2af2b80af6f24e, + 0xd1476e2c07286faa, 0x1af5af660db4aee1, + 0x82cca4db847945ca, 0x50d98d9fc890ed4d, + 0xa37fce126597973c, 0xe50ff107bab528a0, + 0xcc5fc196fefd7d0c, 0x1e53ed49a96272c8, + 0xff77b1fcbebcdc4f, 0x25e8e89c13bb0f7a, + 0x9faacf3df73609b1, 0x77b191618c54e9ac, + 0xc795830d75038c1d, 0xd59df5b9ef6a2417, + 0xf97ae3d0d2446f25, 0x4b0573286b44ad1d, + 0x9becce62836ac577, 0x4ee367f9430aec32, + 0xc2e801fb244576d5, 0x229c41f793cda73f, + 0xf3a20279ed56d48a, 0x6b43527578c1110f, + 0x9845418c345644d6, 0x830a13896b78aaa9, + 0xbe5691ef416bd60c, 0x23cc986bc656d553, + 0xedec366b11c6cb8f, 0x2cbfbe86b7ec8aa8, + 0x94b3a202eb1c3f39, 0x7bf7d71432f3d6a9, + 0xb9e08a83a5e34f07, 0xdaf5ccd93fb0cc53, + 0xe858ad248f5c22c9, 0xd1b3400f8f9cff68, + 0x91376c36d99995be, 0x23100809b9c21fa1, + 0xb58547448ffffb2d, 0xabd40a0c2832a78a, + 0xe2e69915b3fff9f9, 0x16c90c8f323f516c, + 0x8dd01fad907ffc3b, 0xae3da7d97f6792e3, + 0xb1442798f49ffb4a, 0x99cd11cfdf41779c, + 0xdd95317f31c7fa1d, 0x40405643d711d583, + 0x8a7d3eef7f1cfc52, 0x482835ea666b2572, + 0xad1c8eab5ee43b66, 0xda3243650005eecf, + 0xd863b256369d4a40, 0x90bed43e40076a82, + 0x873e4f75e2224e68, 0x5a7744a6e804a291, + 0xa90de3535aaae202, 0x711515d0a205cb36, + 0xd3515c2831559a83, 0xd5a5b44ca873e03, + 0x8412d9991ed58091, 0xe858790afe9486c2, + 0xa5178fff668ae0b6, 0x626e974dbe39a872, + 0xce5d73ff402d98e3, 0xfb0a3d212dc8128f, + 0x80fa687f881c7f8e, 0x7ce66634bc9d0b99, + 0xa139029f6a239f72, 0x1c1fffc1ebc44e80, + 0xc987434744ac874e, 0xa327ffb266b56220, + 0xfbe9141915d7a922, 0x4bf1ff9f0062baa8, + 0x9d71ac8fada6c9b5, 0x6f773fc3603db4a9, + 0xc4ce17b399107c22, 0xcb550fb4384d21d3, + 0xf6019da07f549b2b, 0x7e2a53a146606a48, + 0x99c102844f94e0fb, 0x2eda7444cbfc426d, + 0xc0314325637a1939, 0xfa911155fefb5308, + 0xf03d93eebc589f88, 0x793555ab7eba27ca, + 0x96267c7535b763b5, 0x4bc1558b2f3458de, + 0xbbb01b9283253ca2, 0x9eb1aaedfb016f16, + 0xea9c227723ee8bcb, 0x465e15a979c1cadc, + 0x92a1958a7675175f, 0xbfacd89ec191ec9, + 0xb749faed14125d36, 0xcef980ec671f667b, + 0xe51c79a85916f484, 0x82b7e12780e7401a, + 0x8f31cc0937ae58d2, 0xd1b2ecb8b0908810, + 0xb2fe3f0b8599ef07, 0x861fa7e6dcb4aa15, + 0xdfbdcece67006ac9, 0x67a791e093e1d49a, + 0x8bd6a141006042bd, 0xe0c8bb2c5c6d24e0, + 0xaecc49914078536d, 0x58fae9f773886e18, + 0xda7f5bf590966848, 0xaf39a475506a899e, + 0x888f99797a5e012d, 0x6d8406c952429603, + 0xaab37fd7d8f58178, 0xc8e5087ba6d33b83, + 0xd5605fcdcf32e1d6, 0xfb1e4a9a90880a64, + 0x855c3be0a17fcd26, 0x5cf2eea09a55067f, + 0xa6b34ad8c9dfc06f, 0xf42faa48c0ea481e, + 0xd0601d8efc57b08b, 0xf13b94daf124da26, + 0x823c12795db6ce57, 0x76c53d08d6b70858, + 0xa2cb1717b52481ed, 0x54768c4b0c64ca6e, + 0xcb7ddcdda26da268, 0xa9942f5dcf7dfd09, + 0xfe5d54150b090b02, 0xd3f93b35435d7c4c, + 0x9efa548d26e5a6e1, 0xc47bc5014a1a6daf, + 0xc6b8e9b0709f109a, 0x359ab6419ca1091b, + 0xf867241c8cc6d4c0, 0xc30163d203c94b62, + 0x9b407691d7fc44f8, 0x79e0de63425dcf1d, + 0xc21094364dfb5636, 0x985915fc12f542e4, + 0xf294b943e17a2bc4, 0x3e6f5b7b17b2939d, + 0x979cf3ca6cec5b5a, 0xa705992ceecf9c42, + 0xbd8430bd08277231, 0x50c6ff782a838353, + 0xece53cec4a314ebd, 0xa4f8bf5635246428, + 0x940f4613ae5ed136, 0x871b7795e136be99, + 0xb913179899f68584, 0x28e2557b59846e3f, + 0xe757dd7ec07426e5, 0x331aeada2fe589cf, + 0x9096ea6f3848984f, 0x3ff0d2c85def7621, + 0xb4bca50b065abe63, 0xfed077a756b53a9, + 0xe1ebce4dc7f16dfb, 0xd3e8495912c62894, + 0x8d3360f09cf6e4bd, 0x64712dd7abbbd95c, + 0xb080392cc4349dec, 0xbd8d794d96aacfb3, + 0xdca04777f541c567, 0xecf0d7a0fc5583a0, + 0x89e42caaf9491b60, 0xf41686c49db57244, + 0xac5d37d5b79b6239, 0x311c2875c522ced5, + 0xd77485cb25823ac7, 0x7d633293366b828b, + 0x86a8d39ef77164bc, 0xae5dff9c02033197, + 0xa8530886b54dbdeb, 0xd9f57f830283fdfc, + 0xd267caa862a12d66, 0xd072df63c324fd7b, + 0x8380dea93da4bc60, 0x4247cb9e59f71e6d, + 0xa46116538d0deb78, 0x52d9be85f074e608, + 0xcd795be870516656, 0x67902e276c921f8b, + 0x806bd9714632dff6, 0xba1cd8a3db53b6, + 0xa086cfcd97bf97f3, 0x80e8a40eccd228a4, + 0xc8a883c0fdaf7df0, 0x6122cd128006b2cd, + 0xfad2a4b13d1b5d6c, 0x796b805720085f81, + 0x9cc3a6eec6311a63, 0xcbe3303674053bb0, + 0xc3f490aa77bd60fc, 0xbedbfc4411068a9c, + 0xf4f1b4d515acb93b, 0xee92fb5515482d44, + 0x991711052d8bf3c5, 0x751bdd152d4d1c4a, + 0xbf5cd54678eef0b6, 0xd262d45a78a0635d, + 0xef340a98172aace4, 0x86fb897116c87c34, + 0x9580869f0e7aac0e, 0xd45d35e6ae3d4da0, + 0xbae0a846d2195712, 0x8974836059cca109, + 0xe998d258869facd7, 0x2bd1a438703fc94b, + 0x91ff83775423cc06, 0x7b6306a34627ddcf, + 0xb67f6455292cbf08, 0x1a3bc84c17b1d542, + 0xe41f3d6a7377eeca, 0x20caba5f1d9e4a93, + 0x8e938662882af53e, 0x547eb47b7282ee9c, + 0xb23867fb2a35b28d, 0xe99e619a4f23aa43, + 0xdec681f9f4c31f31, 0x6405fa00e2ec94d4, + 0x8b3c113c38f9f37e, 0xde83bc408dd3dd04, + 0xae0b158b4738705e, 0x9624ab50b148d445, + 0xd98ddaee19068c76, 0x3badd624dd9b0957, + 0x87f8a8d4cfa417c9, 0xe54ca5d70a80e5d6, + 0xa9f6d30a038d1dbc, 0x5e9fcf4ccd211f4c, + 0xd47487cc8470652b, 0x7647c3200069671f, + 0x84c8d4dfd2c63f3b, 0x29ecd9f40041e073, + 0xa5fb0a17c777cf09, 0xf468107100525890, + 0xcf79cc9db955c2cc, 0x7182148d4066eeb4, + 0x81ac1fe293d599bf, 0xc6f14cd848405530, + 0xa21727db38cb002f, 0xb8ada00e5a506a7c, + 0xca9cf1d206fdc03b, 0xa6d90811f0e4851c, + 0xfd442e4688bd304a, 0x908f4a166d1da663, + 0x9e4a9cec15763e2e, 0x9a598e4e043287fe, + 0xc5dd44271ad3cdba, 0x40eff1e1853f29fd, + 0xf7549530e188c128, 0xd12bee59e68ef47c, + 0x9a94dd3e8cf578b9, 0x82bb74f8301958ce, + 0xc13a148e3032d6e7, 0xe36a52363c1faf01, + 0xf18899b1bc3f8ca1, 0xdc44e6c3cb279ac1, + 0x96f5600f15a7b7e5, 0x29ab103a5ef8c0b9, + 0xbcb2b812db11a5de, 0x7415d448f6b6f0e7, + 0xebdf661791d60f56, 0x111b495b3464ad21, + 0x936b9fcebb25c995, 0xcab10dd900beec34, + 0xb84687c269ef3bfb, 0x3d5d514f40eea742, + 0xe65829b3046b0afa, 0xcb4a5a3112a5112, + 0x8ff71a0fe2c2e6dc, 0x47f0e785eaba72ab, + 0xb3f4e093db73a093, 0x59ed216765690f56, + 0xe0f218b8d25088b8, 0x306869c13ec3532c, + 0x8c974f7383725573, 0x1e414218c73a13fb, + 0xafbd2350644eeacf, 0xe5d1929ef90898fa, + 0xdbac6c247d62a583, 0xdf45f746b74abf39, + 0x894bc396ce5da772, 0x6b8bba8c328eb783, + 0xab9eb47c81f5114f, 0x66ea92f3f326564, + 0xd686619ba27255a2, 0xc80a537b0efefebd, + 0x8613fd0145877585, 0xbd06742ce95f5f36, + 0xa798fc4196e952e7, 0x2c48113823b73704, + 0xd17f3b51fca3a7a0, 0xf75a15862ca504c5, + 0x82ef85133de648c4, 0x9a984d73dbe722fb, + 0xa3ab66580d5fdaf5, 0xc13e60d0d2e0ebba, + 0xcc963fee10b7d1b3, 0x318df905079926a8, + 0xffbbcfe994e5c61f, 0xfdf17746497f7052, + 0x9fd561f1fd0f9bd3, 0xfeb6ea8bedefa633, + 0xc7caba6e7c5382c8, 0xfe64a52ee96b8fc0, + 0xf9bd690a1b68637b, 0x3dfdce7aa3c673b0, + 0x9c1661a651213e2d, 0x6bea10ca65c084e, + 0xc31bfa0fe5698db8, 0x486e494fcff30a62, + 0xf3e2f893dec3f126, 0x5a89dba3c3efccfa, + 0x986ddb5c6b3a76b7, 0xf89629465a75e01c, + 0xbe89523386091465, 0xf6bbb397f1135823, + 0xee2ba6c0678b597f, 0x746aa07ded582e2c, + 0x94db483840b717ef, 0xa8c2a44eb4571cdc, + 0xba121a4650e4ddeb, 0x92f34d62616ce413, + 0xe896a0d7e51e1566, 0x77b020baf9c81d17, + 0x915e2486ef32cd60, 0xace1474dc1d122e, + 0xb5b5ada8aaff80b8, 0xd819992132456ba, + 0xe3231912d5bf60e6, 0x10e1fff697ed6c69, + 0x8df5efabc5979c8f, 0xca8d3ffa1ef463c1, + 0xb1736b96b6fd83b3, 0xbd308ff8a6b17cb2, + 0xddd0467c64bce4a0, 0xac7cb3f6d05ddbde, + 0x8aa22c0dbef60ee4, 0x6bcdf07a423aa96b, + 0xad4ab7112eb3929d, 0x86c16c98d2c953c6, + 0xd89d64d57a607744, 0xe871c7bf077ba8b7, + 0x87625f056c7c4a8b, 0x11471cd764ad4972, + 0xa93af6c6c79b5d2d, 0xd598e40d3dd89bcf, + 0xd389b47879823479, 0x4aff1d108d4ec2c3, + 0x843610cb4bf160cb, 0xcedf722a585139ba, + 0xa54394fe1eedb8fe, 0xc2974eb4ee658828, + 0xce947a3da6a9273e, 0x733d226229feea32, + 0x811ccc668829b887, 0x806357d5a3f525f, + 0xa163ff802a3426a8, 0xca07c2dcb0cf26f7, + 0xc9bcff6034c13052, 0xfc89b393dd02f0b5, + 0xfc2c3f3841f17c67, 0xbbac2078d443ace2, + 0x9d9ba7832936edc0, 0xd54b944b84aa4c0d, + 0xc5029163f384a931, 0xa9e795e65d4df11, + 0xf64335bcf065d37d, 0x4d4617b5ff4a16d5, + 0x99ea0196163fa42e, 0x504bced1bf8e4e45, + 0xc06481fb9bcf8d39, 0xe45ec2862f71e1d6, + 0xf07da27a82c37088, 0x5d767327bb4e5a4c, + 0x964e858c91ba2655, 0x3a6a07f8d510f86f, + 0xbbe226efb628afea, 0x890489f70a55368b, + 0xeadab0aba3b2dbe5, 0x2b45ac74ccea842e, + 0x92c8ae6b464fc96f, 0x3b0b8bc90012929d, + 0xb77ada0617e3bbcb, 0x9ce6ebb40173744, + 0xe55990879ddcaabd, 0xcc420a6a101d0515, + 0x8f57fa54c2a9eab6, 0x9fa946824a12232d, + 0xb32df8e9f3546564, 0x47939822dc96abf9, + 0xdff9772470297ebd, 0x59787e2b93bc56f7, + 0x8bfbea76c619ef36, 0x57eb4edb3c55b65a, + 0xaefae51477a06b03, 0xede622920b6b23f1, + 0xdab99e59958885c4, 0xe95fab368e45eced, + 0x88b402f7fd75539b, 0x11dbcb0218ebb414, + 0xaae103b5fcd2a881, 0xd652bdc29f26a119, + 0xd59944a37c0752a2, 0x4be76d3346f0495f, + 0x857fcae62d8493a5, 0x6f70a4400c562ddb, + 0xa6dfbd9fb8e5b88e, 0xcb4ccd500f6bb952, + 0xd097ad07a71f26b2, 0x7e2000a41346a7a7, + 0x825ecc24c873782f, 0x8ed400668c0c28c8, + 0xa2f67f2dfa90563b, 0x728900802f0f32fa, + 0xcbb41ef979346bca, 0x4f2b40a03ad2ffb9, + 0xfea126b7d78186bc, 0xe2f610c84987bfa8, + 0x9f24b832e6b0f436, 0xdd9ca7d2df4d7c9, + 0xc6ede63fa05d3143, 0x91503d1c79720dbb, + 0xf8a95fcf88747d94, 0x75a44c6397ce912a, + 0x9b69dbe1b548ce7c, 0xc986afbe3ee11aba, + 0xc24452da229b021b, 0xfbe85badce996168, + 0xf2d56790ab41c2a2, 0xfae27299423fb9c3, + 0x97c560ba6b0919a5, 0xdccd879fc967d41a, + 0xbdb6b8e905cb600f, 0x5400e987bbc1c920, + 0xed246723473e3813, 0x290123e9aab23b68, + 0x9436c0760c86e30b, 0xf9a0b6720aaf6521, + 0xb94470938fa89bce, 0xf808e40e8d5b3e69, + 0xe7958cb87392c2c2, 0xb60b1d1230b20e04, + 0x90bd77f3483bb9b9, 0xb1c6f22b5e6f48c2, + 0xb4ecd5f01a4aa828, 0x1e38aeb6360b1af3, + 0xe2280b6c20dd5232, 0x25c6da63c38de1b0, + 0x8d590723948a535f, 0x579c487e5a38ad0e, + 0xb0af48ec79ace837, 0x2d835a9df0c6d851, + 0xdcdb1b2798182244, 0xf8e431456cf88e65, + 0x8a08f0f8bf0f156b, 0x1b8e9ecb641b58ff, + 0xac8b2d36eed2dac5, 0xe272467e3d222f3f, + 0xd7adf884aa879177, 0x5b0ed81dcc6abb0f, + 0x86ccbb52ea94baea, 0x98e947129fc2b4e9, + 0xa87fea27a539e9a5, 0x3f2398d747b36224, + 0xd29fe4b18e88640e, 0x8eec7f0d19a03aad, + 0x83a3eeeef9153e89, 0x1953cf68300424ac, + 0xa48ceaaab75a8e2b, 0x5fa8c3423c052dd7, + 0xcdb02555653131b6, 0x3792f412cb06794d, + 0x808e17555f3ebf11, 0xe2bbd88bbee40bd0, + 0xa0b19d2ab70e6ed6, 0x5b6aceaeae9d0ec4, + 0xc8de047564d20a8b, 0xf245825a5a445275, + 0xfb158592be068d2e, 0xeed6e2f0f0d56712, + 0x9ced737bb6c4183d, 0x55464dd69685606b, + 0xc428d05aa4751e4c, 0xaa97e14c3c26b886, + 0xf53304714d9265df, 0xd53dd99f4b3066a8, + 0x993fe2c6d07b7fab, 0xe546a8038efe4029, + 0xbf8fdb78849a5f96, 0xde98520472bdd033, + 0xef73d256a5c0f77c, 0x963e66858f6d4440, + 0x95a8637627989aad, 0xdde7001379a44aa8, + 0xbb127c53b17ec159, 0x5560c018580d5d52, + 0xe9d71b689dde71af, 0xaab8f01e6e10b4a6, + 0x9226712162ab070d, 0xcab3961304ca70e8, + 0xb6b00d69bb55c8d1, 0x3d607b97c5fd0d22, + 0xe45c10c42a2b3b05, 0x8cb89a7db77c506a, + 0x8eb98a7a9a5b04e3, 0x77f3608e92adb242, + 0xb267ed1940f1c61c, 0x55f038b237591ed3, + 0xdf01e85f912e37a3, 0x6b6c46dec52f6688, + 0x8b61313bbabce2c6, 0x2323ac4b3b3da015, + 0xae397d8aa96c1b77, 0xabec975e0a0d081a, + 0xd9c7dced53c72255, 0x96e7bd358c904a21, + 0x881cea14545c7575, 0x7e50d64177da2e54, + 0xaa242499697392d2, 0xdde50bd1d5d0b9e9, + 0xd4ad2dbfc3d07787, 0x955e4ec64b44e864, + 0x84ec3c97da624ab4, 0xbd5af13bef0b113e, + 0xa6274bbdd0fadd61, 0xecb1ad8aeacdd58e, + 0xcfb11ead453994ba, 0x67de18eda5814af2, + 0x81ceb32c4b43fcf4, 0x80eacf948770ced7, + 0xa2425ff75e14fc31, 0xa1258379a94d028d, + 0xcad2f7f5359a3b3e, 0x96ee45813a04330, + 0xfd87b5f28300ca0d, 0x8bca9d6e188853fc, + 0x9e74d1b791e07e48, 0x775ea264cf55347e, + 0xc612062576589dda, 0x95364afe032a819e, + 0xf79687aed3eec551, 0x3a83ddbd83f52205, + 0x9abe14cd44753b52, 0xc4926a9672793543, + 0xc16d9a0095928a27, 0x75b7053c0f178294, + 0xf1c90080baf72cb1, 0x5324c68b12dd6339, + 0x971da05074da7bee, 0xd3f6fc16ebca5e04, + 0xbce5086492111aea, 0x88f4bb1ca6bcf585, + 0xec1e4a7db69561a5, 0x2b31e9e3d06c32e6, + 0x9392ee8e921d5d07, 0x3aff322e62439fd0, + 0xb877aa3236a4b449, 0x9befeb9fad487c3, + 0xe69594bec44de15b, 0x4c2ebe687989a9b4, + 0x901d7cf73ab0acd9, 0xf9d37014bf60a11, + 0xb424dc35095cd80f, 0x538484c19ef38c95, + 0xe12e13424bb40e13, 0x2865a5f206b06fba, + 0x8cbccc096f5088cb, 0xf93f87b7442e45d4, + 0xafebff0bcb24aafe, 0xf78f69a51539d749, + 0xdbe6fecebdedd5be, 0xb573440e5a884d1c, + 0x89705f4136b4a597, 0x31680a88f8953031, + 0xabcc77118461cefc, 0xfdc20d2b36ba7c3e, + 0xd6bf94d5e57a42bc, 0x3d32907604691b4d, + 0x8637bd05af6c69b5, 0xa63f9a49c2c1b110, + 0xa7c5ac471b478423, 0xfcf80dc33721d54, + 0xd1b71758e219652b, 0xd3c36113404ea4a9, + 0x83126e978d4fdf3b, 0x645a1cac083126ea, + 0xa3d70a3d70a3d70a, 0x3d70a3d70a3d70a4, + 0xcccccccccccccccc, 0xcccccccccccccccd, + 0x8000000000000000, 0x0, + 0xa000000000000000, 0x0, + 0xc800000000000000, 0x0, + 0xfa00000000000000, 0x0, + 0x9c40000000000000, 0x0, + 0xc350000000000000, 0x0, + 0xf424000000000000, 0x0, + 0x9896800000000000, 0x0, + 0xbebc200000000000, 0x0, + 0xee6b280000000000, 0x0, + 0x9502f90000000000, 0x0, + 0xba43b74000000000, 0x0, + 0xe8d4a51000000000, 0x0, + 0x9184e72a00000000, 0x0, + 0xb5e620f480000000, 0x0, + 0xe35fa931a0000000, 0x0, + 0x8e1bc9bf04000000, 0x0, + 0xb1a2bc2ec5000000, 0x0, + 0xde0b6b3a76400000, 0x0, + 0x8ac7230489e80000, 0x0, + 0xad78ebc5ac620000, 0x0, + 0xd8d726b7177a8000, 0x0, + 0x878678326eac9000, 0x0, + 0xa968163f0a57b400, 0x0, + 0xd3c21bcecceda100, 0x0, + 0x84595161401484a0, 0x0, + 0xa56fa5b99019a5c8, 0x0, + 0xcecb8f27f4200f3a, 0x0, + 0x813f3978f8940984, 0x4000000000000000, + 0xa18f07d736b90be5, 0x5000000000000000, + 0xc9f2c9cd04674ede, 0xa400000000000000, + 0xfc6f7c4045812296, 0x4d00000000000000, + 0x9dc5ada82b70b59d, 0xf020000000000000, + 0xc5371912364ce305, 0x6c28000000000000, + 0xf684df56c3e01bc6, 0xc732000000000000, + 0x9a130b963a6c115c, 0x3c7f400000000000, + 0xc097ce7bc90715b3, 0x4b9f100000000000, + 0xf0bdc21abb48db20, 0x1e86d40000000000, + 0x96769950b50d88f4, 0x1314448000000000, + 0xbc143fa4e250eb31, 0x17d955a000000000, + 0xeb194f8e1ae525fd, 0x5dcfab0800000000, + 0x92efd1b8d0cf37be, 0x5aa1cae500000000, + 0xb7abc627050305ad, 0xf14a3d9e40000000, + 0xe596b7b0c643c719, 0x6d9ccd05d0000000, + 0x8f7e32ce7bea5c6f, 0xe4820023a2000000, + 0xb35dbf821ae4f38b, 0xdda2802c8a800000, + 0xe0352f62a19e306e, 0xd50b2037ad200000, + 0x8c213d9da502de45, 0x4526f422cc340000, + 0xaf298d050e4395d6, 0x9670b12b7f410000, + 0xdaf3f04651d47b4c, 0x3c0cdd765f114000, + 0x88d8762bf324cd0f, 0xa5880a69fb6ac800, + 0xab0e93b6efee0053, 0x8eea0d047a457a00, + 0xd5d238a4abe98068, 0x72a4904598d6d880, + 0x85a36366eb71f041, 0x47a6da2b7f864750, + 0xa70c3c40a64e6c51, 0x999090b65f67d924, + 0xd0cf4b50cfe20765, 0xfff4b4e3f741cf6d, + 0x82818f1281ed449f, 0xbff8f10e7a8921a4, + 0xa321f2d7226895c7, 0xaff72d52192b6a0d, + 0xcbea6f8ceb02bb39, 0x9bf4f8a69f764490, + 0xfee50b7025c36a08, 0x2f236d04753d5b4, + 0x9f4f2726179a2245, 0x1d762422c946590, + 0xc722f0ef9d80aad6, 0x424d3ad2b7b97ef5, + 0xf8ebad2b84e0d58b, 0xd2e0898765a7deb2, + 0x9b934c3b330c8577, 0x63cc55f49f88eb2f, + 0xc2781f49ffcfa6d5, 0x3cbf6b71c76b25fb, + 0xf316271c7fc3908a, 0x8bef464e3945ef7a, + 0x97edd871cfda3a56, 0x97758bf0e3cbb5ac, + 0xbde94e8e43d0c8ec, 0x3d52eeed1cbea317, + 0xed63a231d4c4fb27, 0x4ca7aaa863ee4bdd, + 0x945e455f24fb1cf8, 0x8fe8caa93e74ef6a, + 0xb975d6b6ee39e436, 0xb3e2fd538e122b44, + 0xe7d34c64a9c85d44, 0x60dbbca87196b616, + 0x90e40fbeea1d3a4a, 0xbc8955e946fe31cd, + 0xb51d13aea4a488dd, 0x6babab6398bdbe41, + 0xe264589a4dcdab14, 0xc696963c7eed2dd1, + 0x8d7eb76070a08aec, 0xfc1e1de5cf543ca2, + 0xb0de65388cc8ada8, 0x3b25a55f43294bcb, + 0xdd15fe86affad912, 0x49ef0eb713f39ebe, + 0x8a2dbf142dfcc7ab, 0x6e3569326c784337, + 0xacb92ed9397bf996, 0x49c2c37f07965404, + 0xd7e77a8f87daf7fb, 0xdc33745ec97be906, + 0x86f0ac99b4e8dafd, 0x69a028bb3ded71a3, + 0xa8acd7c0222311bc, 0xc40832ea0d68ce0c, + 0xd2d80db02aabd62b, 0xf50a3fa490c30190, + 0x83c7088e1aab65db, 0x792667c6da79e0fa, + 0xa4b8cab1a1563f52, 0x577001b891185938, + 0xcde6fd5e09abcf26, 0xed4c0226b55e6f86, + 0x80b05e5ac60b6178, 0x544f8158315b05b4, + 0xa0dc75f1778e39d6, 0x696361ae3db1c721, + 0xc913936dd571c84c, 0x3bc3a19cd1e38e9, + 0xfb5878494ace3a5f, 0x4ab48a04065c723, + 0x9d174b2dcec0e47b, 0x62eb0d64283f9c76, + 0xc45d1df942711d9a, 0x3ba5d0bd324f8394, + 0xf5746577930d6500, 0xca8f44ec7ee36479, + 0x9968bf6abbe85f20, 0x7e998b13cf4e1ecb, + 0xbfc2ef456ae276e8, 0x9e3fedd8c321a67e, + 0xefb3ab16c59b14a2, 0xc5cfe94ef3ea101e, + 0x95d04aee3b80ece5, 0xbba1f1d158724a12, + 0xbb445da9ca61281f, 0x2a8a6e45ae8edc97, + 0xea1575143cf97226, 0xf52d09d71a3293bd, + 0x924d692ca61be758, 0x593c2626705f9c56, + 0xb6e0c377cfa2e12e, 0x6f8b2fb00c77836c, + 0xe498f455c38b997a, 0xb6dfb9c0f956447, + 0x8edf98b59a373fec, 0x4724bd4189bd5eac, + 0xb2977ee300c50fe7, 0x58edec91ec2cb657, + 0xdf3d5e9bc0f653e1, 0x2f2967b66737e3ed, + 0x8b865b215899f46c, 0xbd79e0d20082ee74, + 0xae67f1e9aec07187, 0xecd8590680a3aa11, + 0xda01ee641a708de9, 0xe80e6f4820cc9495, + 0x884134fe908658b2, 0x3109058d147fdcdd, + 0xaa51823e34a7eede, 0xbd4b46f0599fd415, + 0xd4e5e2cdc1d1ea96, 0x6c9e18ac7007c91a, + 0x850fadc09923329e, 0x3e2cf6bc604ddb0, + 0xa6539930bf6bff45, 0x84db8346b786151c, + 0xcfe87f7cef46ff16, 0xe612641865679a63, + 0x81f14fae158c5f6e, 0x4fcb7e8f3f60c07e, + 0xa26da3999aef7749, 0xe3be5e330f38f09d, + 0xcb090c8001ab551c, 0x5cadf5bfd3072cc5, + 0xfdcb4fa002162a63, 0x73d9732fc7c8f7f6, + 0x9e9f11c4014dda7e, 0x2867e7fddcdd9afa, + 0xc646d63501a1511d, 0xb281e1fd541501b8, + 0xf7d88bc24209a565, 0x1f225a7ca91a4226, + 0x9ae757596946075f, 0x3375788de9b06958, + 0xc1a12d2fc3978937, 0x52d6b1641c83ae, + 0xf209787bb47d6b84, 0xc0678c5dbd23a49a, + 0x9745eb4d50ce6332, 0xf840b7ba963646e0, + 0xbd176620a501fbff, 0xb650e5a93bc3d898, + 0xec5d3fa8ce427aff, 0xa3e51f138ab4cebe, + 0x93ba47c980e98cdf, 0xc66f336c36b10137, + 0xb8a8d9bbe123f017, 0xb80b0047445d4184, + 0xe6d3102ad96cec1d, 0xa60dc059157491e5, + 0x9043ea1ac7e41392, 0x87c89837ad68db2f, + 0xb454e4a179dd1877, 0x29babe4598c311fb, + 0xe16a1dc9d8545e94, 0xf4296dd6fef3d67a, + 0x8ce2529e2734bb1d, 0x1899e4a65f58660c, + 0xb01ae745b101e9e4, 0x5ec05dcff72e7f8f, + 0xdc21a1171d42645d, 0x76707543f4fa1f73, + 0x899504ae72497eba, 0x6a06494a791c53a8, + 0xabfa45da0edbde69, 0x487db9d17636892, + 0xd6f8d7509292d603, 0x45a9d2845d3c42b6, + 0x865b86925b9bc5c2, 0xb8a2392ba45a9b2, + 0xa7f26836f282b732, 0x8e6cac7768d7141e, + 0xd1ef0244af2364ff, 0x3207d795430cd926, + 0x8335616aed761f1f, 0x7f44e6bd49e807b8, + 0xa402b9c5a8d3a6e7, 0x5f16206c9c6209a6, + 0xcd036837130890a1, 0x36dba887c37a8c0f, + 0x802221226be55a64, 0xc2494954da2c9789, + 0xa02aa96b06deb0fd, 0xf2db9baa10b7bd6c, + 0xc83553c5c8965d3d, 0x6f92829494e5acc7, + 0xfa42a8b73abbf48c, 0xcb772339ba1f17f9, + 0x9c69a97284b578d7, 0xff2a760414536efb, + 0xc38413cf25e2d70d, 0xfef5138519684aba, + 0xf46518c2ef5b8cd1, 0x7eb258665fc25d69, + 0x98bf2f79d5993802, 0xef2f773ffbd97a61, + 0xbeeefb584aff8603, 0xaafb550ffacfd8fa, + 0xeeaaba2e5dbf6784, 0x95ba2a53f983cf38, + 0x952ab45cfa97a0b2, 0xdd945a747bf26183, + 0xba756174393d88df, 0x94f971119aeef9e4, + 0xe912b9d1478ceb17, 0x7a37cd5601aab85d, + 0x91abb422ccb812ee, 0xac62e055c10ab33a, + 0xb616a12b7fe617aa, 0x577b986b314d6009, + 0xe39c49765fdf9d94, 0xed5a7e85fda0b80b, + 0x8e41ade9fbebc27d, 0x14588f13be847307, + 0xb1d219647ae6b31c, 0x596eb2d8ae258fc8, + 0xde469fbd99a05fe3, 0x6fca5f8ed9aef3bb, + 0x8aec23d680043bee, 0x25de7bb9480d5854, + 0xada72ccc20054ae9, 0xaf561aa79a10ae6a, + 0xd910f7ff28069da4, 0x1b2ba1518094da04, + 0x87aa9aff79042286, 0x90fb44d2f05d0842, + 0xa99541bf57452b28, 0x353a1607ac744a53, + 0xd3fa922f2d1675f2, 0x42889b8997915ce8, + 0x847c9b5d7c2e09b7, 0x69956135febada11, + 0xa59bc234db398c25, 0x43fab9837e699095, + 0xcf02b2c21207ef2e, 0x94f967e45e03f4bb, + 0x8161afb94b44f57d, 0x1d1be0eebac278f5, + 0xa1ba1ba79e1632dc, 0x6462d92a69731732, + 0xca28a291859bbf93, 0x7d7b8f7503cfdcfe, + 0xfcb2cb35e702af78, 0x5cda735244c3d43e, + 0x9defbf01b061adab, 0x3a0888136afa64a7, + 0xc56baec21c7a1916, 0x88aaa1845b8fdd0, + 0xf6c69a72a3989f5b, 0x8aad549e57273d45, + 0x9a3c2087a63f6399, 0x36ac54e2f678864b, + 0xc0cb28a98fcf3c7f, 0x84576a1bb416a7dd, + 0xf0fdf2d3f3c30b9f, 0x656d44a2a11c51d5, + 0x969eb7c47859e743, 0x9f644ae5a4b1b325, + 0xbc4665b596706114, 0x873d5d9f0dde1fee, + 0xeb57ff22fc0c7959, 0xa90cb506d155a7ea, + 0x9316ff75dd87cbd8, 0x9a7f12442d588f2, + 0xb7dcbf5354e9bece, 0xc11ed6d538aeb2f, + 0xe5d3ef282a242e81, 0x8f1668c8a86da5fa, + 0x8fa475791a569d10, 0xf96e017d694487bc, + 0xb38d92d760ec4455, 0x37c981dcc395a9ac, + 0xe070f78d3927556a, 0x85bbe253f47b1417, + 0x8c469ab843b89562, 0x93956d7478ccec8e, + 0xaf58416654a6babb, 0x387ac8d1970027b2, + 0xdb2e51bfe9d0696a, 0x6997b05fcc0319e, + 0x88fcf317f22241e2, 0x441fece3bdf81f03, + 0xab3c2fddeeaad25a, 0xd527e81cad7626c3, + 0xd60b3bd56a5586f1, 0x8a71e223d8d3b074, + 0x85c7056562757456, 0xf6872d5667844e49, + 0xa738c6bebb12d16c, 0xb428f8ac016561db, + 0xd106f86e69d785c7, 0xe13336d701beba52, + 0x82a45b450226b39c, 0xecc0024661173473, + 0xa34d721642b06084, 0x27f002d7f95d0190, + 0xcc20ce9bd35c78a5, 0x31ec038df7b441f4, + 0xff290242c83396ce, 0x7e67047175a15271, + 0x9f79a169bd203e41, 0xf0062c6e984d386, + 0xc75809c42c684dd1, 0x52c07b78a3e60868, + 0xf92e0c3537826145, 0xa7709a56ccdf8a82, + 0x9bbcc7a142b17ccb, 0x88a66076400bb691, + 0xc2abf989935ddbfe, 0x6acff893d00ea435, + 0xf356f7ebf83552fe, 0x583f6b8c4124d43, + 0x98165af37b2153de, 0xc3727a337a8b704a, + 0xbe1bf1b059e9a8d6, 0x744f18c0592e4c5c, + 0xeda2ee1c7064130c, 0x1162def06f79df73, + 0x9485d4d1c63e8be7, 0x8addcb5645ac2ba8, + 0xb9a74a0637ce2ee1, 0x6d953e2bd7173692, + 0xe8111c87c5c1ba99, 0xc8fa8db6ccdd0437, + 0x910ab1d4db9914a0, 0x1d9c9892400a22a2, + 0xb54d5e4a127f59c8, 0x2503beb6d00cab4b, + 0xe2a0b5dc971f303a, 0x2e44ae64840fd61d, + 0x8da471a9de737e24, 0x5ceaecfed289e5d2, + 0xb10d8e1456105dad, 0x7425a83e872c5f47, + 0xdd50f1996b947518, 0xd12f124e28f77719, + 0x8a5296ffe33cc92f, 0x82bd6b70d99aaa6f, + 0xace73cbfdc0bfb7b, 0x636cc64d1001550b, + 0xd8210befd30efa5a, 0x3c47f7e05401aa4e, + 0x8714a775e3e95c78, 0x65acfaec34810a71, + 0xa8d9d1535ce3b396, 0x7f1839a741a14d0d, + 0xd31045a8341ca07c, 0x1ede48111209a050, + 0x83ea2b892091e44d, 0x934aed0aab460432, + 0xa4e4b66b68b65d60, 0xf81da84d5617853f, + 0xce1de40642e3f4b9, 0x36251260ab9d668e, + 0x80d2ae83e9ce78f3, 0xc1d72b7c6b426019, + 0xa1075a24e4421730, 0xb24cf65b8612f81f, + 0xc94930ae1d529cfc, 0xdee033f26797b627, + 0xfb9b7cd9a4a7443c, 0x169840ef017da3b1, + 0x9d412e0806e88aa5, 0x8e1f289560ee864e, + 0xc491798a08a2ad4e, 0xf1a6f2bab92a27e2, + 0xf5b5d7ec8acb58a2, 0xae10af696774b1db, + 0x9991a6f3d6bf1765, 0xacca6da1e0a8ef29, + 0xbff610b0cc6edd3f, 0x17fd090a58d32af3, + 0xeff394dcff8a948e, 0xddfc4b4cef07f5b0, + 0x95f83d0a1fb69cd9, 0x4abdaf101564f98e, + 0xbb764c4ca7a4440f, 0x9d6d1ad41abe37f1, + 0xea53df5fd18d5513, 0x84c86189216dc5ed, + 0x92746b9be2f8552c, 0x32fd3cf5b4e49bb4, + 0xb7118682dbb66a77, 0x3fbc8c33221dc2a1, + 0xe4d5e82392a40515, 0xfabaf3feaa5334a, + 0x8f05b1163ba6832d, 0x29cb4d87f2a7400e, + 0xb2c71d5bca9023f8, 0x743e20e9ef511012, + 0xdf78e4b2bd342cf6, 0x914da9246b255416, + 0x8bab8eefb6409c1a, 0x1ad089b6c2f7548e, + 0xae9672aba3d0c320, 0xa184ac2473b529b1, + 0xda3c0f568cc4f3e8, 0xc9e5d72d90a2741e, + 0x8865899617fb1871, 0x7e2fa67c7a658892, + 0xaa7eebfb9df9de8d, 0xddbb901b98feeab7, + 0xd51ea6fa85785631, 0x552a74227f3ea565, + 0x8533285c936b35de, 0xd53a88958f87275f, + 0xa67ff273b8460356, 0x8a892abaf368f137, + 0xd01fef10a657842c, 0x2d2b7569b0432d85, + 0x8213f56a67f6b29b, 0x9c3b29620e29fc73, + 0xa298f2c501f45f42, 0x8349f3ba91b47b8f, + 0xcb3f2f7642717713, 0x241c70a936219a73, + 0xfe0efb53d30dd4d7, 0xed238cd383aa0110, + 0x9ec95d1463e8a506, 0xf4363804324a40aa, + 0xc67bb4597ce2ce48, 0xb143c6053edcd0d5, + 0xf81aa16fdc1b81da, 0xdd94b7868e94050a, + 0x9b10a4e5e9913128, 0xca7cf2b4191c8326, + 0xc1d4ce1f63f57d72, 0xfd1c2f611f63a3f0, + 0xf24a01a73cf2dccf, 0xbc633b39673c8cec, + 0x976e41088617ca01, 0xd5be0503e085d813, + 0xbd49d14aa79dbc82, 0x4b2d8644d8a74e18, + 0xec9c459d51852ba2, 0xddf8e7d60ed1219e, + 0x93e1ab8252f33b45, 0xcabb90e5c942b503, + 0xb8da1662e7b00a17, 0x3d6a751f3b936243, + 0xe7109bfba19c0c9d, 0xcc512670a783ad4, + 0x906a617d450187e2, 0x27fb2b80668b24c5, + 0xb484f9dc9641e9da, 0xb1f9f660802dedf6, + 0xe1a63853bbd26451, 0x5e7873f8a0396973, + 0x8d07e33455637eb2, 0xdb0b487b6423e1e8, + 0xb049dc016abc5e5f, 0x91ce1a9a3d2cda62, + 0xdc5c5301c56b75f7, 0x7641a140cc7810fb, + 0x89b9b3e11b6329ba, 0xa9e904c87fcb0a9d, + 0xac2820d9623bf429, 0x546345fa9fbdcd44, + 0xd732290fbacaf133, 0xa97c177947ad4095, + 0x867f59a9d4bed6c0, 0x49ed8eabcccc485d, + 0xa81f301449ee8c70, 0x5c68f256bfff5a74, + 0xd226fc195c6a2f8c, 0x73832eec6fff3111, + 0x83585d8fd9c25db7, 0xc831fd53c5ff7eab, + 0xa42e74f3d032f525, 0xba3e7ca8b77f5e55, + 0xcd3a1230c43fb26f, 0x28ce1bd2e55f35eb, + 0x80444b5e7aa7cf85, 0x7980d163cf5b81b3, + 0xa0555e361951c366, 0xd7e105bcc332621f, + 0xc86ab5c39fa63440, 0x8dd9472bf3fefaa7, + 0xfa856334878fc150, 0xb14f98f6f0feb951, + 0x9c935e00d4b9d8d2, 0x6ed1bf9a569f33d3, + 0xc3b8358109e84f07, 0xa862f80ec4700c8, + 0xf4a642e14c6262c8, 0xcd27bb612758c0fa, + 0x98e7e9cccfbd7dbd, 0x8038d51cb897789c, + 0xbf21e44003acdd2c, 0xe0470a63e6bd56c3, + 0xeeea5d5004981478, 0x1858ccfce06cac74, + 0x95527a5202df0ccb, 0xf37801e0c43ebc8, + 0xbaa718e68396cffd, 0xd30560258f54e6ba, + 0xe950df20247c83fd, 0x47c6b82ef32a2069, + 0x91d28b7416cdd27e, 0x4cdc331d57fa5441, + 0xb6472e511c81471d, 0xe0133fe4adf8e952, + 0xe3d8f9e563a198e5, 0x58180fddd97723a6, + 0x8e679c2f5e44ff8f, 0x570f09eaa7ea7648, + }; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr uint64_t + powers_template::power_of_five_128[number_of_entries]; + +#endif + +using powers = powers_template<>; + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/include/fast_float/float_common.h b/vnext/external/fast-float/include/fast_float/float_common.h new file mode 100644 index 00000000000..ef499ce7925 --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/float_common.h @@ -0,0 +1,1240 @@ +#ifndef FASTFLOAT_FLOAT_COMMON_H +#define FASTFLOAT_FLOAT_COMMON_H + +#include +#include +#include +#include +#include +#include +#include +#ifdef __has_include +#if __has_include() && (__cplusplus > 202002L || _MSVC_LANG > 202002L) +#include +#endif +#endif +#include "constexpr_feature_detect.h" + +#define FASTFLOAT_VERSION_MAJOR 8 +#define FASTFLOAT_VERSION_MINOR 0 +#define FASTFLOAT_VERSION_PATCH 0 + +#define FASTFLOAT_STRINGIZE_IMPL(x) #x +#define FASTFLOAT_STRINGIZE(x) FASTFLOAT_STRINGIZE_IMPL(x) + +#define FASTFLOAT_VERSION_STR \ + FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MAJOR) \ + "." FASTFLOAT_STRINGIZE(FASTFLOAT_VERSION_MINOR) "." FASTFLOAT_STRINGIZE( \ + FASTFLOAT_VERSION_PATCH) + +#define FASTFLOAT_VERSION \ + (FASTFLOAT_VERSION_MAJOR * 10000 + FASTFLOAT_VERSION_MINOR * 100 + \ + FASTFLOAT_VERSION_PATCH) + +namespace fast_float { + +enum class chars_format : uint64_t; + +namespace detail { +constexpr chars_format basic_json_fmt = chars_format(1 << 5); +constexpr chars_format basic_fortran_fmt = chars_format(1 << 6); +} // namespace detail + +enum class chars_format : uint64_t { + scientific = 1 << 0, + fixed = 1 << 2, + hex = 1 << 3, + no_infnan = 1 << 4, + // RFC 8259: https://datatracker.ietf.org/doc/html/rfc8259#section-6 + json = uint64_t(detail::basic_json_fmt) | fixed | scientific | no_infnan, + // Extension of RFC 8259 where, e.g., "inf" and "nan" are allowed. + json_or_infnan = uint64_t(detail::basic_json_fmt) | fixed | scientific, + fortran = uint64_t(detail::basic_fortran_fmt) | fixed | scientific, + general = fixed | scientific, + allow_leading_plus = 1 << 7, + skip_white_space = 1 << 8, +}; + +template struct from_chars_result_t { + UC const *ptr; + std::errc ec; +}; + +using from_chars_result = from_chars_result_t; + +template struct parse_options_t { + constexpr explicit parse_options_t(chars_format fmt = chars_format::general, + UC dot = UC('.'), int b = 10) + : format(fmt), decimal_point(dot), base(b) {} + + /** Which number formats are accepted */ + chars_format format; + /** The character used as decimal point */ + UC decimal_point; + /** The base used for integers */ + int base; +}; + +using parse_options = parse_options_t; + +} // namespace fast_float + +#if FASTFLOAT_HAS_BIT_CAST +#include +#endif + +#if (defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || \ + defined(__amd64) || defined(__aarch64__) || defined(_M_ARM64) || \ + defined(__MINGW64__) || defined(__s390x__) || \ + (defined(__ppc64__) || defined(__PPC64__) || defined(__ppc64le__) || \ + defined(__PPC64LE__)) || \ + defined(__loongarch64)) +#define FASTFLOAT_64BIT 1 +#elif (defined(__i386) || defined(__i386__) || defined(_M_IX86) || \ + defined(__arm__) || defined(_M_ARM) || defined(__ppc__) || \ + defined(__MINGW32__) || defined(__EMSCRIPTEN__)) +#define FASTFLOAT_32BIT 1 +#else + // Need to check incrementally, since SIZE_MAX is a size_t, avoid overflow. +// We can never tell the register width, but the SIZE_MAX is a good +// approximation. UINTPTR_MAX and INTPTR_MAX are optional, so avoid them for max +// portability. +#if SIZE_MAX == 0xffff +#error Unknown platform (16-bit, unsupported) +#elif SIZE_MAX == 0xffffffff +#define FASTFLOAT_32BIT 1 +#elif SIZE_MAX == 0xffffffffffffffff +#define FASTFLOAT_64BIT 1 +#else +#error Unknown platform (not 32-bit, not 64-bit?) +#endif +#endif + +#if ((defined(_WIN32) || defined(_WIN64)) && !defined(__clang__)) || \ + (defined(_M_ARM64) && !defined(__MINGW32__)) +#include +#endif + +#if defined(_MSC_VER) && !defined(__clang__) +#define FASTFLOAT_VISUAL_STUDIO 1 +#endif + +#if defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ +#define FASTFLOAT_IS_BIG_ENDIAN (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#elif defined _WIN32 +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#else +#if defined(__APPLE__) || defined(__FreeBSD__) +#include +#elif defined(sun) || defined(__sun) +#include +#elif defined(__MVS__) +#include +#else +#ifdef __has_include +#if __has_include() +#include +#endif //__has_include() +#endif //__has_include +#endif +# +#ifndef __BYTE_ORDER__ +// safe choice +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#endif +# +#ifndef __ORDER_LITTLE_ENDIAN__ +// safe choice +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#endif +# +#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ +#define FASTFLOAT_IS_BIG_ENDIAN 0 +#else +#define FASTFLOAT_IS_BIG_ENDIAN 1 +#endif +#endif + +#if defined(__SSE2__) || (defined(FASTFLOAT_VISUAL_STUDIO) && \ + (defined(_M_AMD64) || defined(_M_X64) || \ + (defined(_M_IX86_FP) && _M_IX86_FP == 2))) +#define FASTFLOAT_SSE2 1 +#endif + +#if defined(__aarch64__) || defined(_M_ARM64) +#define FASTFLOAT_NEON 1 +#endif + +#if defined(FASTFLOAT_SSE2) || defined(FASTFLOAT_NEON) +#define FASTFLOAT_HAS_SIMD 1 +#endif + +#if defined(__GNUC__) +// disable -Wcast-align=strict (GCC only) +#define FASTFLOAT_SIMD_DISABLE_WARNINGS \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wcast-align\"") +#else +#define FASTFLOAT_SIMD_DISABLE_WARNINGS +#endif + +#if defined(__GNUC__) +#define FASTFLOAT_SIMD_RESTORE_WARNINGS _Pragma("GCC diagnostic pop") +#else +#define FASTFLOAT_SIMD_RESTORE_WARNINGS +#endif + +#ifdef FASTFLOAT_VISUAL_STUDIO +#define fastfloat_really_inline __forceinline +#else +#define fastfloat_really_inline inline __attribute__((always_inline)) +#endif + +#ifndef FASTFLOAT_ASSERT +#define FASTFLOAT_ASSERT(x) \ + { ((void)(x)); } +#endif + +#ifndef FASTFLOAT_DEBUG_ASSERT +#define FASTFLOAT_DEBUG_ASSERT(x) \ + { ((void)(x)); } +#endif + +// rust style `try!()` macro, or `?` operator +#define FASTFLOAT_TRY(x) \ + { \ + if (!(x)) \ + return false; \ + } + +#define FASTFLOAT_ENABLE_IF(...) \ + typename std::enable_if<(__VA_ARGS__), int>::type + +namespace fast_float { + +fastfloat_really_inline constexpr bool cpp20_and_in_constexpr() { +#if FASTFLOAT_HAS_IS_CONSTANT_EVALUATED + return std::is_constant_evaluated(); +#else + return false; +#endif +} + +template +struct is_supported_float_type + : std::integral_constant< + bool, std::is_same::value || std::is_same::value +#ifdef __STDCPP_FLOAT64_T__ + || std::is_same::value +#endif +#ifdef __STDCPP_FLOAT32_T__ + || std::is_same::value +#endif +#ifdef __STDCPP_FLOAT16_T__ + || std::is_same::value +#endif +#ifdef __STDCPP_BFLOAT16_T__ + || std::is_same::value +#endif + > { +}; + +template +using equiv_uint_t = typename std::conditional< + sizeof(T) == 1, uint8_t, + typename std::conditional< + sizeof(T) == 2, uint16_t, + typename std::conditional::type>::type>::type; + +template struct is_supported_integer_type : std::is_integral {}; + +template +struct is_supported_char_type + : std::integral_constant::value || + std::is_same::value || + std::is_same::value || + std::is_same::value +#ifdef __cpp_char8_t + || std::is_same::value +#endif + > { +}; + +// Compares two ASCII strings in a case insensitive manner. +template +inline FASTFLOAT_CONSTEXPR14 bool +fastfloat_strncasecmp(UC const *actual_mixedcase, UC const *expected_lowercase, + size_t length) { + for (size_t i = 0; i < length; ++i) { + UC const actual = actual_mixedcase[i]; + if ((actual < 256 ? actual | 32 : actual) != expected_lowercase[i]) { + return false; + } + } + return true; +} + +#ifndef FLT_EVAL_METHOD +#error "FLT_EVAL_METHOD should be defined, please include cfloat." +#endif + +// a pointer and a length to a contiguous block of memory +template struct span { + T const *ptr; + size_t length; + + constexpr span(T const *_ptr, size_t _length) : ptr(_ptr), length(_length) {} + + constexpr span() : ptr(nullptr), length(0) {} + + constexpr size_t len() const noexcept { return length; } + + FASTFLOAT_CONSTEXPR14 const T &operator[](size_t index) const noexcept { + FASTFLOAT_DEBUG_ASSERT(index < length); + return ptr[index]; + } +}; + +struct value128 { + uint64_t low; + uint64_t high; + + constexpr value128(uint64_t _low, uint64_t _high) : low(_low), high(_high) {} + + constexpr value128() : low(0), high(0) {} +}; + +/* Helper C++14 constexpr generic implementation of leading_zeroes */ +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 int +leading_zeroes_generic(uint64_t input_num, int last_bit = 0) { + if (input_num & uint64_t(0xffffffff00000000)) { + input_num >>= 32; + last_bit |= 32; + } + if (input_num & uint64_t(0xffff0000)) { + input_num >>= 16; + last_bit |= 16; + } + if (input_num & uint64_t(0xff00)) { + input_num >>= 8; + last_bit |= 8; + } + if (input_num & uint64_t(0xf0)) { + input_num >>= 4; + last_bit |= 4; + } + if (input_num & uint64_t(0xc)) { + input_num >>= 2; + last_bit |= 2; + } + if (input_num & uint64_t(0x2)) { /* input_num >>= 1; */ + last_bit |= 1; + } + return 63 - last_bit; +} + +/* result might be undefined when input_num is zero */ +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 int +leading_zeroes(uint64_t input_num) { + assert(input_num > 0); + if (cpp20_and_in_constexpr()) { + return leading_zeroes_generic(input_num); + } +#ifdef FASTFLOAT_VISUAL_STUDIO +#if defined(_M_X64) || defined(_M_ARM64) + unsigned long leading_zero = 0; + // Search the mask data from most significant bit (MSB) + // to least significant bit (LSB) for a set bit (1). + _BitScanReverse64(&leading_zero, input_num); + return (int)(63 - leading_zero); +#else + return leading_zeroes_generic(input_num); +#endif +#else + return __builtin_clzll(input_num); +#endif +} + +// slow emulation routine for 32-bit +fastfloat_really_inline constexpr uint64_t emulu(uint32_t x, uint32_t y) { + return x * (uint64_t)y; +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t +umul128_generic(uint64_t ab, uint64_t cd, uint64_t *hi) { + uint64_t ad = emulu((uint32_t)(ab >> 32), (uint32_t)cd); + uint64_t bd = emulu((uint32_t)ab, (uint32_t)cd); + uint64_t adbc = ad + emulu((uint32_t)ab, (uint32_t)(cd >> 32)); + uint64_t adbc_carry = (uint64_t)(adbc < ad); + uint64_t lo = bd + (adbc << 32); + *hi = emulu((uint32_t)(ab >> 32), (uint32_t)(cd >> 32)) + (adbc >> 32) + + (adbc_carry << 32) + (uint64_t)(lo < bd); + return lo; +} + +#ifdef FASTFLOAT_32BIT + +// slow emulation routine for 32-bit +#if !defined(__MINGW64__) +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 uint64_t _umul128(uint64_t ab, + uint64_t cd, + uint64_t *hi) { + return umul128_generic(ab, cd, hi); +} +#endif // !__MINGW64__ + +#endif // FASTFLOAT_32BIT + +// compute 64-bit a*b +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 value128 +full_multiplication(uint64_t a, uint64_t b) { + if (cpp20_and_in_constexpr()) { + value128 answer; + answer.low = umul128_generic(a, b, &answer.high); + return answer; + } + value128 answer; +#if defined(_M_ARM64) && !defined(__MINGW32__) + // ARM64 has native support for 64-bit multiplications, no need to emulate + // But MinGW on ARM64 doesn't have native support for 64-bit multiplications + answer.high = __umulh(a, b); + answer.low = a * b; +#elif defined(FASTFLOAT_32BIT) || \ + (defined(_WIN64) && !defined(__clang__) && !defined(_M_ARM64)) + answer.low = _umul128(a, b, &answer.high); // _umul128 not available on ARM64 +#elif defined(FASTFLOAT_64BIT) && defined(__SIZEOF_INT128__) + __uint128_t r = ((__uint128_t)a) * b; + answer.low = uint64_t(r); + answer.high = uint64_t(r >> 64); +#else + answer.low = umul128_generic(a, b, &answer.high); +#endif + return answer; +} + +struct adjusted_mantissa { + uint64_t mantissa{0}; + int32_t power2{0}; // a negative value indicates an invalid result + adjusted_mantissa() = default; + + constexpr bool operator==(adjusted_mantissa const &o) const { + return mantissa == o.mantissa && power2 == o.power2; + } + + constexpr bool operator!=(adjusted_mantissa const &o) const { + return mantissa != o.mantissa || power2 != o.power2; + } +}; + +// Bias so we can get the real exponent with an invalid adjusted_mantissa. +constexpr static int32_t invalid_am_bias = -0x8000; + +// used for binary_format_lookup_tables::max_mantissa +constexpr uint64_t constant_55555 = 5 * 5 * 5 * 5 * 5; + +template struct binary_format_lookup_tables; + +template struct binary_format : binary_format_lookup_tables { + using equiv_uint = equiv_uint_t; + + static constexpr int mantissa_explicit_bits(); + static constexpr int minimum_exponent(); + static constexpr int infinite_power(); + static constexpr int sign_index(); + static constexpr int + min_exponent_fast_path(); // used when fegetround() == FE_TONEAREST + static constexpr int max_exponent_fast_path(); + static constexpr int max_exponent_round_to_even(); + static constexpr int min_exponent_round_to_even(); + static constexpr uint64_t max_mantissa_fast_path(int64_t power); + static constexpr uint64_t + max_mantissa_fast_path(); // used when fegetround() == FE_TONEAREST + static constexpr int largest_power_of_ten(); + static constexpr int smallest_power_of_ten(); + static constexpr T exact_power_of_ten(int64_t power); + static constexpr size_t max_digits(); + static constexpr equiv_uint exponent_mask(); + static constexpr equiv_uint mantissa_mask(); + static constexpr equiv_uint hidden_bit_mask(); +}; + +template struct binary_format_lookup_tables { + static constexpr double powers_of_ten[] = { + 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9, 1e10, 1e11, + 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19, 1e20, 1e21, 1e22}; + + // Largest integer value v so that (5**index * v) <= 1<<53. + // 0x20000000000000 == 1 << 53 + static constexpr uint64_t max_mantissa[] = { + 0x20000000000000, + 0x20000000000000 / 5, + 0x20000000000000 / (5 * 5), + 0x20000000000000 / (5 * 5 * 5), + 0x20000000000000 / (5 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555), + 0x20000000000000 / (constant_55555 * 5), + 0x20000000000000 / (constant_55555 * 5 * 5), + 0x20000000000000 / (constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * 5 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555), + 0x20000000000000 / (constant_55555 * constant_55555 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * 5 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * 5 * 5 * 5 * 5), + 0x20000000000000 / + (constant_55555 * constant_55555 * constant_55555 * constant_55555), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5 * 5 * 5), + 0x20000000000000 / (constant_55555 * constant_55555 * constant_55555 * + constant_55555 * 5 * 5 * 5 * 5)}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr double binary_format_lookup_tables::powers_of_ten[]; + +template +constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; + +#endif + +template struct binary_format_lookup_tables { + static constexpr float powers_of_ten[] = {1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, + 1e6f, 1e7f, 1e8f, 1e9f, 1e10f}; + + // Largest integer value v so that (5**index * v) <= 1<<24. + // 0x1000000 == 1<<24 + static constexpr uint64_t max_mantissa[] = { + 0x1000000, + 0x1000000 / 5, + 0x1000000 / (5 * 5), + 0x1000000 / (5 * 5 * 5), + 0x1000000 / (5 * 5 * 5 * 5), + 0x1000000 / (constant_55555), + 0x1000000 / (constant_55555 * 5), + 0x1000000 / (constant_55555 * 5 * 5), + 0x1000000 / (constant_55555 * 5 * 5 * 5), + 0x1000000 / (constant_55555 * 5 * 5 * 5 * 5), + 0x1000000 / (constant_55555 * constant_55555), + 0x1000000 / (constant_55555 * constant_55555 * 5)}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr float binary_format_lookup_tables::powers_of_ten[]; + +template +constexpr uint64_t binary_format_lookup_tables::max_mantissa[]; + +#endif + +template <> +inline constexpr int binary_format::min_exponent_fast_path() { +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + return 0; +#else + return -22; +#endif +} + +template <> +inline constexpr int binary_format::min_exponent_fast_path() { +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + return 0; +#else + return -10; +#endif +} + +template <> +inline constexpr int binary_format::mantissa_explicit_bits() { + return 52; +} + +template <> +inline constexpr int binary_format::mantissa_explicit_bits() { + return 23; +} + +template <> +inline constexpr int binary_format::max_exponent_round_to_even() { + return 23; +} + +template <> +inline constexpr int binary_format::max_exponent_round_to_even() { + return 10; +} + +template <> +inline constexpr int binary_format::min_exponent_round_to_even() { + return -4; +} + +template <> +inline constexpr int binary_format::min_exponent_round_to_even() { + return -17; +} + +template <> inline constexpr int binary_format::minimum_exponent() { + return -1023; +} + +template <> inline constexpr int binary_format::minimum_exponent() { + return -127; +} + +template <> inline constexpr int binary_format::infinite_power() { + return 0x7FF; +} + +template <> inline constexpr int binary_format::infinite_power() { + return 0xFF; +} + +template <> inline constexpr int binary_format::sign_index() { + return 63; +} + +template <> inline constexpr int binary_format::sign_index() { + return 31; +} + +template <> +inline constexpr int binary_format::max_exponent_fast_path() { + return 22; +} + +template <> +inline constexpr int binary_format::max_exponent_fast_path() { + return 10; +} + +template <> +inline constexpr uint64_t binary_format::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} + +template <> +inline constexpr uint64_t binary_format::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} + +// credit: Jakub Jelínek +#ifdef __STDCPP_FLOAT16_T__ +template struct binary_format_lookup_tables { + static constexpr std::float16_t powers_of_ten[] = {1e0f16, 1e1f16, 1e2f16, + 1e3f16, 1e4f16}; + + // Largest integer value v so that (5**index * v) <= 1<<11. + // 0x800 == 1<<11 + static constexpr uint64_t max_mantissa[] = {0x800, + 0x800 / 5, + 0x800 / (5 * 5), + 0x800 / (5 * 5 * 5), + 0x800 / (5 * 5 * 5 * 5), + 0x800 / (constant_55555)}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr std::float16_t + binary_format_lookup_tables::powers_of_ten[]; + +template +constexpr uint64_t + binary_format_lookup_tables::max_mantissa[]; + +#endif + +template <> +inline constexpr std::float16_t +binary_format::exact_power_of_ten(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7C00; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x03FF; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x0400; +} + +template <> +inline constexpr int binary_format::max_exponent_fast_path() { + return 4; +} + +template <> +inline constexpr int binary_format::mantissa_explicit_bits() { + return 10; +} + +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} + +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // caller is responsible to ensure that + // power >= 0 && power <= 4 + // + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + +template <> +inline constexpr int binary_format::min_exponent_fast_path() { + return 0; +} + +template <> +inline constexpr int +binary_format::max_exponent_round_to_even() { + return 5; +} + +template <> +inline constexpr int +binary_format::min_exponent_round_to_even() { + return -22; +} + +template <> +inline constexpr int binary_format::minimum_exponent() { + return -15; +} + +template <> +inline constexpr int binary_format::infinite_power() { + return 0x1F; +} + +template <> inline constexpr int binary_format::sign_index() { + return 15; +} + +template <> +inline constexpr int binary_format::largest_power_of_ten() { + return 4; +} + +template <> +inline constexpr int binary_format::smallest_power_of_ten() { + return -27; +} + +template <> +inline constexpr size_t binary_format::max_digits() { + return 22; +} +#endif // __STDCPP_FLOAT16_T__ + +// credit: Jakub Jelínek +#ifdef __STDCPP_BFLOAT16_T__ +template struct binary_format_lookup_tables { + static constexpr std::bfloat16_t powers_of_ten[] = {1e0bf16, 1e1bf16, 1e2bf16, + 1e3bf16}; + + // Largest integer value v so that (5**index * v) <= 1<<8. + // 0x100 == 1<<8 + static constexpr uint64_t max_mantissa[] = {0x100, 0x100 / 5, 0x100 / (5 * 5), + 0x100 / (5 * 5 * 5), + 0x100 / (5 * 5 * 5 * 5)}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template +constexpr std::bfloat16_t + binary_format_lookup_tables::powers_of_ten[]; + +template +constexpr uint64_t + binary_format_lookup_tables::max_mantissa[]; + +#endif + +template <> +inline constexpr std::bfloat16_t +binary_format::exact_power_of_ten(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; +} + +template <> +inline constexpr int binary_format::max_exponent_fast_path() { + return 3; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7F80; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x007F; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x0080; +} + +template <> +inline constexpr int binary_format::mantissa_explicit_bits() { + return 7; +} + +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path() { + return uint64_t(2) << mantissa_explicit_bits(); +} + +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // caller is responsible to ensure that + // power >= 0 && power <= 3 + // + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + +template <> +inline constexpr int binary_format::min_exponent_fast_path() { + return 0; +} + +template <> +inline constexpr int +binary_format::max_exponent_round_to_even() { + return 3; +} + +template <> +inline constexpr int +binary_format::min_exponent_round_to_even() { + return -24; +} + +template <> +inline constexpr int binary_format::minimum_exponent() { + return -127; +} + +template <> +inline constexpr int binary_format::infinite_power() { + return 0xFF; +} + +template <> inline constexpr int binary_format::sign_index() { + return 15; +} + +template <> +inline constexpr int binary_format::largest_power_of_ten() { + return 38; +} + +template <> +inline constexpr int binary_format::smallest_power_of_ten() { + return -60; +} + +template <> +inline constexpr size_t binary_format::max_digits() { + return 98; +} +#endif // __STDCPP_BFLOAT16_T__ + +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // caller is responsible to ensure that + // power >= 0 && power <= 22 + // + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + +template <> +inline constexpr uint64_t +binary_format::max_mantissa_fast_path(int64_t power) { + // caller is responsible to ensure that + // power >= 0 && power <= 10 + // + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)max_mantissa[0], max_mantissa[power]; +} + +template <> +inline constexpr double +binary_format::exact_power_of_ten(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; +} + +template <> +inline constexpr float binary_format::exact_power_of_ten(int64_t power) { + // Work around clang bug https://godbolt.org/z/zedh7rrhc + return (void)powers_of_ten[0], powers_of_ten[power]; +} + +template <> inline constexpr int binary_format::largest_power_of_ten() { + return 308; +} + +template <> inline constexpr int binary_format::largest_power_of_ten() { + return 38; +} + +template <> +inline constexpr int binary_format::smallest_power_of_ten() { + return -342; +} + +template <> inline constexpr int binary_format::smallest_power_of_ten() { + return -64; +} + +template <> inline constexpr size_t binary_format::max_digits() { + return 769; +} + +template <> inline constexpr size_t binary_format::max_digits() { + return 114; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7F800000; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::exponent_mask() { + return 0x7FF0000000000000; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x007FFFFF; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::mantissa_mask() { + return 0x000FFFFFFFFFFFFF; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x00800000; +} + +template <> +inline constexpr binary_format::equiv_uint +binary_format::hidden_bit_mask() { + return 0x0010000000000000; +} + +template +fastfloat_really_inline FASTFLOAT_CONSTEXPR20 void +to_float(bool negative, adjusted_mantissa am, T &value) { + using equiv_uint = equiv_uint_t; + equiv_uint word = equiv_uint(am.mantissa); + word = equiv_uint(word | equiv_uint(am.power2) + << binary_format::mantissa_explicit_bits()); + word = + equiv_uint(word | equiv_uint(negative) << binary_format::sign_index()); +#if FASTFLOAT_HAS_BIT_CAST + value = std::bit_cast(word); +#else + ::memcpy(&value, &word, sizeof(T)); +#endif +} + +template struct space_lut { + static constexpr bool value[] = { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template constexpr bool space_lut::value[]; + +#endif + +template constexpr bool is_space(UC c) { + return c < 256 && space_lut<>::value[uint8_t(c)]; +} + +template static constexpr uint64_t int_cmp_zeros() { + static_assert((sizeof(UC) == 1) || (sizeof(UC) == 2) || (sizeof(UC) == 4), + "Unsupported character size"); + return (sizeof(UC) == 1) ? 0x3030303030303030 + : (sizeof(UC) == 2) + ? (uint64_t(UC('0')) << 48 | uint64_t(UC('0')) << 32 | + uint64_t(UC('0')) << 16 | UC('0')) + : (uint64_t(UC('0')) << 32 | UC('0')); +} + +template static constexpr int int_cmp_len() { + return sizeof(uint64_t) / sizeof(UC); +} + +template constexpr UC const *str_const_nan(); + +template <> constexpr char const *str_const_nan() { return "nan"; } + +template <> constexpr wchar_t const *str_const_nan() { return L"nan"; } + +template <> constexpr char16_t const *str_const_nan() { + return u"nan"; +} + +template <> constexpr char32_t const *str_const_nan() { + return U"nan"; +} + +#ifdef __cpp_char8_t +template <> constexpr char8_t const *str_const_nan() { + return u8"nan"; +} +#endif + +template constexpr UC const *str_const_inf(); + +template <> constexpr char const *str_const_inf() { return "infinity"; } + +template <> constexpr wchar_t const *str_const_inf() { + return L"infinity"; +} + +template <> constexpr char16_t const *str_const_inf() { + return u"infinity"; +} + +template <> constexpr char32_t const *str_const_inf() { + return U"infinity"; +} + +#ifdef __cpp_char8_t +template <> constexpr char8_t const *str_const_inf() { + return u8"infinity"; +} +#endif + +template struct int_luts { + static constexpr uint8_t chdigit[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 255, 255, + 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 255, 255, 255, 255, 255, 255, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, + 33, 34, 35, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255}; + + static constexpr size_t maxdigits_u64[] = { + 64, 41, 32, 28, 25, 23, 22, 21, 20, 19, 18, 18, 17, 17, 16, 16, 16, 16, + 15, 15, 15, 15, 14, 14, 14, 14, 14, 14, 14, 13, 13, 13, 13, 13, 13}; + + static constexpr uint64_t min_safe_u64[] = { + 9223372036854775808ull, 12157665459056928801ull, 4611686018427387904, + 7450580596923828125, 4738381338321616896, 3909821048582988049, + 9223372036854775808ull, 12157665459056928801ull, 10000000000000000000ull, + 5559917313492231481, 2218611106740436992, 8650415919381337933, + 2177953337809371136, 6568408355712890625, 1152921504606846976, + 2862423051509815793, 6746640616477458432, 15181127029874798299ull, + 1638400000000000000, 3243919932521508681, 6221821273427820544, + 11592836324538749809ull, 876488338465357824, 1490116119384765625, + 2481152873203736576, 4052555153018976267, 6502111422497947648, + 10260628712958602189ull, 15943230000000000000ull, 787662783788549761, + 1152921504606846976, 1667889514952984961, 2386420683693101056, + 3379220508056640625, 4738381338321616896}; +}; + +#if FASTFLOAT_DETAIL_MUST_DEFINE_CONSTEXPR_VARIABLE + +template constexpr uint8_t int_luts::chdigit[]; + +template constexpr size_t int_luts::maxdigits_u64[]; + +template constexpr uint64_t int_luts::min_safe_u64[]; + +#endif + +template +fastfloat_really_inline constexpr uint8_t ch_to_digit(UC c) { + return int_luts<>::chdigit[static_cast(c)]; +} + +fastfloat_really_inline constexpr size_t max_digits_u64(int base) { + return int_luts<>::maxdigits_u64[base - 2]; +} + +// If a u64 is exactly max_digits_u64() in length, this is +// the value below which it has definitely overflowed. +fastfloat_really_inline constexpr uint64_t min_safe_u64(int base) { + return int_luts<>::min_safe_u64[base - 2]; +} + +static_assert(std::is_same, uint64_t>::value, + "equiv_uint should be uint64_t for double"); +static_assert(std::numeric_limits::is_iec559, + "double must fulfill the requirements of IEC 559 (IEEE 754)"); + +static_assert(std::is_same, uint32_t>::value, + "equiv_uint should be uint32_t for float"); +static_assert(std::numeric_limits::is_iec559, + "float must fulfill the requirements of IEC 559 (IEEE 754)"); + +#ifdef __STDCPP_FLOAT64_T__ +static_assert(std::is_same, uint64_t>::value, + "equiv_uint should be uint64_t for std::float64_t"); +static_assert( + std::numeric_limits::is_iec559, + "std::float64_t must fulfill the requirements of IEC 559 (IEEE 754)"); +#endif // __STDCPP_FLOAT64_T__ + +#ifdef __STDCPP_FLOAT32_T__ +static_assert(std::is_same, uint32_t>::value, + "equiv_uint should be uint32_t for std::float32_t"); +static_assert( + std::numeric_limits::is_iec559, + "std::float32_t must fulfill the requirements of IEC 559 (IEEE 754)"); +#endif // __STDCPP_FLOAT32_T__ + +#ifdef __STDCPP_FLOAT16_T__ +static_assert( + std::is_same::equiv_uint, uint16_t>::value, + "equiv_uint should be uint16_t for std::float16_t"); +static_assert( + std::numeric_limits::is_iec559, + "std::float16_t must fulfill the requirements of IEC 559 (IEEE 754)"); +#endif // __STDCPP_FLOAT16_T__ + +#ifdef __STDCPP_BFLOAT16_T__ +static_assert( + std::is_same::equiv_uint, uint16_t>::value, + "equiv_uint should be uint16_t for std::bfloat16_t"); +static_assert( + std::numeric_limits::is_iec559, + "std::bfloat16_t must fulfill the requirements of IEC 559 (IEEE 754)"); +#endif // __STDCPP_BFLOAT16_T__ + +constexpr chars_format operator~(chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(~static_cast(rhs)); +} + +constexpr chars_format operator&(chars_format lhs, chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(static_cast(lhs) & + static_cast(rhs)); +} + +constexpr chars_format operator|(chars_format lhs, chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(static_cast(lhs) | + static_cast(rhs)); +} + +constexpr chars_format operator^(chars_format lhs, chars_format rhs) noexcept { + using int_type = std::underlying_type::type; + return static_cast(static_cast(lhs) ^ + static_cast(rhs)); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & +operator&=(chars_format &lhs, chars_format rhs) noexcept { + return lhs = (lhs & rhs); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & +operator|=(chars_format &lhs, chars_format rhs) noexcept { + return lhs = (lhs | rhs); +} + +fastfloat_really_inline FASTFLOAT_CONSTEXPR14 chars_format & +operator^=(chars_format &lhs, chars_format rhs) noexcept { + return lhs = (lhs ^ rhs); +} + +namespace detail { +// adjust for deprecated feature macros +constexpr chars_format adjust_for_feature_macros(chars_format fmt) { + return fmt +#ifdef FASTFLOAT_ALLOWS_LEADING_PLUS + | chars_format::allow_leading_plus +#endif +#ifdef FASTFLOAT_SKIP_WHITE_SPACE + | chars_format::skip_white_space +#endif + ; +} +} // namespace detail + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/include/fast_float/parse_number.h b/vnext/external/fast-float/include/fast_float/parse_number.h new file mode 100644 index 00000000000..0dbb3a143a2 --- /dev/null +++ b/vnext/external/fast-float/include/fast_float/parse_number.h @@ -0,0 +1,399 @@ +#ifndef FASTFLOAT_PARSE_NUMBER_H +#define FASTFLOAT_PARSE_NUMBER_H + +#include "ascii_number.h" +#include "decimal_to_binary.h" +#include "digit_comparison.h" +#include "float_common.h" + +#include +#include +#include +#include + +namespace fast_float { + +namespace detail { +/** + * Special case +inf, -inf, nan, infinity, -infinity. + * The case comparisons could be made much faster given that we know that the + * strings a null-free and fixed. + **/ +template +from_chars_result_t + FASTFLOAT_CONSTEXPR14 parse_infnan(UC const *first, UC const *last, + T &value, chars_format fmt) noexcept { + from_chars_result_t answer{}; + answer.ptr = first; + answer.ec = std::errc(); // be optimistic + // assume first < last, so dereference without checks; + bool const minusSign = (*first == UC('-')); + // C++17 20.19.3.(7.1) explicitly forbids '+' sign here + if ((*first == UC('-')) || + (uint64_t(fmt & chars_format::allow_leading_plus) && + (*first == UC('+')))) { + ++first; + } + if (last - first >= 3) { + if (fastfloat_strncasecmp(first, str_const_nan(), 3)) { + answer.ptr = (first += 3); + value = minusSign ? -std::numeric_limits::quiet_NaN() + : std::numeric_limits::quiet_NaN(); + // Check for possible nan(n-char-seq-opt), C++17 20.19.3.7, + // C11 7.20.1.3.3. At least MSVC produces nan(ind) and nan(snan). + if (first != last && *first == UC('(')) { + for (UC const *ptr = first + 1; ptr != last; ++ptr) { + if (*ptr == UC(')')) { + answer.ptr = ptr + 1; // valid nan(n-char-seq-opt) + break; + } else if (!((UC('a') <= *ptr && *ptr <= UC('z')) || + (UC('A') <= *ptr && *ptr <= UC('Z')) || + (UC('0') <= *ptr && *ptr <= UC('9')) || *ptr == UC('_'))) + break; // forbidden char, not nan(n-char-seq-opt) + } + } + return answer; + } + if (fastfloat_strncasecmp(first, str_const_inf(), 3)) { + if ((last - first >= 8) && + fastfloat_strncasecmp(first + 3, str_const_inf() + 3, 5)) { + answer.ptr = first + 8; + } else { + answer.ptr = first + 3; + } + value = minusSign ? -std::numeric_limits::infinity() + : std::numeric_limits::infinity(); + return answer; + } + } + answer.ec = std::errc::invalid_argument; + return answer; +} + +/** + * Returns true if the floating-pointing rounding mode is to 'nearest'. + * It is the default on most system. This function is meant to be inexpensive. + * Credit : @mwalcott3 + */ +fastfloat_really_inline bool rounds_to_nearest() noexcept { + // https://lemire.me/blog/2020/06/26/gcc-not-nearest/ +#if (FLT_EVAL_METHOD != 1) && (FLT_EVAL_METHOD != 0) + return false; +#endif + // See + // A fast function to check your floating-point rounding mode + // https://lemire.me/blog/2022/11/16/a-fast-function-to-check-your-floating-point-rounding-mode/ + // + // This function is meant to be equivalent to : + // prior: #include + // return fegetround() == FE_TONEAREST; + // However, it is expected to be much faster than the fegetround() + // function call. + // + // The volatile keyword prevents the compiler from computing the function + // at compile-time. + // There might be other ways to prevent compile-time optimizations (e.g., + // asm). The value does not need to be std::numeric_limits::min(), any + // small value so that 1 + x should round to 1 would do (after accounting for + // excess precision, as in 387 instructions). + static float volatile fmin = std::numeric_limits::min(); + float fmini = fmin; // we copy it so that it gets loaded at most once. +// +// Explanation: +// Only when fegetround() == FE_TONEAREST do we have that +// fmin + 1.0f == 1.0f - fmin. +// +// FE_UPWARD: +// fmin + 1.0f > 1 +// 1.0f - fmin == 1 +// +// FE_DOWNWARD or FE_TOWARDZERO: +// fmin + 1.0f == 1 +// 1.0f - fmin < 1 +// +// Note: This may fail to be accurate if fast-math has been +// enabled, as rounding conventions may not apply. +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(push) +// todo: is there a VS warning? +// see +// https://stackoverflow.com/questions/46079446/is-there-a-warning-for-floating-point-equality-checking-in-visual-studio-2013 +#elif defined(__clang__) +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wfloat-equal" +#elif defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wfloat-equal" +#endif + return (fmini + 1.0f == 1.0f - fmini); +#ifdef FASTFLOAT_VISUAL_STUDIO +#pragma warning(pop) +#elif defined(__clang__) +#pragma clang diagnostic pop +#elif defined(__GNUC__) +#pragma GCC diagnostic pop +#endif +} + +} // namespace detail + +template struct from_chars_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_advanced(first, last, value, options); + } +}; + +#ifdef __STDCPP_FLOAT32_T__ +template <> struct from_chars_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, std::float32_t &value, + parse_options_t options) noexcept { + // if std::float32_t is defined, and we are in C++23 mode; macro set for + // float32; set value to float due to equivalence between float and + // float32_t + float val; + auto ret = from_chars_advanced(first, last, val, options); + value = val; + return ret; + } +}; +#endif + +#ifdef __STDCPP_FLOAT64_T__ +template <> struct from_chars_caller { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, std::float64_t &value, + parse_options_t options) noexcept { + // if std::float64_t is defined, and we are in C++23 mode; macro set for + // float64; set value as double due to equivalence between double and + // float64_t + double val; + auto ret = from_chars_advanced(first, last, val, options); + value = val; + return ret; + } +}; +#endif + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, + chars_format fmt /*= chars_format::general*/) noexcept { + return from_chars_caller::call(first, last, value, + parse_options_t(fmt)); +} + +/** + * This function overload takes parsed_number_string_t structure that is created + * and populated either by from_chars_advanced function taking chars range and + * parsing options or other parsing custom function implemented by user. + */ +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(parsed_number_string_t &pns, T &value) noexcept { + + static_assert(is_supported_float_type::value, + "only some floating-point types are supported"); + static_assert(is_supported_char_type::value, + "only char, wchar_t, char16_t and char32_t are supported"); + + from_chars_result_t answer; + + answer.ec = std::errc(); // be optimistic + answer.ptr = pns.lastmatch; + // The implementation of the Clinger's fast path is convoluted because + // we want round-to-nearest in all cases, irrespective of the rounding mode + // selected on the thread. + // We proceed optimistically, assuming that detail::rounds_to_nearest() + // returns true. + if (binary_format::min_exponent_fast_path() <= pns.exponent && + pns.exponent <= binary_format::max_exponent_fast_path() && + !pns.too_many_digits) { + // Unfortunately, the conventional Clinger's fast path is only possible + // when the system rounds to the nearest float. + // + // We expect the next branch to almost always be selected. + // We could check it first (before the previous branch), but + // there might be performance advantages at having the check + // be last. + if (!cpp20_and_in_constexpr() && detail::rounds_to_nearest()) { + // We have that fegetround() == FE_TONEAREST. + // Next is Clinger's fast path. + if (pns.mantissa <= binary_format::max_mantissa_fast_path()) { + value = T(pns.mantissa); + if (pns.exponent < 0) { + value = value / binary_format::exact_power_of_ten(-pns.exponent); + } else { + value = value * binary_format::exact_power_of_ten(pns.exponent); + } + if (pns.negative) { + value = -value; + } + return answer; + } + } else { + // We do not have that fegetround() == FE_TONEAREST. + // Next is a modified Clinger's fast path, inspired by Jakub Jelínek's + // proposal + if (pns.exponent >= 0 && + pns.mantissa <= + binary_format::max_mantissa_fast_path(pns.exponent)) { +#if defined(__clang__) || defined(FASTFLOAT_32BIT) + // Clang may map 0 to -0.0 when fegetround() == FE_DOWNWARD + if (pns.mantissa == 0) { + value = pns.negative ? T(-0.) : T(0.); + return answer; + } +#endif + value = T(pns.mantissa) * + binary_format::exact_power_of_ten(pns.exponent); + if (pns.negative) { + value = -value; + } + return answer; + } + } + } + adjusted_mantissa am = + compute_float>(pns.exponent, pns.mantissa); + if (pns.too_many_digits && am.power2 >= 0) { + if (am != compute_float>(pns.exponent, pns.mantissa + 1)) { + am = compute_error>(pns.exponent, pns.mantissa); + } + } + // If we called compute_float>(pns.exponent, pns.mantissa) + // and we have an invalid power (am.power2 < 0), then we need to go the long + // way around again. This is very uncommon. + if (am.power2 < 0) { + am = digit_comp(pns, am); + } + to_float(pns.negative, am, value); + // Test for over/underflow. + if ((pns.mantissa != 0 && am.mantissa == 0 && am.power2 == 0) || + am.power2 == binary_format::infinite_power()) { + answer.ec = std::errc::result_out_of_range; + } + return answer; +} + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_float_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + + static_assert(is_supported_float_type::value, + "only some floating-point types are supported"); + static_assert(is_supported_char_type::value, + "only char, wchar_t, char16_t and char32_t are supported"); + + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + + from_chars_result_t answer; + if (uint64_t(fmt & chars_format::skip_white_space)) { + while ((first != last) && fast_float::is_space(*first)) { + first++; + } + } + if (first == last) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + parsed_number_string_t pns = + parse_number_string(first, last, options); + if (!pns.valid) { + if (uint64_t(fmt & chars_format::no_infnan)) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } else { + return detail::parse_infnan(first, last, value, fmt); + } + } + + // call overload that takes parsed_number_string_t directly. + return from_chars_advanced(pns, value); +} + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars(UC const *first, UC const *last, T &value, int base) noexcept { + + static_assert(is_supported_integer_type::value, + "only integer types are supported"); + static_assert(is_supported_char_type::value, + "only char, wchar_t, char16_t and char32_t are supported"); + + parse_options_t options; + options.base = base; + return from_chars_advanced(first, last, value, options); +} + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_int_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + + static_assert(is_supported_integer_type::value, + "only integer types are supported"); + static_assert(is_supported_char_type::value, + "only char, wchar_t, char16_t and char32_t are supported"); + + chars_format const fmt = detail::adjust_for_feature_macros(options.format); + int const base = options.base; + + from_chars_result_t answer; + if (uint64_t(fmt & chars_format::skip_white_space)) { + while ((first != last) && fast_float::is_space(*first)) { + first++; + } + } + if (first == last || base < 2 || base > 36) { + answer.ec = std::errc::invalid_argument; + answer.ptr = first; + return answer; + } + + return parse_int_string(first, last, value, options); +} + +template struct from_chars_advanced_caller { + static_assert(TypeIx > 0, "unsupported type"); +}; + +template <> struct from_chars_advanced_caller<1> { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_float_advanced(first, last, value, options); + } +}; + +template <> struct from_chars_advanced_caller<2> { + template + FASTFLOAT_CONSTEXPR20 static from_chars_result_t + call(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_int_advanced(first, last, value, options); + } +}; + +template +FASTFLOAT_CONSTEXPR20 from_chars_result_t +from_chars_advanced(UC const *first, UC const *last, T &value, + parse_options_t options) noexcept { + return from_chars_advanced_caller< + size_t(is_supported_float_type::value) + + 2 * size_t(is_supported_integer_type::value)>::call(first, last, value, + options); +} + +} // namespace fast_float + +#endif diff --git a/vnext/external/fast-float/sync-config.json b/vnext/external/fast-float/sync-config.json new file mode 100644 index 00000000000..3d59b4b87f0 --- /dev/null +++ b/vnext/external/fast-float/sync-config.json @@ -0,0 +1,8 @@ +{ + "repo": "https://github.com/fastfloat/fast_float", + "branch": "main", + "commit": "77cc847c842c49e7e3477c1e95da2b6540166d66", + "subDir": "", + "tag": "v8.0.0", + "lastSync": "" +} diff --git a/vnext/external/folly/.syncignore b/vnext/external/folly/.syncignore new file mode 100644 index 00000000000..b284125ace6 --- /dev/null +++ b/vnext/external/folly/.syncignore @@ -0,0 +1,62 @@ +/sync-config.json +/.syncignore +/sync-instructions.md +/cgmanifest.json +/folly.vcxitems +/Folly.natvis +/folly/.clang-format + +# Top-level build/CI/meta files +/CMakeLists.txt +/CMakeListsForBuck2.txt +/CMake/ +/build/ +/shim/ +/static/ +/BUCK +/PACKAGE +/buck2 +/build.bat +/build.sh +/CODE_OF_CONDUCT.md +/CONTRIBUTING.md +/LICENSE +/README.md + +# folly/ subdirectories not used by RNW +/folly/algorithm/* +!/folly/algorithm/simd/ +/folly/algorithm/simd/test/ +/folly/algorithm/simd/detail/test/ +/folly/buck_config/ +/folly/build/ +/folly/channels/ +/folly/cli/ +/folly/compression/ +/folly/coro/ +/folly/crypto/ +/folly/debugging/ +/folly/docs/ +/folly/executors/ +/folly/experimental/ +/folly/ext/ +/folly/external/ +/folly/fibers/ +/folly/futures/ +/folly/gen/ +/folly/init/ +/folly/io/ +/folly/logging/ +/folly/net/ +/folly/observer/ +/folly/poly/ +/folly/python/ +/folly/settings/ +/folly/ssl/ +/folly/static/ +/folly/stats/ +/folly/support/ +/folly/test/ +/folly/testing/ +/folly/tool/ +/folly/tracing/ diff --git a/vnext/Folly/Folly.natvis b/vnext/external/folly/Folly.natvis similarity index 100% rename from vnext/Folly/Folly.natvis rename to vnext/external/folly/Folly.natvis diff --git a/vnext/Folly/cgmanifest.json b/vnext/external/folly/cgmanifest.json similarity index 100% rename from vnext/Folly/cgmanifest.json rename to vnext/external/folly/cgmanifest.json diff --git a/vnext/external/folly/folly.vcxitems b/vnext/external/folly/folly.vcxitems new file mode 100644 index 00000000000..188ec44b1e7 --- /dev/null +++ b/vnext/external/folly/folly.vcxitems @@ -0,0 +1,156 @@ + + + + + Create + pch.h + $(IntDir)folly.pch + $(IntDir)folly_pch.obj + false + FOLLY_CFG_NO_COROUTINES;FOLLY_NO_CONFIG;NOMINMAX;_CRT_SECURE_NO_WARNINGS;WINAPI_PARTITION_APP;%(PreprocessorDefinitions) + 4251;4293;4305;4800;4804;4310;%(DisableSpecificWarnings) + /Zc:__cplusplus %(AdditionalOptions) + $(ReactNativeWindowsDir)Folly;$(ReactNativeWindowsDir)stubs;$(ExternalDir)folly;$(ExternalDir)fast-float\include;$(ExternalDir)fmt\include;%(AdditionalIncludeDirectories) + + + + + + + + + + + + + + + + $(IntDir)folly_Format.obj + + + + + + $(IntDir)\portabilityString.obj + + + + + + + + + + + + + + + NotUsing + _HAS_AUTO_PTR_ETC=1;FOLLY_CFG_NO_COROUTINES;FOLLY_NO_CONFIG;NOMINMAX;WIN32;%(PreprocessorDefinitions) + $(ExternalDir)folly;%(AdditionalIncludeDirectories) + 4293;%(DisableSpecificWarnings) + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Use + pch.h + $(IntDir)folly.pch + false + FOLLY_CFG_NO_COROUTINES;FOLLY_NO_CONFIG;NOMINMAX;_CRT_SECURE_NO_WARNINGS;WINAPI_PARTITION_APP;%(PreprocessorDefinitions) + 4251;4293;4305;4800;4804;4310;%(DisableSpecificWarnings) + /Zc:__cplusplus %(AdditionalOptions) + pch.h + $(ReactNativeWindowsDir)Folly;$(ReactNativeWindowsDir)stubs;$(ExternalDir)folly;$(ExternalDir)fast-float\include;$(ExternalDir)fmt\include;%(AdditionalIncludeDirectories) + + + diff --git a/vnext/Folly/.clang-format b/vnext/external/folly/folly/.clang-format similarity index 51% rename from vnext/Folly/.clang-format rename to vnext/external/folly/folly/.clang-format index a43d914ec38..e3845288a2a 100644 --- a/vnext/Folly/.clang-format +++ b/vnext/external/folly/folly/.clang-format @@ -1,2 +1 @@ DisableFormat: true -SortIncludes: false \ No newline at end of file diff --git a/vnext/external/folly/folly/AtomicHashArray-inl.h b/vnext/external/folly/folly/AtomicHashArray-inl.h new file mode 100644 index 00000000000..8b3f743215c --- /dev/null +++ b/vnext/external/folly/folly/AtomicHashArray-inl.h @@ -0,0 +1,546 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FOLLY_ATOMICHASHARRAY_H_ +#error "This should only be included by AtomicHashArray.h" +#endif + +#include + +#include +#include +#include +#include + +namespace folly { + +// AtomicHashArray private constructor -- +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>:: + AtomicHashArray( + size_t capacity, + KeyT emptyKey, + KeyT lockedKey, + KeyT erasedKey, + double _maxLoadFactor, + uint32_t cacheSize) + : capacity_(capacity), + maxEntries_(size_t(_maxLoadFactor * capacity_ + 0.5)), + kEmptyKey_(emptyKey), + kLockedKey_(lockedKey), + kErasedKey_(erasedKey), + kAnchorMask_(nextPowTwo(capacity_) - 1), + numEntries_(0, cacheSize), + numPendingEntries_(0, cacheSize), + isFull_(0), + numErases_(0) { + if (capacity == 0) { + throw_exception("capacity"); + } +} + +/* + * findInternal -- + * + * Sets ret.second to value found and ret.index to index + * of key and returns true, or if key does not exist returns false and + * ret.index is set to capacity_. + */ +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +template +typename AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::SimpleRetT +AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::findInternal(const LookupKeyT key_in) { + checkLegalKeyIfKey(key_in); + + for (size_t idx = keyToAnchorIdx(key_in), + numProbes = 0; + ; + idx = ProbeFcn()(idx, numProbes, capacity_)) { + const KeyT key = acquireLoadKey(cells_[idx]); + if (FOLLY_LIKELY(LookupEqualFcn()(key, key_in))) { + return SimpleRetT(idx, true); + } + if (FOLLY_UNLIKELY(key == kEmptyKey_)) { + // if we hit an empty element, this key does not exist + return SimpleRetT(capacity_, false); + } + // NOTE: the way we count numProbes must be same in find(), insert(), + // and erase(). Otherwise it may break probing. + ++numProbes; + if (FOLLY_UNLIKELY(numProbes >= capacity_)) { + // probed every cell...fail + return SimpleRetT(capacity_, false); + } + } +} + +/* + * insertInternal -- + * + * Returns false on failure due to key collision or full. + * Also sets ret.index to the index of the key. If the map is full, sets + * ret.index = capacity_. Also sets ret.second to cell value, thus if insert + * successful this will be what we just inserted, if there is a key collision + * this will be the previously inserted value, and if the map is full it is + * default. + */ +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +template < + typename LookupKeyT, + typename LookupHashFcn, + typename LookupEqualFcn, + typename LookupKeyToKeyFcn, + typename... ArgTs> +typename AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::SimpleRetT +AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::insertInternal(LookupKeyT key_in, ArgTs&&... vCtorArgs) { + const short NO_NEW_INSERTS = 1; + const short NO_PENDING_INSERTS = 2; + checkLegalKeyIfKey(key_in); + + size_t idx = keyToAnchorIdx(key_in); + size_t numProbes = 0; + for (;;) { + DCHECK_LT(idx, capacity_); + value_type* cell = &cells_[idx]; + if (relaxedLoadKey(*cell) == kEmptyKey_) { + // NOTE: isFull_ is set based on numEntries_.readFast(), so it's + // possible to insert more than maxEntries_ entries. However, it's not + // possible to insert past capacity_. + ++numPendingEntries_; + if (isFull_.load(std::memory_order_acquire)) { + --numPendingEntries_; + + // Before deciding whether this insert succeeded, this thread needs to + // wait until no other thread can add a new entry. + + // Correctness assumes isFull_ is true at this point. If + // another thread now does ++numPendingEntries_, we expect it + // to pass the isFull_.load() test above. (It shouldn't insert + // a new entry.) + detail::atomic_hash_spin_wait([&] { + return (isFull_.load(std::memory_order_acquire) != + NO_PENDING_INSERTS) && + (numPendingEntries_.readFull() != 0); + }); + isFull_.store(NO_PENDING_INSERTS, std::memory_order_release); + + if (relaxedLoadKey(*cell) == kEmptyKey_) { + // Don't insert past max load factor + return SimpleRetT(capacity_, false); + } + } else { + // An unallocated cell. Try once to lock it. If we succeed, insert here. + // If we fail, fall through to comparison below; maybe the insert that + // just beat us was for this very key.... + if (tryLockCell(cell)) { + KeyT key_new; + // Write the value - done before unlocking + try { + key_new = LookupKeyToKeyFcn()(key_in); + typedef + typename std::remove_const::type LookupKeyTNoConst; + constexpr bool kAlreadyChecked = + std::is_same::value; + if (!kAlreadyChecked) { + checkLegalKeyIfKey(key_new); + } + DCHECK(relaxedLoadKey(*cell) == kLockedKey_); + // A const mapped_type is only constant once constructed, so cast + // away any const for the placement new here. + using mapped = typename std::remove_const::type; + new (const_cast(&cell->second)) + ValueT(std::forward(vCtorArgs)...); + unlockCell(cell, key_new); // Sets the new key + } catch (...) { + // Transition back to empty key---requires handling + // locked->empty below. + unlockCell(cell, kEmptyKey_); + --numPendingEntries_; + throw; + } + // An erase() can race here and delete right after our insertion + // Direct comparison rather than EqualFcn ok here + // (we just inserted it) + DCHECK( + relaxedLoadKey(*cell) == key_new || + relaxedLoadKey(*cell) == kErasedKey_); + --numPendingEntries_; + ++numEntries_; // This is a thread cached atomic increment :) + if (numEntries_.readFast() >= maxEntries_) { + isFull_.store(NO_NEW_INSERTS, std::memory_order_relaxed); + } + return SimpleRetT(idx, true); + } + --numPendingEntries_; + } + } + DCHECK(relaxedLoadKey(*cell) != kEmptyKey_); + if (kLockedKey_ == acquireLoadKey(*cell)) { + detail::atomic_hash_spin_wait( + [&] { return kLockedKey_ == acquireLoadKey(*cell); }); + } + + const KeyT thisKey = acquireLoadKey(*cell); + if (LookupEqualFcn()(thisKey, key_in)) { + // Found an existing entry for our key, but we don't overwrite the + // previous value. + return SimpleRetT(idx, false); + } else if (thisKey == kEmptyKey_ || thisKey == kLockedKey_) { + // We need to try again (i.e., don't increment numProbes or + // advance idx): this case can happen if the constructor for + // ValueT threw for this very cell (the rethrow block above). + continue; + } + + // NOTE: the way we count numProbes must be same in find(), + // insert(), and erase(). Otherwise it may break probing. + ++numProbes; + if (FOLLY_UNLIKELY(numProbes >= capacity_)) { + // probed every cell...fail + return SimpleRetT(capacity_, false); + } + + idx = ProbeFcn()(idx, numProbes, capacity_); + } +} + +/* + * erase -- + * + * This will attempt to erase the given key key_in if the key is found. It + * returns 1 iff the key was located and marked as erased, and 0 otherwise. + * + * Memory is not freed or reclaimed by erase, i.e. the cell containing the + * erased key will never be reused. If there's an associated value, we won't + * touch it either. + */ +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +size_t AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::erase(KeyT key_in) { + CHECK_NE(key_in, kEmptyKey_); + CHECK_NE(key_in, kLockedKey_); + CHECK_NE(key_in, kErasedKey_); + + for (size_t idx = keyToAnchorIdx(key_in), numProbes = 0;; + idx = ProbeFcn()(idx, numProbes, capacity_)) { + DCHECK_LT(idx, capacity_); + value_type* cell = &cells_[idx]; + KeyT currentKey = acquireLoadKey(*cell); + if (currentKey == kEmptyKey_ || currentKey == kLockedKey_) { + // If we hit an empty (or locked) element, this key does not exist. This + // is similar to how it's handled in find(). + return 0; + } + if (EqualFcn()(currentKey, key_in)) { + // Found an existing entry for our key, attempt to mark it erased. + // Some other thread may have erased our key, but this is ok. + KeyT expect = currentKey; + if (cellKeyPtr(*cell)->compare_exchange_strong(expect, kErasedKey_)) { + numErases_.fetch_add(1, std::memory_order_relaxed); + + // Even if there's a value in the cell, we won't delete (or even + // default construct) it because some other thread may be accessing it. + // Locking it meanwhile won't work either since another thread may be + // holding a pointer to it. + + // We found the key and successfully erased it. + return 1; + } + // If another thread succeeds in erasing our key, we'll stop our search. + return 0; + } + + // NOTE: the way we count numProbes must be same in find(), insert(), + // and erase(). Otherwise it may break probing. + ++numProbes; + if (FOLLY_UNLIKELY(numProbes >= capacity_)) { + // probed every cell...fail + return 0; + } + } +} + +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +typename AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::SmartPtr +AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::create(size_t maxSize, const Config& c) { + CHECK_LE(c.maxLoadFactor, 1.0); + CHECK_GT(c.maxLoadFactor, 0.0); + CHECK_NE(c.emptyKey, c.lockedKey); + size_t capacity = size_t(maxSize / c.maxLoadFactor); + size_t sz = sizeof(AtomicHashArray) + sizeof(value_type) * capacity; + + auto const mem = Allocator().allocate(sz); + try { + new (mem) AtomicHashArray( + capacity, + c.emptyKey, + c.lockedKey, + c.erasedKey, + c.maxLoadFactor, + c.entryCountThreadCacheSize); + } catch (...) { + Allocator().deallocate(mem, sz); + throw; + } + + SmartPtr map(static_cast((void*)mem)); + + /* + * Mark all cells as empty. + * + * Note: we're bending the rules a little here accessing the key + * element in our cells even though the cell object has not been + * constructed, and casting them to atomic objects (see cellKeyPtr). + * (Also, in fact we never actually invoke the value_type + * constructor.) This is in order to avoid needing to default + * construct a bunch of value_type when we first start up: if you + * have an expensive default constructor for the value type this can + * noticeably speed construction time for an AHA. + */ + FOR_EACH_RANGE (i, 0, map->capacity_) { + cellKeyPtr(map->cells_[i]) + ->store(map->kEmptyKey_, std::memory_order_relaxed); + } + return map; +} + +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +void AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::destroy(AtomicHashArray* p) { + assert(p); + + size_t sz = sizeof(AtomicHashArray) + sizeof(value_type) * p->capacity_; + + FOR_EACH_RANGE (i, 0, p->capacity_) { + if (p->cells_[i].first != p->kEmptyKey_) { + p->cells_[i].~value_type(); + } + } + p->~AtomicHashArray(); + + Allocator().deallocate((char*)p, sz); +} + +// clear -- clears all keys and values in the map and resets all counters +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +void AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::clear() { + FOR_EACH_RANGE (i, 0, capacity_) { + if (cells_[i].first != kEmptyKey_) { + cells_[i].~value_type(); + *const_cast(&cells_[i].first) = kEmptyKey_; + } + CHECK(cells_[i].first == kEmptyKey_); + } + numEntries_.set(0); + numPendingEntries_.set(0); + isFull_.store(0, std::memory_order_relaxed); + numErases_.store(0, std::memory_order_relaxed); +} + +// Iterator implementation + +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +template +struct AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::aha_iterator + : detail::IteratorFacade< + aha_iterator, + IterVal, + std::forward_iterator_tag> { + explicit aha_iterator() : aha_(nullptr) {} + + // Conversion ctor for interoperability between const_iterator and + // iterator. The enable_if<> magic keeps us well-behaved for + // is_convertible<> (v. the iterator_facade documentation). + template + aha_iterator( + const aha_iterator& o, + typename std::enable_if< + std::is_convertible::value>::type* = nullptr) + : aha_(o.aha_), offset_(o.offset_) {} + + explicit aha_iterator(ContT* array, size_t offset) + : aha_(array), offset_(offset) {} + + // Returns unique index that can be used with findAt(). + // WARNING: The following function will fail silently for hashtable + // with capacity > 2^32 + uint32_t getIndex() const { return offset_; } + + void advancePastEmpty() { + while (offset_ < aha_->capacity_ && !isValid()) { + ++offset_; + } + } + + private: + friend class AtomicHashArray; + friend class detail:: + IteratorFacade; + + void increment() { + ++offset_; + advancePastEmpty(); + } + + bool equal(const aha_iterator& o) const { + return aha_ == o.aha_ && offset_ == o.offset_; + } + + IterVal& dereference() const { return aha_->cells_[offset_]; } + + bool isValid() const { + KeyT key = acquireLoadKey(aha_->cells_[offset_]); + return key != aha_->kEmptyKey_ && key != aha_->kLockedKey_ && + key != aha_->kErasedKey_; + } + + private: + ContT* aha_; + size_t offset_; +}; // aha_iterator + +} // namespace folly diff --git a/vnext/external/folly/folly/AtomicHashArray.h b/vnext/external/folly/folly/AtomicHashArray.h new file mode 100644 index 00000000000..a0c3b2b3338 --- /dev/null +++ b/vnext/external/folly/folly/AtomicHashArray.h @@ -0,0 +1,431 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * AtomicHashArray is the building block for AtomicHashMap. It provides the + * core lock-free functionality, but is limited by the fact that it cannot + * grow past its initialization size and is a little more awkward (no public + * constructor, for example). If you're confident that you won't run out of + * space, don't mind the awkardness, and really need bare-metal performance, + * feel free to use AHA directly. + * + * Check out AtomicHashMap.h for more thorough documentation on perf and + * general pros and cons relative to other hash maps. + * + */ + +#pragma once +#define FOLLY_ATOMICHASHARRAY_H_ + +#include + +#include +#include +#include + +namespace folly { + +struct AtomicHashArrayLinearProbeFcn { + inline size_t operator()( + size_t idx, size_t /* numProbes */, size_t capacity) const { + idx += 1; // linear probing + + // Avoid modulus because it's slow + return FOLLY_LIKELY(idx < capacity) ? idx : (idx - capacity); + } +}; + +struct AtomicHashArrayQuadraticProbeFcn { + inline size_t operator()( + size_t idx, size_t numProbes, size_t capacity) const { + idx += numProbes; // quadratic probing + + // Avoid modulus because it's slow + return FOLLY_LIKELY(idx < capacity) ? idx : (idx - capacity); + } +}; + +// Enables specializing checkLegalKey without specializing its class. +namespace detail { +template +inline void checkLegalKeyIfKeyTImpl( + NotKeyT /* ignored */, + KeyT /* emptyKey */, + KeyT /* lockedKey */, + KeyT /* erasedKey */) {} + +template +inline void checkLegalKeyIfKeyTImpl( + KeyT key_in, KeyT emptyKey, KeyT lockedKey, KeyT erasedKey) { + DCHECK_NE(key_in, emptyKey); + DCHECK_NE(key_in, lockedKey); + DCHECK_NE(key_in, erasedKey); +} +} // namespace detail + +template < + class KeyT, + class ValueT, + class HashFcn = std::hash, + class EqualFcn = std::equal_to, + class Allocator = std::allocator, + class ProbeFcn = AtomicHashArrayLinearProbeFcn, + class KeyConvertFcn = Identity> +class AtomicHashMap; + +template < + class KeyT, + class ValueT, + class HashFcn = std::hash, + class EqualFcn = std::equal_to, + class Allocator = std::allocator, + class ProbeFcn = AtomicHashArrayLinearProbeFcn, + class KeyConvertFcn = Identity> +class AtomicHashArray { + static_assert( + (std::is_convertible::value || + std::is_convertible::value || + std::is_convertible::value), + "You are trying to use AtomicHashArray with disallowed key " + "types. You must use atomically compare-and-swappable integer " + "keys, or a different container class."); + + public: + typedef KeyT key_type; + typedef ValueT mapped_type; + typedef HashFcn hasher; + typedef EqualFcn key_equal; + typedef KeyConvertFcn key_convert; + typedef std::pair value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef value_type* pointer; + typedef const value_type* const_pointer; + + const size_t capacity_; + const size_t maxEntries_; + const KeyT kEmptyKey_; + const KeyT kLockedKey_; + const KeyT kErasedKey_; + + template + struct aha_iterator; + + typedef aha_iterator const_iterator; + typedef aha_iterator iterator; + + // You really shouldn't need this if you use the SmartPtr provided by create, + // but if you really want to do something crazy like stick the released + // pointer into a DescriminatedPtr or something, you'll need this to clean up + // after yourself. + static void destroy(AtomicHashArray*); + + private: + const size_t kAnchorMask_; + + struct Deleter { + void operator()(AtomicHashArray* ptr) { AtomicHashArray::destroy(ptr); } + }; + + public: + typedef std::unique_ptr SmartPtr; + + /* + * create -- + * + * Creates AtomicHashArray objects. Use instead of constructor/destructor. + * + * We do things this way in order to avoid the perf penalty of a second + * pointer indirection when composing these into AtomicHashMap, which needs + * to store an array of pointers so that it can perform atomic operations on + * them when growing. + * + * Instead of a mess of arguments, we take a max size and a Config struct to + * simulate named ctor parameters. The Config struct has sensible defaults + * for everything, but is overloaded - if you specify a positive capacity, + * that will be used directly instead of computing it based on + * maxLoadFactor. + * + * Create returns an AHA::SmartPtr which is a unique_ptr with a custom + * deleter to make sure everything is cleaned up properly. + */ + struct Config { + KeyT emptyKey; + KeyT lockedKey; + KeyT erasedKey; + double maxLoadFactor; + double growthFactor; + uint32_t entryCountThreadCacheSize; + size_t capacity; // if positive, overrides maxLoadFactor + + // Cannot have constexpr ctor because some compilers rightly complain. + Config() + : emptyKey((KeyT)-1), + lockedKey((KeyT)-2), + erasedKey((KeyT)-3), + maxLoadFactor(0.8), + growthFactor(-1), + entryCountThreadCacheSize(1000), + capacity(0) {} + }; + + // Cannot have pre-instantiated const Config instance because of SIOF. + static SmartPtr create(size_t maxSize, const Config& c = Config()); + + /* + * find -- + * + * + * Returns the iterator to the element if found, otherwise end(). + * + * As an optional feature, the type of the key to look up (LookupKeyT) is + * allowed to be different from the type of keys actually stored (KeyT). + * + * This enables use cases where materializing the key is costly and usually + * redundant, e.g., canonicalizing/interning a set of strings and being able + * to look up by StringPiece. To use this feature, LookupHashFcn must take + * a LookupKeyT, and LookupEqualFcn must take KeyT and LookupKeyT as first + * and second parameter, respectively. + * + * See folly/test/ArrayHashArrayTest.cpp for sample usage. + */ + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal> + iterator find(LookupKeyT k) { + return iterator( + this, findInternal(k).idx); + } + + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal> + const_iterator find(LookupKeyT k) const { + return const_cast(this) + ->find(k); + } + + /* + * insert -- + * + * Returns a pair with iterator to the element at r.first and bool success. + * Retrieve the index with ret.first.getIndex(). + * + * Fails on key collision (does not overwrite) or if map becomes + * full, at which point no element is inserted, iterator is set to end(), + * and success is set false. On collisions, success is set false, but the + * iterator is set to the existing entry. + */ + std::pair insert(const value_type& r) { + return emplace(r.first, r.second); + } + std::pair insert(value_type&& r) { + return emplace(r.first, std::move(r.second)); + } + + /* + * emplace -- + * + * Same contract as insert(), but performs in-place construction + * of the value type using the specified arguments. + * + * Also, like find(), this method optionally allows 'key_in' to have a type + * different from that stored in the table; see find(). If and only if no + * equal key is already present, this method converts 'key_in' to a key of + * type KeyT using the provided LookupKeyToKeyFcn. + */ + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal, + typename LookupKeyToKeyFcn = key_convert, + typename... ArgTs> + std::pair emplace(LookupKeyT key_in, ArgTs&&... vCtorArgs) { + SimpleRetT ret = insertInternal< + LookupKeyT, + LookupHashFcn, + LookupEqualFcn, + LookupKeyToKeyFcn>(key_in, std::forward(vCtorArgs)...); + return std::make_pair(iterator(this, ret.idx), ret.success); + } + + // returns the number of elements erased - should never exceed 1 + size_t erase(KeyT k); + + // clears all keys and values in the map and resets all counters. Not thread + // safe. + void clear(); + + // Exact number of elements in the map - note that readFull() acquires a + // mutex. See folly/ThreadCachedInt.h for more details. + size_t size() const { + return numEntries_.readFull() - numErases_.load(std::memory_order_relaxed); + } + + bool empty() const { return size() == 0; } + + iterator begin() { + iterator it(this, 0); + it.advancePastEmpty(); + return it; + } + const_iterator begin() const { + const_iterator it(this, 0); + it.advancePastEmpty(); + return it; + } + + iterator end() { return iterator(this, capacity_); } + const_iterator end() const { return const_iterator(this, capacity_); } + + // See AtomicHashMap::findAt - access elements directly + // WARNING: The following 2 functions will fail silently for hashtable + // with capacity > 2^32 + iterator findAt(uint32_t idx) { + DCHECK_LT(idx, capacity_); + return iterator(this, idx); + } + const_iterator findAt(uint32_t idx) const { + return const_cast(this)->findAt(idx); + } + + iterator makeIter(size_t idx) { return iterator(this, idx); } + const_iterator makeIter(size_t idx) const { + return const_iterator(this, idx); + } + + // The max load factor allowed for this map + double maxLoadFactor() const { return ((double)maxEntries_) / capacity_; } + + void setEntryCountThreadCacheSize(uint32_t newSize) { + numEntries_.setCacheSize(newSize); + numPendingEntries_.setCacheSize(newSize); + } + + uint32_t getEntryCountThreadCacheSize() const { + return numEntries_.getCacheSize(); + } + + /* Private data and helper functions... */ + + private: + friend class AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn>; + + struct SimpleRetT { + size_t idx; + bool success; + SimpleRetT(size_t i, bool s) : idx(i), success(s) {} + SimpleRetT() = default; + }; + + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal, + typename LookupKeyToKeyFcn = Identity, + typename... ArgTs> + SimpleRetT insertInternal(LookupKeyT key, ArgTs&&... vCtorArgs); + + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal> + SimpleRetT findInternal(const LookupKeyT key); + + template + void checkLegalKeyIfKey(MaybeKeyT key) { + detail::checkLegalKeyIfKeyTImpl(key, kEmptyKey_, kLockedKey_, kErasedKey_); + } + + static std::atomic* cellKeyPtr(const value_type& r) { + // We need some illegal casting here in order to actually store + // our value_type as a std::pair. But a little bit of + // undefined behavior never hurt anyone ... + static_assert( + sizeof(std::atomic) == sizeof(KeyT), + "std::atomic is implemented in an unexpected way for AHM"); + return const_cast*>( + reinterpret_cast const*>(&r.first)); + } + + static KeyT relaxedLoadKey(const value_type& r) { + return cellKeyPtr(r)->load(std::memory_order_relaxed); + } + + static KeyT acquireLoadKey(const value_type& r) { + return cellKeyPtr(r)->load(std::memory_order_acquire); + } + + // Fun with thread local storage - atomic increment is expensive + // (relatively), so we accumulate in the thread cache and periodically + // flush to the actual variable, and walk through the unflushed counts when + // reading the value, so be careful of calling size() too frequently. This + // increases insertion throughput several times over while keeping the count + // accurate. + ThreadCachedInt numEntries_; // Successful key inserts + ThreadCachedInt numPendingEntries_; // Used by insertInternal + std::atomic isFull_; // Used by insertInternal + std::atomic numErases_; // Successful key erases + + value_type cells_[0]; // This must be the last field of this class + + // Force constructor/destructor private since create/destroy should be + // used externally instead + AtomicHashArray( + size_t capacity, + KeyT emptyKey, + KeyT lockedKey, + KeyT erasedKey, + double maxLoadFactor, + uint32_t cacheSize); + + AtomicHashArray(const AtomicHashArray&) = delete; + AtomicHashArray& operator=(const AtomicHashArray&) = delete; + + ~AtomicHashArray() = default; + + inline void unlockCell(value_type* const cell, KeyT newKey) { + cellKeyPtr(*cell)->store(newKey, std::memory_order_release); + } + + inline bool tryLockCell(value_type* const cell) { + KeyT expect = kEmptyKey_; + return cellKeyPtr(*cell)->compare_exchange_strong( + expect, kLockedKey_, std::memory_order_acq_rel); + } + + template + inline size_t keyToAnchorIdx(const LookupKeyT k) const { + const size_t hashVal = LookupHashFcn()(k); + const size_t probe = hashVal & kAnchorMask_; + return FOLLY_LIKELY(probe < capacity_) ? probe : hashVal % capacity_; + } + +}; // AtomicHashArray + +} // namespace folly + +#include diff --git a/vnext/external/folly/folly/AtomicHashMap-inl.h b/vnext/external/folly/folly/AtomicHashMap-inl.h new file mode 100644 index 00000000000..c73c13e90c9 --- /dev/null +++ b/vnext/external/folly/folly/AtomicHashMap-inl.h @@ -0,0 +1,653 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef FOLLY_ATOMICHASHMAP_H_ +#error "This should only be included by AtomicHashMap.h" +#endif + +#include +#include + +#include + +namespace folly { + +// AtomicHashMap constructor -- Atomic wrapper that allows growth +// This class has a lot of overhead (184 Bytes) so only use for big maps +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::AtomicHashMap(size_t finalSizeEst, const Config& config) + : kGrowthFrac_( + config.growthFactor < 0 ? 1.0f - config.maxLoadFactor + : config.growthFactor) { + CHECK(config.maxLoadFactor > 0.0f && config.maxLoadFactor < 1.0f); + subMaps_[0].store( + SubMap::create(finalSizeEst, config).release(), + std::memory_order_relaxed); + auto subMapCount = kNumSubMaps_; + FOR_EACH_RANGE (i, 1, subMapCount) { + subMaps_[i].store(nullptr, std::memory_order_relaxed); + } + numMapsAllocated_.store(1, std::memory_order_relaxed); +} + +// emplace -- +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +template < + typename LookupKeyT, + typename LookupHashFcn, + typename LookupEqualFcn, + typename LookupKeyToKeyFcn, + typename... ArgTs> +std::pair< + typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::iterator, + bool> +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::emplace(LookupKeyT k, ArgTs&&... vCtorArgs) { + SimpleRetT ret = insertInternal< + LookupKeyT, + LookupHashFcn, + LookupEqualFcn, + LookupKeyToKeyFcn>(k, std::forward(vCtorArgs)...); + SubMap* subMap = subMaps_[ret.i].load(std::memory_order_relaxed); + return std::make_pair( + iterator(this, ret.i, subMap->makeIter(ret.j)), ret.success); +} + +// insertInternal -- Allocates new sub maps as existing ones fill up. +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +template < + typename LookupKeyT, + typename LookupHashFcn, + typename LookupEqualFcn, + typename LookupKeyToKeyFcn, + typename... ArgTs> +typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::SimpleRetT +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::insertInternal(LookupKeyT key, ArgTs&&... vCtorArgs) { +beginInsertInternal: + auto nextMapIdx = // this maintains our state + numMapsAllocated_.load(std::memory_order_acquire); + typename SubMap::SimpleRetT ret; + FOR_EACH_RANGE (i, 0, nextMapIdx) { + // insert in each map successively. If one succeeds, we're done! + SubMap* subMap = subMaps_[i].load(std::memory_order_relaxed); + ret = subMap->template insertInternal< + LookupKeyT, + LookupHashFcn, + LookupEqualFcn, + LookupKeyToKeyFcn>(key, std::forward(vCtorArgs)...); + if (ret.idx == subMap->capacity_) { + continue; // map is full, so try the next one + } + // Either collision or success - insert in either case + return SimpleRetT(i, ret.idx, ret.success); + } + + // If we made it this far, all maps are full and we need to try to allocate + // the next one. + + SubMap* primarySubMap = subMaps_[0].load(std::memory_order_relaxed); + if (nextMapIdx >= kNumSubMaps_ || + primarySubMap->capacity_ * kGrowthFrac_ < 1.0) { + // Can't allocate any more sub maps. + throw AtomicHashMapFullError(); + } + + if (tryLockMap(nextMapIdx)) { + // Alloc a new map and shove it in. We can change whatever + // we want because other threads are waiting on us... + size_t numCellsAllocated = + (size_t)(primarySubMap->capacity_ * + std::pow(1.0 + kGrowthFrac_, nextMapIdx - 1)); + size_t newSize = size_t(numCellsAllocated * kGrowthFrac_); + DCHECK( + subMaps_[nextMapIdx].load(std::memory_order_relaxed) == + (SubMap*)kLockedPtr_); + // create a new map using the settings stored in the first map + + Config config; + config.emptyKey = primarySubMap->kEmptyKey_; + config.lockedKey = primarySubMap->kLockedKey_; + config.erasedKey = primarySubMap->kErasedKey_; + config.maxLoadFactor = primarySubMap->maxLoadFactor(); + config.entryCountThreadCacheSize = + primarySubMap->getEntryCountThreadCacheSize(); + subMaps_[nextMapIdx].store( + SubMap::create(newSize, config).release(), std::memory_order_relaxed); + + // Publish the map to other threads. + numMapsAllocated_.fetch_add(1, std::memory_order_release); + DCHECK_EQ( + nextMapIdx + 1, numMapsAllocated_.load(std::memory_order_relaxed)); + } else { + // If we lost the race, we'll have to wait for the next map to get + // allocated before doing any insertion here. + detail::atomic_hash_spin_wait([&] { + return nextMapIdx >= numMapsAllocated_.load(std::memory_order_acquire); + }); + } + + // Relaxed is ok here because either we just created this map, or we + // just did a spin wait with an acquire load on numMapsAllocated_. + SubMap* loadedMap = subMaps_[nextMapIdx].load(std::memory_order_relaxed); + DCHECK(loadedMap && loadedMap != (SubMap*)kLockedPtr_); + ret = loadedMap->insertInternal(key, std::forward(vCtorArgs)...); + if (ret.idx != loadedMap->capacity_) { + return SimpleRetT(nextMapIdx, ret.idx, ret.success); + } + // We took way too long and the new map is already full...try again from + // the top (this should pretty much never happen). + goto beginInsertInternal; +} + +// find -- +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +template +typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::iterator +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::find(LookupKeyT k) { + SimpleRetT ret = findInternal(k); + if (!ret.success) { + return end(); + } + SubMap* subMap = subMaps_[ret.i].load(std::memory_order_relaxed); + return iterator(this, ret.i, subMap->makeIter(ret.j)); +} + +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +template +typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::const_iterator +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::find(LookupKeyT k) const { + return const_cast(this) + ->find(k); +} + +// findInternal -- +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +template +typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::SimpleRetT +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::findInternal(const LookupKeyT k) const { + SubMap* const primaryMap = subMaps_[0].load(std::memory_order_relaxed); + typename SubMap::SimpleRetT ret = + primaryMap + ->template findInternal(k); + if (FOLLY_LIKELY(ret.idx != primaryMap->capacity_)) { + return SimpleRetT(0, ret.idx, ret.success); + } + const unsigned int numMaps = + numMapsAllocated_.load(std::memory_order_acquire); + FOR_EACH_RANGE (i, 1, numMaps) { + // Check each map successively. If one succeeds, we're done! + SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); + ret = + thisMap + ->template findInternal( + k); + if (FOLLY_LIKELY(ret.idx != thisMap->capacity_)) { + return SimpleRetT(i, ret.idx, ret.success); + } + } + // Didn't find our key... + return SimpleRetT(numMaps, 0, false); +} + +// findAtInternal -- see encodeIndex() for details. +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::SimpleRetT +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::findAtInternal(uint32_t idx) const { + uint32_t subMapIdx, subMapOffset; + if (idx & kSecondaryMapBit_) { + // idx falls in a secondary map + idx &= ~kSecondaryMapBit_; // unset secondary bit + subMapIdx = idx >> kSubMapIndexShift_; + DCHECK_LT(subMapIdx, numMapsAllocated_.load(std::memory_order_relaxed)); + subMapOffset = idx & kSubMapIndexMask_; + } else { + // idx falls in primary map + subMapIdx = 0; + subMapOffset = idx; + } + return SimpleRetT(subMapIdx, subMapOffset, true); +} + +// erase -- +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +typename AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::size_type +AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::erase(const KeyT k) { + int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); + FOR_EACH_RANGE (i, 0, numMaps) { + // Check each map successively. If one succeeds, we're done! + if (subMaps_[i].load(std::memory_order_relaxed)->erase(k)) { + return 1; + } + } + // Didn't find our key... + return 0; +} + +// capacity -- summation of capacities of all submaps +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +size_t AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::capacity() const { + size_t totalCap(0); + int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); + FOR_EACH_RANGE (i, 0, numMaps) { + totalCap += subMaps_[i].load(std::memory_order_relaxed)->capacity_; + } + return totalCap; +} + +// spaceRemaining -- +// number of new insertions until current submaps are all at max load +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +size_t AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::spaceRemaining() const { + size_t spaceRem(0); + int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); + FOR_EACH_RANGE (i, 0, numMaps) { + SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); + spaceRem += + std::max(0, thisMap->maxEntries_ - &thisMap->numEntries_.readFull()); + } + return spaceRem; +} + +// clear -- Wipes all keys and values from primary map and destroys +// all secondary maps. Not thread safe. +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +void AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::clear() { + subMaps_[0].load(std::memory_order_relaxed)->clear(); + int const numMaps = numMapsAllocated_.load(std::memory_order_relaxed); + FOR_EACH_RANGE (i, 1, numMaps) { + SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); + DCHECK(thisMap); + SubMap::destroy(thisMap); + subMaps_[i].store(nullptr, std::memory_order_relaxed); + } + numMapsAllocated_.store(1, std::memory_order_relaxed); +} + +// size -- +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +size_t AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::size() const { + size_t totalSize(0); + int const numMaps = numMapsAllocated_.load(std::memory_order_acquire); + FOR_EACH_RANGE (i, 0, numMaps) { + totalSize += subMaps_[i].load(std::memory_order_relaxed)->size(); + } + return totalSize; +} + +// encodeIndex -- Encode the submap index and offset into return. +// index_ret must be pre-populated with the submap offset. +// +// We leave index_ret untouched when referring to the primary map +// so it can be as large as possible (31 data bits). Max size of +// secondary maps is limited by what can fit in the low 27 bits. +// +// Returns the following bit-encoded data in index_ret: +// if subMap == 0 (primary map) => +// bit(s) value +// 31 0 +// 0-30 submap offset (index_ret input) +// +// if subMap > 0 (secondary maps) => +// bit(s) value +// 31 1 +// 27-30 which subMap +// 0-26 subMap offset (index_ret input) +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +inline uint32_t AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::encodeIndex(uint32_t subMap, uint32_t offset) { + DCHECK_EQ(offset & kSecondaryMapBit_, 0); // offset can't be too big + if (subMap == 0) { + return offset; + } + // Make sure subMap isn't too big + DCHECK_EQ(subMap >> kNumSubMapBits_, 0); + // Make sure subMap bits of offset are clear + DCHECK_EQ(offset & (~kSubMapIndexMask_ | kSecondaryMapBit_), 0); + + // Set high-order bits to encode which submap this index belongs to + return offset | (subMap << kSubMapIndexShift_) | kSecondaryMapBit_; +} + +// Iterator implementation + +template < + typename KeyT, + typename ValueT, + typename HashFcn, + typename EqualFcn, + typename Allocator, + typename ProbeFcn, + typename KeyConvertFcn> +template +struct AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn>::ahm_iterator + : detail::IteratorFacade< + ahm_iterator, + IterVal, + std::forward_iterator_tag> { + explicit ahm_iterator() : ahm_(nullptr) {} + + // Conversion ctor for interoperability between const_iterator and + // iterator. The enable_if<> magic keeps us well-behaved for + // is_convertible<> (v. the iterator_facade documentation). + template + ahm_iterator( + const ahm_iterator& o, + typename std::enable_if< + std::is_convertible::value>::type* = nullptr) + : ahm_(o.ahm_), subMap_(o.subMap_), subIt_(o.subIt_) {} + + /* + * Returns the unique index that can be used for access directly + * into the data storage. + */ + uint32_t getIndex() const { + CHECK(!isEnd()); + return ahm_->encodeIndex(subMap_, subIt_.getIndex()); + } + + private: + friend class AtomicHashMap; + explicit ahm_iterator(ContT* ahm, uint32_t subMap, const SubIt& subIt) + : ahm_(ahm), subMap_(subMap), subIt_(subIt) {} + + friend class detail:: + IteratorFacade; + + void increment() { + CHECK(!isEnd()); + ++subIt_; + checkAdvanceToNextSubmap(); + } + + bool equal(const ahm_iterator& other) const { + if (ahm_ != other.ahm_) { + return false; + } + + if (isEnd() || other.isEnd()) { + return isEnd() == other.isEnd(); + } + + return subMap_ == other.subMap_ && subIt_ == other.subIt_; + } + + IterVal& dereference() const { return *subIt_; } + + bool isEnd() const { return ahm_ == nullptr; } + + void checkAdvanceToNextSubmap() { + if (isEnd()) { + return; + } + + SubMap* thisMap = ahm_->subMaps_[subMap_].load(std::memory_order_relaxed); + while (subIt_ == thisMap->end()) { + // This sub iterator is done, advance to next one + if (subMap_ + 1 < + ahm_->numMapsAllocated_.load(std::memory_order_acquire)) { + ++subMap_; + thisMap = ahm_->subMaps_[subMap_].load(std::memory_order_relaxed); + subIt_ = thisMap->begin(); + } else { + ahm_ = nullptr; + return; + } + } + } + + private: + ContT* ahm_; + uint32_t subMap_; + SubIt subIt_; +}; // ahm_iterator + +} // namespace folly diff --git a/vnext/external/folly/folly/AtomicHashMap.h b/vnext/external/folly/folly/AtomicHashMap.h new file mode 100644 index 00000000000..5694ac46c18 --- /dev/null +++ b/vnext/external/folly/folly/AtomicHashMap.h @@ -0,0 +1,484 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * AtomicHashMap -- + * + * A high-performance concurrent hash map with int32_t or int64_t keys. Supports + * insert, find(key), findAt(index), erase(key), size, and more. Memory cannot + * be freed or reclaimed by erase. Can grow to a maximum of about 18 times the + * initial capacity, but performance degrades linearly with growth. Can also be + * used as an object store with unique 32-bit references directly into the + * internal storage (retrieved with iterator::getIndex()). + * + * Advantages: + * - High-performance (~2-4x tbb::concurrent_hash_map in heavily + * multi-threaded environments). + * - Efficient memory usage if initial capacity is not over estimated + * (especially for small keys and values). + * - Good fragmentation properties (only allocates in large slabs which can + * be reused with clear() and never move). + * - Can generate unique, long-lived 32-bit references for efficient lookup + * (see findAt()). + * + * Disadvantages: + * - Keys must be native int32_t or int64_t, or explicitly converted. + * - Must be able to specify unique empty, locked, and erased keys + * - Performance degrades linearly as size grows beyond initialization + * capacity. + * - Max size limit of ~18x initial size (dependent on max load factor). + * - Memory is not freed or reclaimed by erase. + * + * Usage and Operation Details: + * Simple performance/memory tradeoff with maxLoadFactor. Higher load factors + * give better memory utilization but probe lengths increase, reducing + * performance. + * + * Implementation and Performance Details: + * AHArray is a fixed size contiguous block of value_type cells. When + * writing a cell, the key is locked while the rest of the record is + * written. Once done, the cell is unlocked by setting the key. find() + * is completely wait-free and doesn't require any non-relaxed atomic + * operations. AHA cannot grow beyond initialization capacity, but is + * faster because of reduced data indirection. + * + * AHMap is a wrapper around AHArray sub-maps that allows growth and provides + * an interface closer to the STL UnorderedAssociativeContainer concept. These + * sub-maps are allocated on the fly and are processed in series, so the more + * there are (from growing past initial capacity), the worse the performance. + * + * Insert returns false if there is a key collision and throws if the max size + * of the map is exceeded. + * + * Benchmark performance with 8 simultaneous threads processing 1 million + * unique entries on a 4-core, 2.5 GHz machine: + * + * Load Factor Mem Efficiency usec/Insert usec/Find + * 50% 50% 0.19 0.05 + * 85% 85% 0.20 0.06 + * 90% 90% 0.23 0.08 + * 95% 95% 0.27 0.10 + * + * See folly/tests/AtomicHashMapTest.cpp for more benchmarks. + */ + +#pragma once +#define FOLLY_ATOMICHASHMAP_H_ + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +namespace folly { + +/* + * AtomicHashMap provides an interface somewhat similar to the + * UnorderedAssociativeContainer concept in C++. This does not + * exactly match this concept (or even the basic Container concept), + * because of some restrictions imposed by our datastructure. + * + * Specific differences (there are quite a few): + * + * - Efficiently thread safe for inserts (main point of this stuff), + * wait-free for lookups. + * + * - You can erase from this container, but the cell containing the key will + * not be free or reclaimed. + * + * - You can erase everything by calling clear() (and you must guarantee only + * one thread can be using the container to do that). + * + * - We aren't DefaultConstructible, CopyConstructible, Assignable, or + * EqualityComparable. (Most of these are probably not something + * you actually want to do with this anyway.) + * + * - We don't support the various bucket functions, rehash(), + * reserve(), or equal_range(). Also no constructors taking + * iterators, although this could change. + * + * - Several insertion functions, notably operator[], are not + * implemented. It is a little too easy to misuse these functions + * with this container, where part of the point is that when an + * insertion happens for a new key, it will atomically have the + * desired value. + * + * - The map has no templated insert() taking an iterator range, but + * we do provide an insert(key, value). The latter seems more + * frequently useful for this container (to avoid sprinkling + * make_pair everywhere), and providing both can lead to some gross + * template error messages. + * + * - The Allocator must not be stateful (a new instance will be spun up for + * each allocation), and its allocate() method must take a raw number of + * bytes. + * + * - KeyT must be a 32 bit or 64 bit atomic integer type, and you must + * define special 'locked' and 'empty' key values in the ctor + * + * - We don't take the Hash function object as an instance in the + * constructor. + * + */ + +// Thrown when insertion fails due to running out of space for +// submaps. +struct FOLLY_EXPORT AtomicHashMapFullError : std::runtime_error { + explicit AtomicHashMapFullError() + : std::runtime_error("AtomicHashMap is full") {} +}; + +template < + class KeyT, + class ValueT, + class HashFcn, + class EqualFcn, + class Allocator, + class ProbeFcn, + class KeyConvertFcn> +class AtomicHashMap { + typedef AtomicHashArray< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + ProbeFcn, + KeyConvertFcn> + SubMap; + + public: + typedef KeyT key_type; + typedef ValueT mapped_type; + typedef std::pair value_type; + typedef HashFcn hasher; + typedef EqualFcn key_equal; + typedef KeyConvertFcn key_convert; + typedef value_type* pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::ptrdiff_t difference_type; + typedef std::size_t size_type; + typedef typename SubMap::Config Config; + + template + struct ahm_iterator; + + typedef ahm_iterator< + const AtomicHashMap, + const value_type, + typename SubMap::const_iterator> + const_iterator; + typedef ahm_iterator + iterator; + + public: + const float kGrowthFrac_; // How much to grow when we run out of capacity. + + // The constructor takes a finalSizeEst which is the optimal + // number of elements to maximize space utilization and performance, + // and a Config object to specify more advanced options. + explicit AtomicHashMap(size_t finalSizeEst, const Config& c = Config()); + + AtomicHashMap(const AtomicHashMap&) = delete; + AtomicHashMap& operator=(const AtomicHashMap&) = delete; + + ~AtomicHashMap() { + const unsigned int numMaps = + numMapsAllocated_.load(std::memory_order_relaxed); + FOR_EACH_RANGE (i, 0, numMaps) { + SubMap* thisMap = subMaps_[i].load(std::memory_order_relaxed); + DCHECK(thisMap); + SubMap::destroy(thisMap); + } + } + + key_equal key_eq() const { return key_equal(); } + hasher hash_function() const { return hasher(); } + + /* + * insert -- + * + * Returns a pair with iterator to the element at r.first and + * success. Retrieve the index with ret.first.getIndex(). + * + * Does not overwrite on key collision, but returns an iterator to + * the existing element (since this could due to a race with + * another thread, it is often important to check this return + * value). + * + * Allocates new sub maps as the existing ones become full. If + * all sub maps are full, no element is inserted, and + * AtomicHashMapFullError is thrown. + */ + std::pair insert(const value_type& r) { + return emplace(r.first, r.second); + } + std::pair insert(key_type k, const mapped_type& v) { + return emplace(k, v); + } + std::pair insert(value_type&& r) { + return emplace(r.first, std::move(r.second)); + } + std::pair insert(key_type k, mapped_type&& v) { + return emplace(k, std::move(v)); + } + + /* + * emplace -- + * + * Same contract as insert(), but performs in-place construction + * of the value type using the specified arguments. + * + * Also, like find(), this method optionally allows 'key_in' to have a type + * different from that stored in the table; see find(). If and only if no + * equal key is already present, this method converts 'key_in' to a key of + * type KeyT using the provided LookupKeyToKeyFcn. + */ + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal, + typename LookupKeyToKeyFcn = key_convert, + typename... ArgTs> + std::pair emplace(LookupKeyT k, ArgTs&&... vCtorArg); + + /* + * find -- + * + * Returns the iterator to the element if found, otherwise end(). + * + * As an optional feature, the type of the key to look up (LookupKeyT) is + * allowed to be different from the type of keys actually stored (KeyT). + * + * This enables use cases where materializing the key is costly and usually + * redundant, e.g., canonicalizing/interning a set of strings and being able + * to look up by StringPiece. To use this feature, LookupHashFcn must take + * a LookupKeyT, and LookupEqualFcn must take KeyT and LookupKeyT as first + * and second parameter, respectively. + * + * See folly/test/ArrayHashMapTest.cpp for sample usage. + */ + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal> + iterator find(LookupKeyT k); + + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal> + const_iterator find(LookupKeyT k) const; + + /* + * erase -- + * + * Erases key k from the map + * + * Returns 1 iff the key is found and erased, and 0 otherwise. + */ + size_type erase(key_type k); + + /* + * clear -- + * + * Wipes all keys and values from primary map and destroys all secondary + * maps. Primary map remains allocated and thus the memory can be reused + * in place. Not thread safe. + * + */ + void clear(); + + /* + * size -- + * + * Returns the exact size of the map. Note this is not as cheap as typical + * size() implementations because, for each AtomicHashArray in this AHM, we + * need to grab a lock and accumulate the values from all the thread local + * counters. See folly/ThreadCachedInt.h for more details. + */ + size_t size() const; + + bool empty() const { return size() == 0; } + + size_type count(key_type k) const { return find(k) == end() ? 0 : 1; } + + /* + * findAt -- + * + * Returns an iterator into the map. + * + * idx should only be an unmodified value returned by calling getIndex() on + * a valid iterator returned by find() or insert(). If idx is invalid you + * have a bug and the process aborts. + */ + iterator findAt(uint32_t idx) { + SimpleRetT ret = findAtInternal(idx); + DCHECK_LT(ret.i, numSubMaps()); + return iterator( + this, + ret.i, + subMaps_[ret.i].load(std::memory_order_relaxed)->makeIter(ret.j)); + } + const_iterator findAt(uint32_t idx) const { + return const_cast(this)->findAt(idx); + } + + // Total capacity - summation of capacities of all submaps. + size_t capacity() const; + + // Number of new insertions until current submaps are all at max load factor. + size_t spaceRemaining() const; + + void setEntryCountThreadCacheSize(int32_t newSize) { + const int numMaps = numMapsAllocated_.load(std::memory_order_acquire); + for (int i = 0; i < numMaps; ++i) { + SubMap* map = subMaps_[i].load(std::memory_order_relaxed); + map->setEntryCountThreadCacheSize(newSize); + } + } + + // Number of sub maps allocated so far to implement this map. The more there + // are, the worse the performance. + int numSubMaps() const { + return numMapsAllocated_.load(std::memory_order_acquire); + } + + iterator begin() { + iterator it(this, 0, subMaps_[0].load(std::memory_order_relaxed)->begin()); + it.checkAdvanceToNextSubmap(); + return it; + } + + const_iterator begin() const { + const_iterator it( + this, 0, subMaps_[0].load(std::memory_order_relaxed)->begin()); + it.checkAdvanceToNextSubmap(); + return it; + } + + iterator end() { return iterator(); } + + const_iterator end() const { return const_iterator(); } + + /* Advanced functions for direct access: */ + + inline uint32_t recToIdx(const value_type& r, bool mayInsert = true) { + SimpleRetT ret = + mayInsert ? insertInternal(r.first, r.second) : findInternal(r.first); + return encodeIndex(ret.i, ret.j); + } + + inline uint32_t recToIdx(value_type&& r, bool mayInsert = true) { + SimpleRetT ret = mayInsert ? insertInternal(r.first, std::move(r.second)) + : findInternal(r.first); + return encodeIndex(ret.i, ret.j); + } + + inline uint32_t recToIdx( + key_type k, const mapped_type& v, bool mayInsert = true) { + SimpleRetT ret = mayInsert ? insertInternal(k, v) : findInternal(k); + return encodeIndex(ret.i, ret.j); + } + + inline uint32_t recToIdx(key_type k, mapped_type&& v, bool mayInsert = true) { + SimpleRetT ret = + mayInsert ? insertInternal(k, std::move(v)) : findInternal(k); + return encodeIndex(ret.i, ret.j); + } + + inline uint32_t keyToIdx(const KeyT k, bool mayInsert = false) { + return recToIdx(value_type(k), mayInsert); + } + + inline const value_type& idxToRec(uint32_t idx) const { + SimpleRetT ret = findAtInternal(idx); + return subMaps_[ret.i].load(std::memory_order_relaxed)->idxToRec(ret.j); + } + + /* Private data and helper functions... */ + + private: + // This limits primary submap size to 2^31 ~= 2 billion, secondary submap + // size to 2^(32 - kNumSubMapBits_ - 1) = 2^27 ~= 130 million, and num subMaps + // to 2^kNumSubMapBits_ = 16. + static const uint32_t kNumSubMapBits_ = 4; + static const uint32_t kSecondaryMapBit_ = 1u << 31; // Highest bit + static const uint32_t kSubMapIndexShift_ = 32 - kNumSubMapBits_ - 1; + static const uint32_t kSubMapIndexMask_ = (1 << kSubMapIndexShift_) - 1; + static const uint32_t kNumSubMaps_ = 1 << kNumSubMapBits_; + static const uintptr_t kLockedPtr_ = 0x88ULL << 48; // invalid pointer + + struct SimpleRetT { + uint32_t i; + size_t j; + bool success; + SimpleRetT(uint32_t ii, size_t jj, bool s) : i(ii), j(jj), success(s) {} + SimpleRetT() = default; + }; + + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal, + typename LookupKeyToKeyFcn = key_convert, + typename... ArgTs> + SimpleRetT insertInternal(LookupKeyT key, ArgTs&&... value); + + template < + typename LookupKeyT = key_type, + typename LookupHashFcn = hasher, + typename LookupEqualFcn = key_equal> + SimpleRetT findInternal(const LookupKeyT k) const; + + SimpleRetT findAtInternal(uint32_t idx) const; + + std::atomic subMaps_[kNumSubMaps_]; + std::atomic numMapsAllocated_; + + inline bool tryLockMap(unsigned int idx) { + SubMap* val = nullptr; + return subMaps_[idx].compare_exchange_strong( + val, (SubMap*)kLockedPtr_, std::memory_order_acquire); + } + + static inline uint32_t encodeIndex(uint32_t subMap, uint32_t subMapIdx); + +}; // AtomicHashMap + +template < + class KeyT, + class ValueT, + class HashFcn = std::hash, + class EqualFcn = std::equal_to, + class Allocator = std::allocator> +using QuadraticProbingAtomicHashMap = AtomicHashMap< + KeyT, + ValueT, + HashFcn, + EqualFcn, + Allocator, + AtomicHashArrayQuadraticProbeFcn>; +} // namespace folly + +#include diff --git a/vnext/external/folly/folly/AtomicIntrusiveLinkedList.h b/vnext/external/folly/folly/AtomicIntrusiveLinkedList.h new file mode 100644 index 00000000000..272efed98ee --- /dev/null +++ b/vnext/external/folly/folly/AtomicIntrusiveLinkedList.h @@ -0,0 +1,206 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +namespace folly { + +/** + * A very simple atomic single-linked list primitive. + * + * Usage: + * + * class MyClass { + * AtomicIntrusiveLinkedListHook hook_; + * } + * + * AtomicIntrusiveLinkedList list; + * list.insert(&a); + * list.sweep([] (MyClass* c) { doSomething(c); } + */ +template +struct AtomicIntrusiveLinkedListHook { + T* next{nullptr}; +}; + +template T::*HookMember> +class AtomicIntrusiveLinkedList { + public: + AtomicIntrusiveLinkedList() {} + + AtomicIntrusiveLinkedList(const AtomicIntrusiveLinkedList&) = delete; + AtomicIntrusiveLinkedList& operator=(const AtomicIntrusiveLinkedList&) = + delete; + + AtomicIntrusiveLinkedList(AtomicIntrusiveLinkedList&& other) noexcept + : head_(other.head_.exchange(nullptr, std::memory_order_acq_rel)) {} + + // Absent because would be too error-prone to use correctly because of + // the requirement that lists are empty upon destruction. + AtomicIntrusiveLinkedList& operator=( + AtomicIntrusiveLinkedList&& other) noexcept = delete; + + /** + * Move the currently held elements to a new list. + * The current list becomes empty, but concurrent threads + * might still add new elements to it. + * + * Equivalent to calling a move constructor, but more linter-friendly + * in case you still need the old list. + */ + AtomicIntrusiveLinkedList spliceAll() { return std::move(*this); } + + /** + * Move-assign the current list to `other`, then reverse-sweep + * the old list with the provided callback `func`. + * + * A safe replacement for the move assignment operator, which is absent + * because of the resource leak concerns. + */ + template + void reverseSweepAndAssign(AtomicIntrusiveLinkedList&& other, F&& func) { + auto otherHead = other.head_.exchange(nullptr, std::memory_order_acq_rel); + auto head = head_.exchange(otherHead, std::memory_order_acq_rel); + unlinkAll(head, std::forward(func)); + } + + /** + * Note: The list must be empty on destruction. + */ + ~AtomicIntrusiveLinkedList() { assert(empty()); } + + /** + * Returns the current head of the list. + * + * WARNING: The returned pointer might not be valid if the list + * is modified concurrently! + */ + T* unsafeHead() const { return head_.load(std::memory_order_acquire); } + + /** + * Returns true if the list is empty. + * + * WARNING: This method's return value is only valid for a snapshot + * of the state, it might become stale as soon as it's returned. + */ + bool empty() const { return unsafeHead() == nullptr; } + + /** + * Atomically insert t at the head of the list. + * @return True if the inserted element is the only one in the list + * after the call. + */ + bool insertHead(T* t) { + assert(next(t) == nullptr); + + auto oldHead = head_.load(std::memory_order_relaxed); + do { + next(t) = oldHead; + /* oldHead is updated by the call below. + + NOTE: we don't use next(t) instead of oldHead directly due to + compiler bugs (GCC prior to 4.8.3 (bug 60272), clang (bug 18899), + MSVC (bug 819819); source: + http://en.cppreference.com/w/cpp/atomic/atomic/compare_exchange */ + } while (!head_.compare_exchange_weak( + oldHead, t, std::memory_order_release, std::memory_order_relaxed)); + + return oldHead == nullptr; + } + + /** + * Replaces the head with nullptr, + * and calls func() on the removed elements in the order from tail to head. + * Returns false if the list was empty. + */ + template + bool sweepOnce(F&& func) { + if (auto head = head_.exchange(nullptr, std::memory_order_acq_rel)) { + auto rhead = reverse(head); + unlinkAll(rhead, std::forward(func)); + return true; + } + return false; + } + + /** + * Repeatedly replaces the head with nullptr, + * and calls func() on the removed elements in the order from tail to head. + * Stops when the list is empty. + */ + template + void sweep(F&& func) { + while (sweepOnce(func)) { + } + } + + /** + * Similar to sweep() but calls func() on elements in LIFO order. + * + * func() is called for all elements in the list at the moment + * reverseSweep() is called. Unlike sweep() it does not loop to ensure the + * list is empty at some point after the last invocation. This way callers + * can reason about the ordering: elements inserted since the last call to + * reverseSweep() will be provided in LIFO order. + * + * Example: if elements are inserted in the order 1-2-3, the callback is + * invoked 3-2-1. If the callback moves elements onto a stack, popping off + * the stack will produce the original insertion order 1-2-3. + */ + template + void reverseSweep(F&& func) { + // We don't loop like sweep() does because the overall order of callbacks + // would be strand-wise LIFO which is meaningless to callers. + auto head = head_.exchange(nullptr, std::memory_order_acq_rel); + unlinkAll(head, std::forward(func)); + } + + private: + std::atomic head_{nullptr}; + + static T*& next(T* t) { return (t->*HookMember).next; } + + /* Reverses a linked list, returning the pointer to the new head + (old tail) */ + static T* reverse(T* head) { + T* rhead = nullptr; + while (head != nullptr) { + auto t = head; + head = next(t); + next(t) = rhead; + rhead = t; + } + return rhead; + } + + /* Unlinks all elements in the linked list fragment pointed to by `head', + * calling func() on every element */ + template + static void unlinkAll(T* head, F&& func) { + while (head != nullptr) { + auto t = head; + head = next(t); + next(t) = nullptr; + func(t); + } + } +}; + +} // namespace folly diff --git a/vnext/external/folly/folly/AtomicLinkedList.h b/vnext/external/folly/folly/AtomicLinkedList.h new file mode 100644 index 00000000000..a644dbe6024 --- /dev/null +++ b/vnext/external/folly/folly/AtomicLinkedList.h @@ -0,0 +1,110 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace folly { + +/** + * A very simple atomic single-linked list primitive. + * + * Usage: + * + * AtomicLinkedList list; + * list.insert(a); + * list.sweep([] (MyClass& c) { doSomething(c); } + */ + +template +class AtomicLinkedList { + public: + AtomicLinkedList() {} + AtomicLinkedList(const AtomicLinkedList&) = delete; + AtomicLinkedList& operator=(const AtomicLinkedList&) = delete; + AtomicLinkedList(AtomicLinkedList&& other) noexcept = default; + AtomicLinkedList& operator=(AtomicLinkedList&& other) noexcept { + list_.reverseSweepAndAssign( + std::move(other.list_), [](Wrapper* node) { delete node; }); + return *this; + } + + ~AtomicLinkedList() { + sweep([](T&&) {}); + } + + bool empty() const { return list_.empty(); } + + /** + * Atomically insert t at the head of the list. + * @return True if the inserted element is the only one in the list + * after the call. + */ + bool insertHead(T t) { + auto wrapper = std::make_unique(std::move(t)); + + return list_.insertHead(wrapper.release()); + } + + /** + * Repeatedly pops element from head, + * and calls func() on the removed elements in the order from tail to head. + * Stops when the list is empty. + */ + template + void sweep(F&& func) { + list_.sweep([&](Wrapper* wrapperPtr) mutable { + std::unique_ptr wrapper(wrapperPtr); + + func(std::move(wrapper->data)); + }); + } + + /** + * Similar to sweep() but calls func() on elements in LIFO order. + * + * func() is called for all elements in the list at the moment + * reverseSweep() is called. Unlike sweep() it does not loop to ensure the + * list is empty at some point after the last invocation. This way callers + * can reason about the ordering: elements inserted since the last call to + * reverseSweep() will be provided in LIFO order. + * + * Example: if elements are inserted in the order 1-2-3, the callback is + * invoked 3-2-1. If the callback moves elements onto a stack, popping off + * the stack will produce the original insertion order 1-2-3. + */ + template + void reverseSweep(F&& func) { + list_.reverseSweep([&](Wrapper* wrapperPtr) mutable { + std::unique_ptr wrapper(wrapperPtr); + + func(std::move(wrapper->data)); + }); + } + + private: + struct Wrapper { + explicit Wrapper(T&& t) : data(std::move(t)) {} + + AtomicIntrusiveLinkedListHook hook; + T data; + }; + AtomicIntrusiveLinkedList list_; +}; + +} // namespace folly diff --git a/vnext/external/folly/folly/AtomicUnorderedMap.h b/vnext/external/folly/folly/AtomicUnorderedMap.h new file mode 100644 index 00000000000..bfd58e16cb8 --- /dev/null +++ b/vnext/external/folly/folly/AtomicUnorderedMap.h @@ -0,0 +1,522 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace folly { + +/// You're probably reading this because you are looking for an +/// AtomicUnorderedMap that is fully general, highly concurrent (for +/// reads, writes, and iteration), and makes no performance compromises. +/// We haven't figured that one out yet. What you will find here is a +/// hash table implementation that sacrifices generality so that it can +/// give you all of the other things. +/// +/// LIMITATIONS: +/// +/// * Insert only (*) - the only write operation supported directly by +/// AtomicUnorderedInsertMap is findOrConstruct. There is a (*) because +/// values aren't moved, so you can roll your own concurrency control for +/// in-place updates of values (see MutableData and MutableAtom below), +/// but the hash table itself doesn't help you. +/// +/// * No resizing - you must specify the capacity up front, and once +/// the hash map gets full you won't be able to insert. Insert +/// performance will degrade once the load factor is high. Insert is +/// O(1/(1-actual_load_factor)). Note that this is a pretty strong +/// limitation, because you can't remove existing keys. +/// +/// * 2^30 maximum default capacity - by default AtomicUnorderedInsertMap +/// uses uint32_t internal indexes (and steals 2 bits), limiting you +/// to about a billion entries. If you need more you can fill in all +/// of the template params so you change IndexType to uint64_t, or you +/// can use AtomicUnorderedInsertMap64. 64-bit indexes will increase +/// the space over of the map, of course. +/// +/// WHAT YOU GET IN EXCHANGE: +/// +/// * Arbitrary key and value types - any K and V that can be used in a +/// std::unordered_map can be used here. In fact, the key and value +/// types don't even have to be copyable or moveable! +/// +/// * Keys and values in the map won't be moved - it is safe to keep +/// pointers or references to the keys and values in the map, because +/// they are never moved or destroyed (until the map itself is destroyed). +/// +/// * Iterators are never invalidated - writes don't invalidate iterators, +/// so you can scan and insert in parallel. +/// +/// * Fast wait-free reads - reads are usually only a single cache miss, +/// even when the hash table is very large. Wait-freedom means that +/// you won't see latency outliers even in the face of concurrent writes. +/// +/// * Lock-free insert - writes proceed in parallel. If a thread in the +/// middle of a write is unlucky and gets suspended, it doesn't block +/// anybody else. +/// +/// COMMENTS ON INSERT-ONLY +/// +/// This map provides wait-free linearizable reads and lock-free +/// linearizable inserts. Inserted values won't be moved, but no +/// concurrency control is provided for safely updating them. To remind +/// you of that fact they are only provided in const form. This is the +/// only simple safe thing to do while preserving something like the normal +/// std::map iteration form, which requires that iteration be exposed +/// via std::pair (and prevents encapsulation of access to the value). +/// +/// There are a couple of reasonable policies for doing in-place +/// concurrency control on the values. I am hoping that the policy can +/// be injected via the value type or an extra template param, to keep +/// the core AtomicUnorderedInsertMap insert-only: +/// +/// CONST: this is the currently implemented strategy, which is simple, +/// performant, and not that expressive. You can always put in a value +/// with a mutable field (see MutableAtom below), but that doesn't look +/// as pretty as it should. +/// +/// ATOMIC: for integers and integer-size trivially copyable structs +/// (via an adapter like tao/queues/AtomicStruct) the value can be a +/// std::atomic and read and written atomically. +/// +/// SEQ-LOCK: attach a counter incremented before and after write. +/// Writers serialize by using CAS to make an even->odd transition, +/// then odd->even after the write. Readers grab the value with memcpy, +/// checking sequence value before and after. Readers retry until they +/// see an even sequence number that doesn't change. This works for +/// larger structs, but still requires memcpy to be equivalent to copy +/// assignment, and it is no longer lock-free. It scales very well, +/// because the readers are still invisible (no cache line writes). +/// +/// LOCK: folly's SharedMutex would be a good choice here. +/// +/// MEMORY ALLOCATION +/// +/// Underlying memory is allocated as a big anonymous mmap chunk, which +/// might be cheaper than calloc() and is certainly not more expensive +/// for large maps. If the SkipKeyValueDeletion template param is true +/// then deletion of the map consists of unmapping the backing memory, +/// which is much faster than destructing all of the keys and values. +/// Feel free to override if std::is_trivial_destructor isn't recognizing +/// the triviality of your destructors. +template < + typename Key, + typename Value, + typename Hash = std::hash, + typename KeyEqual = std::equal_to, + bool SkipKeyValueDeletion = + (std::is_trivially_destructible::value && + std::is_trivially_destructible::value), + template class Atom = std::atomic, + typename IndexType = uint32_t, + typename Allocator = folly::detail::MMapAlloc> + +struct AtomicUnorderedInsertMap { + typedef Key key_type; + typedef Value mapped_type; + typedef std::pair value_type; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef Hash hasher; + typedef KeyEqual key_equal; + typedef const value_type& const_reference; + + typedef struct ConstIterator { + ConstIterator(const AtomicUnorderedInsertMap& owner, IndexType slot) + : owner_(owner), slot_(slot) {} + + ConstIterator(const ConstIterator&) = default; + ConstIterator& operator=(const ConstIterator&) = default; + + const value_type& operator*() const { + return owner_.slots_[slot_].keyValue(); + } + + const value_type* operator->() const { + return &owner_.slots_[slot_].keyValue(); + } + + // pre-increment + const ConstIterator& operator++() { + while (slot_ > 0) { + --slot_; + if (owner_.slots_[slot_].state() == LINKED) { + break; + } + } + return *this; + } + + // post-increment + ConstIterator operator++(int /* dummy */) { + auto prev = *this; + ++*this; + return prev; + } + + bool operator==(const ConstIterator& rhs) const { + return slot_ == rhs.slot_; + } + bool operator!=(const ConstIterator& rhs) const { return !(*this == rhs); } + + private: + const AtomicUnorderedInsertMap& owner_; + IndexType slot_; + } const_iterator; + + friend ConstIterator; + + /// Constructs a map that will support the insertion of maxSize key-value + /// pairs without exceeding the max load factor. Load factors of greater + /// than 1 are not supported, and once the actual load factor of the + /// map approaches 1 the insert performance will suffer. The capacity + /// is limited to 2^30 (about a billion) for the default IndexType, + /// beyond which we will throw invalid_argument. + explicit AtomicUnorderedInsertMap( + size_t maxSize, + float maxLoadFactor = 0.8f, + const Allocator& alloc = Allocator()) + : allocator_(alloc) { + size_t capacity = size_t(maxSize / std::min(1.0f, maxLoadFactor) + 128); + size_t avail = size_t{1} << (8 * sizeof(IndexType) - 2); + if (capacity > avail && maxSize < avail) { + // we'll do our best + capacity = avail; + } + if (capacity < maxSize || capacity > avail) { + throw std::invalid_argument( + "AtomicUnorderedInsertMap capacity must fit in IndexType with 2 bits " + "left over"); + } + + numSlots_ = capacity; + slotMask_ = folly::nextPowTwo(capacity * 4) - 1; + mmapRequested_ = sizeof(Slot) * capacity; + slots_ = reinterpret_cast(allocator_.allocate(mmapRequested_)); + zeroFillSlots(); + // mark the zero-th slot as in-use but not valid, since that happens + // to be our nil value + slots_[0].stateUpdate(EMPTY, CONSTRUCTING); + } + + ~AtomicUnorderedInsertMap() { + if (!SkipKeyValueDeletion) { + for (size_t i = 1; i < numSlots_; ++i) { + slots_[i].~Slot(); + } + } + allocator_.deallocate(reinterpret_cast(slots_), mmapRequested_); + } + + /// Searches for the key, returning (iter,false) if it is found. + /// If it is not found calls the functor Func with a void* argument + /// that is raw storage suitable for placement construction of a Value + /// (see raw_value_type), then returns (iter,true). May call Func and + /// then return (iter,false) if there are other concurrent writes, in + /// which case the newly constructed value will be immediately destroyed. + /// + /// This function does not block other readers or writers. If there + /// are other concurrent writes, many parallel calls to func may happen + /// and only the first one to complete will win. The values constructed + /// by the other calls to func will be destroyed. + /// + /// Usage: + /// + /// AtomicUnorderedInsertMap memo; + /// + /// auto value = memo.findOrConstruct(key, [=](void* raw) { + /// new (raw) std::string(computation(key)); + /// })->first; + template + std::pair findOrConstruct(const Key& key, Func&& func) { + auto const slot = keyToSlotIdx(key); + auto prev = slots_[slot].headAndState_.load(std::memory_order_acquire); + + auto existing = find(key, slot); + if (existing != 0) { + return std::make_pair(ConstIterator(*this, existing), false); + } + + // The copying of key and the calling of func can throw exceptions. Nothing + // else in this function can throw an exception. In the event of an + // exception, deallocate as if the KV was beaten in a concurrent addition. + const auto idx = allocateNear(slot); + SCOPE_FAIL { + slots_[idx].stateUpdate(CONSTRUCTING, EMPTY); + }; + Key* addr = &slots_[idx].keyValue().first; + new (addr) Key(key); + SCOPE_FAIL { + addr->~Key(); + }; + func(static_cast(&slots_[idx].keyValue().second)); + + while (true) { + slots_[idx].next_ = prev >> 2; + + // we can merge the head update and the CONSTRUCTING -> LINKED update + // into a single CAS if slot == idx (which should happen often) + auto after = idx << 2; + if (slot == idx) { + after += LINKED; + } else { + after += (prev & 3); + } + + if (slots_[slot].headAndState_.compare_exchange_strong(prev, after)) { + // success + if (idx != slot) { + slots_[idx].stateUpdate(CONSTRUCTING, LINKED); + } + return std::make_pair(ConstIterator(*this, idx), true); + } + // compare_exchange_strong updates its first arg on failure, so + // there is no need to reread prev + + existing = find(key, slot); + if (existing != 0) { + // our allocated key and value are no longer needed + slots_[idx].keyValue().first.~Key(); + slots_[idx].keyValue().second.~Value(); + slots_[idx].stateUpdate(CONSTRUCTING, EMPTY); + + return std::make_pair(ConstIterator(*this, existing), false); + } + } + } + + /// This isn't really emplace, but it is what we need to test. + /// Eventually we can duplicate all of the std::pair constructor + /// forms, including a recursive tuple forwarding template + /// http://functionalcpp.wordpress.com/2013/08/28/tuple-forwarding/). + template + std::pair emplace(const K& key, V&& value) { + return findOrConstruct( + key, [&](void* raw) { new (raw) Value(std::forward(value)); }); + } + + const_iterator find(const Key& key) const { + return ConstIterator(*this, find(key, keyToSlotIdx(key))); + } + + const_iterator cbegin() const { + IndexType slot = numSlots_ - 1; + while (slot > 0 && slots_[slot].state() != LINKED) { + --slot; + } + return ConstIterator(*this, slot); + } + const_iterator begin() const { return cbegin(); } + + const_iterator cend() const { return ConstIterator(*this, 0); } + const_iterator end() const { return cend(); } + + private: + enum : IndexType { + kMaxAllocationTries = 1000, // after this we throw + }; + + enum BucketState : IndexType { + EMPTY = 0, + CONSTRUCTING = 1, + LINKED = 2, + }; + + /// Lock-free insertion is easiest by prepending to collision chains. + /// A large chaining hash table takes two cache misses instead of + /// one, however. Our solution is to colocate the bucket storage and + /// the head storage, so that even though we are traversing chains we + /// are likely to stay within the same cache line. Just make sure to + /// traverse head before looking at any keys. This strategy gives us + /// 32 bit pointers and fast iteration. + struct Slot { + /// The bottom two bits are the BucketState, the rest is the index + /// of the first bucket for the chain whose keys map to this slot. + /// When things are going well the head usually links to this slot, + /// but that doesn't always have to happen. + Atom headAndState_; + + /// The next bucket in the chain + IndexType next_; + + /// Key and Value + aligned_storage_for_t raw_; + + ~Slot() { + auto s = state(); + assert(s == EMPTY || s == LINKED); + if (s == LINKED) { + keyValue().first.~Key(); + keyValue().second.~Value(); + } + } + + BucketState state() const { + return BucketState(headAndState_.load(std::memory_order_acquire) & 3); + } + + void stateUpdate(BucketState before, BucketState after) { + assert(state() == before); + headAndState_ += (after - before); + } + + value_type& keyValue() { + assert(state() != EMPTY); + return *static_cast(static_cast(&raw_)); + } + + const value_type& keyValue() const { + assert(state() != EMPTY); + return *static_cast(static_cast(&raw_)); + } + }; + + // We manually manage the slot memory so we can bypass initialization + // (by getting a zero-filled mmap chunk) and optionally destruction of + // the slots + + size_t mmapRequested_; + size_t numSlots_; + + /// tricky, see keyToSlotIdx + size_t slotMask_; + + Allocator allocator_; + Slot* slots_; + + IndexType keyToSlotIdx(const Key& key) const { + size_t h = hasher()(key); + h &= slotMask_; + while (h >= numSlots_) { + h -= numSlots_; + } + return h; + } + + IndexType find(const Key& key, IndexType slot) const { + KeyEqual ke = {}; + auto hs = slots_[slot].headAndState_.load(std::memory_order_acquire); + for (slot = hs >> 2; slot != 0; slot = slots_[slot].next_) { + if (ke(key, slots_[slot].keyValue().first)) { + return slot; + } + } + return 0; + } + + /// Allocates a slot and returns its index. Tries to put it near + /// slots_[start]. + IndexType allocateNear(IndexType start) { + for (IndexType tries = 0; tries < kMaxAllocationTries; ++tries) { + auto slot = allocationAttempt(start, tries); + auto prev = slots_[slot].headAndState_.load(std::memory_order_acquire); + if ((prev & 3) == EMPTY && + slots_[slot].headAndState_.compare_exchange_strong( + prev, prev + CONSTRUCTING - EMPTY)) { + return slot; + } + } + throw std::bad_alloc(); + } + + /// Returns the slot we should attempt to allocate after tries failed + /// tries, starting from the specified slot. This is pulled out so we + /// can specialize it differently during deterministic testing + IndexType allocationAttempt(IndexType start, IndexType tries) const { + if (FOLLY_LIKELY(tries < 8 && start + tries < numSlots_)) { + return IndexType(start + tries); + } else { + IndexType rv; + if (sizeof(IndexType) <= 4) { + rv = IndexType(folly::Random::rand32(numSlots_)); + } else { + rv = IndexType(folly::Random::rand64(numSlots_)); + } + assert(rv < numSlots_); + return rv; + } + } + + void zeroFillSlots() { + using folly::detail::GivesZeroFilledMemory; + if (!GivesZeroFilledMemory::value) { + memset(static_cast(slots_), 0, mmapRequested_); + } + } +}; + +/// AtomicUnorderedInsertMap64 is just a type alias that makes it easier +/// to select a 64 bit slot index type. Use this if you need a capacity +/// bigger than 2^30 (about a billion). This increases memory overheads, +/// obviously. +template < + typename Key, + typename Value, + typename Hash = std::hash, + typename KeyEqual = std::equal_to, + bool SkipKeyValueDeletion = + (std::is_trivially_destructible::value && + std::is_trivially_destructible::value), + template class Atom = std::atomic, + typename Allocator = folly::detail::MMapAlloc> +using AtomicUnorderedInsertMap64 = AtomicUnorderedInsertMap< + Key, + Value, + Hash, + KeyEqual, + SkipKeyValueDeletion, + Atom, + uint64_t, + Allocator>; + +/// MutableAtom is a tiny wrapper that gives you the option of atomically +/// updating values inserted into an AtomicUnorderedInsertMap>. This relies on AtomicUnorderedInsertMap's guarantee +/// that it doesn't move values. +template class Atom = std::atomic> +struct MutableAtom { + mutable Atom data; + + explicit MutableAtom(const T& init) : data(init) {} +}; + +/// MutableData is a tiny wrapper that gives you the option of using an +/// external concurrency control mechanism to updating values inserted +/// into an AtomicUnorderedInsertMap. +template +struct MutableData { + mutable T data; + explicit MutableData(const T& init) : data(init) {} +}; + +} // namespace folly diff --git a/vnext/external/folly/folly/BUCK b/vnext/external/folly/folly/BUCK new file mode 100644 index 00000000000..da8afc4b29b --- /dev/null +++ b/vnext/external/folly/folly/BUCK @@ -0,0 +1,1631 @@ +###################################################################### +# Libraries + +load("@fbcode_macros//build_defs:auto_headers.bzl", "AutoHeaders") +load("@fbcode_macros//build_defs:cpp_library.bzl", "cpp_library") +load("@fbcode_macros//build_defs:roar.bzl", "roar_no_jit") + +oncall("fbcode_entropy_wardens_folly") + +cpp_library( + name = "concurrent_bit_set", + headers = ["ConcurrentBitSet.h"], + exported_deps = [":portability"], +) + +cpp_library( + name = "atomic_hash_array", + headers = [ + "AtomicHashArray.h", + "AtomicHashArray-inl.h", + ], + exported_deps = [ + ":thread_cached_int", + ":utility", + "//folly/detail:atomic_hash_utils", + "//folly/detail:iterators", + "//folly/hash:hash", + "//folly/lang:bits", + "//folly/lang:exception", + ], +) + +cpp_library( + name = "atomic_hash_map", + headers = [ + "AtomicHashMap.h", + "AtomicHashMap-inl.h", + ], + exported_deps = [ + ":atomic_hash_array", + ":c_portability", + ":likely", + ":thread_cached_int", + "//folly/container:foreach", + "//folly/detail:atomic_hash_utils", + "//folly/detail:iterators", + "//folly/hash:hash", + ], +) + +cpp_library( + name = "atomic_linked_list", + headers = [ + "AtomicIntrusiveLinkedList.h", + "AtomicLinkedList.h", + ], + exported_deps = [":memory"], +) + +cpp_library( + name = "atomic_unordered_map", + headers = ["AtomicUnorderedMap.h"], + exported_deps = [ + ":conv", + ":likely", + ":random", + ":scope_guard", + ":traits", + "//folly/detail:atomic_unordered_map_utils", + "//folly/lang:bits", + "//folly/portability:sys_mman", + "//folly/portability:unistd", + ], +) + +cpp_library( + name = "base64", + headers = ["base64.h"], + exported_deps = [ + ":c_portability", + ":portability", + "//folly/detail/base64_detail:base64_api", + "//folly/detail/base64_detail:base64_common", + "//folly/lang:exception", + "//folly/memory:uninitialized_memory_hacks", + ], +) + +cpp_library( + name = "benchmark_util", + headers = [ + "BenchmarkUtil.h", + ], + exported_deps = [ + ":portability", + "//folly/lang:hint", + ], +) + +cpp_library( + name = "benchmark", + srcs = ["Benchmark.cpp"], + headers = ["Benchmark.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":file_util", + ":map_util", + ":string", + "//folly/detail:perf_scoped", + "//folly/json:dynamic", + ], + exported_deps = [ + ":benchmark_util", + ":portability", + ":preprocessor", + ":range", + ":scope_guard", + ":traits", + "//folly/functional:invoke", + "//folly/lang:hint", + "//folly/portability:gflags", + ], + external_deps = [ + ("boost", None, "boost_regex"), + ], + exported_external_deps = [ + "boost", + "glog", + ], +) + +cpp_library( + # @shim + name = "bits", + headers = ["Bits.h"], + exported_deps = ["//folly/lang:bits"], +) + +cpp_library( + name = "c_portability", + headers = ["CPortability.h"], + exported_deps = [ + "//folly/portability:config", + ], +) + +cpp_library( + name = "cancellation_token", + srcs = ["CancellationToken.cpp"], + headers = [ + "CancellationToken.h", + "CancellationToken-inl.h", + ], + compiler_flags = roar_no_jit(), + deps = [ + ":optional", + "//folly/synchronization/detail:sleeper", + ], + exported_deps = [ + ":cpp_attributes", + ":function", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "chrono", + headers = ["Chrono.h"], + exported_deps = [ + ":portability", + "//folly/lang:exception", + "//folly/portability:time", + ], +) + +cpp_library( + name = "clock_gettime_wrappers", + srcs = ["ClockGettimeWrappers.cpp"], + headers = ["ClockGettimeWrappers.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":c_portability", + ":likely", + ], + exported_deps = [ + "//folly/portability:time", + ], + external_deps = [ + ("glibc", None, "dl"), + ], + exported_external_deps = [ + ("glibc", None, "rt"), + ], +) + +cpp_library( + name = "concurrent_lazy", + headers = ["ConcurrentLazy.h"], + exported_deps = [ + "//folly/functional:invoke", + "//folly/synchronization:delayed_init", + ], +) + +cpp_library( + name = "concurrent_skip_list", + headers = [ + "ConcurrentSkipList.h", + "ConcurrentSkipList-inl.h", + ], + exported_deps = [ + ":constexpr_math", + ":likely", + ":memory", + ":thread_local", + "//folly/detail:iterators", + "//folly/synchronization:micro_spin_lock", + ], + exported_external_deps = [ + "glog", + ("boost", None, "boost_random"), + ], +) + +cpp_library( + name = "config", + # @fb-only: headers = ["folly-config.h"], + headers = ["//:folly-config.h"], # @oss-only + tags = ["oss_dependency"], # @oss-only +) + +cpp_library( + name = "constexpr_math", + headers = ["ConstexprMath.h"], + exported_deps = [ + ":portability", + "//folly/lang:checked_math", + "//folly/portability:constexpr", + ], +) + +cpp_library( + name = "constructor_callback_list", + headers = [ + "ConstructorCallbackList.h", + ], + exported_deps = [ + ":format", + ":function", + ":shared_mutex", + "//folly/detail:static_singleton_manager", + ], +) + +cpp_library( + name = "conv", + srcs = ["Conv.cpp"], + headers = ["Conv.h"], + compiler_flags = roar_no_jit(), + propagated_pp_flags = select({ + "//folly/buck_config:folly-conv-dtoa-to-chars": [ + # Use std::to_chars instead of libdouble-conversion for Double-To-ASCII conversions + "-DFOLLY_CONV_DTOA_TO_CHARS=1", + ], + "DEFAULT": [], + }) + select({ + "//folly/buck_config:folly-conv-atod-mode-fastfloat": [ + # Use fast_float::from_chars for ASCII-to-Double conversions + "-DFOLLY_CONV_ATOD_MODE=1", + ], + "DEFAULT": [], + }), + undefined_symbols = True, # TODO(T23121628): fix deps and remove + deps = [ + "fbsource//third-party/fast_float:fast_float", + "//folly/lang:safe_assert", + ], + exported_deps = [ + ":c_portability", + ":demangle", + ":expected", + ":fbstring", + ":likely", + ":portability", + ":range", + ":traits", + ":unit", + ":utility", + "//folly/lang:exception", + "//folly/lang:pretty", + "//folly/lang:to_ascii", + "//folly/portability:math", + ], + exported_external_deps = [ + "double_conversion", + ], +) + +cpp_library( + name = "cpp_attributes", + headers = ["CppAttributes.h"], + exported_deps = [":portability"], +) + +cpp_library( + name = "cpu_id", + headers = ["CpuId.h"], + exported_deps = [":portability"], +) + +cpp_library( + name = "default_keep_alive_executor", + headers = [ + "DefaultKeepAliveExecutor.h", + ], + exported_deps = [ + ":executor", + "//folly/executors:sequenced_executor", + "//folly/synchronization:baton", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "demangle", + srcs = ["Demangle.cpp"], + headers = ["Demangle.h"], + compiler_flags = roar_no_jit(), + os_deps = [( + "linux", + ["third-party//binutils:iberty"], + )], + deps = [ + ":c_portability", + ":cpp_attributes", + ":utility", + "//folly/functional:invoke", + "//folly/lang:c_string", + ], + exported_deps = [ + ":fbstring", + "//folly/portability:config", + ], +) + +cpp_library( + name = "discriminated_ptr", + headers = ["DiscriminatedPtr.h"], + exported_deps = [ + ":likely", + ":portability", + "//folly/detail:discriminated_ptr_detail", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "dynamic", + headers = [ + "DynamicConverter.h", + "dynamic.h", + "dynamic-inl.h", + "json.h", + ], + exported_deps = [ + "//folly/json:dynamic", + ], +) + +cpp_library( + name = "exception", + headers = ["Exception.h"], + exported_deps = [ + ":conv", + ":fbstring", + ":likely", + ":portability", + "//folly/portability:sys_types", + ], +) + +cpp_library( + name = "exception_string", + srcs = ["ExceptionString.cpp"], + headers = ["ExceptionString.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":demangle", + "//folly/lang:exception", + "//folly/lang:type_info", + ], + exported_deps = [ + ":fbstring", + ], +) + +cpp_library( + name = "exception_wrapper", + srcs = ["ExceptionWrapper.cpp"], + headers = [ + "ExceptionWrapper.h", + "ExceptionWrapper-inl.h", + ], + compiler_flags = roar_no_jit(), + undefined_symbols = True, # TODO(T23121628): fix deps and remove + deps = [ + ":glog", + ], + exported_deps = [ + ":c_portability", + ":cpp_attributes", + ":demangle", + ":exception_string", + ":fbstring", + ":portability", + ":traits", + ":utility", + "//folly/functional:traits", + "//folly/lang:assume", + "//folly/lang:exception", + ], +) + +cpp_library( + name = "executor", + srcs = ["Executor.cpp"], + headers = [ + "Executor.h", + ], + compiler_flags = roar_no_jit(), + deps = [ + ":exception_string", + ":portability", + ], + exported_deps = [ + ":function", + ":optional", + ":range", + ":utility", + "//folly/lang:exception", + ], + external_deps = [ + "glog", + ], +) + +cpp_library( + name = "expected", + headers = ["Expected.h"], + exported_deps = [ + ":c_portability", + ":cpp_attributes", + ":likely", + ":portability", + ":preprocessor", + ":traits", + ":unit", + ":utility", + "//folly/coro:coroutine", + "//folly/lang:exception", + "//folly/lang:hint", + ], +) + +cpp_library( + name = "fbstring", + headers = ["FBString.h"], + exported_deps = [ + "fbsource//third-party/fmt:fmt", + ":c_portability", + ":cpp_attributes", + ":likely", + ":portability", + ":traits", + "//folly/hash:hash", + "//folly/lang:assume", + "//folly/lang:checked_math", + "//folly/lang:exception", + "//folly/memory:malloc", + ], +) + +cpp_library( + name = "fbvector", + headers = [ + "FBVector.h", + ], + exported_deps = [ + "//folly/container:fbvector", + ], +) + +cpp_library( + name = "file", + srcs = ["File.cpp"], + headers = ["File.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":exception", + ":file_util", + ":scope_guard", + "//folly/portability:fmt_compile", + "//folly/portability:sys_file", + ], + exported_deps = [ + ":exception_wrapper", + ":expected", + ":file_util", # @manual + ":portability", + ":range", + "//folly/portability:fcntl", + "//folly/portability:unistd", + ], + external_deps = [ + "glog", + ], +) + +cpp_library( + name = "file_util", + srcs = ["FileUtil.cpp"], + headers = ["FileUtil.h"], + compiler_flags = roar_no_jit(), + deps = [ + "//folly/detail:file_util_detail", + "//folly/detail:file_util_vector_detail", + "//folly/net:net_ops", + "//folly/portability:sockets", + "//folly/portability:stdlib", + "//folly/portability:sys_file", + "//folly/portability:sys_stat", + ], + exported_deps = [ + ":portability", + ":range", + ":scope_guard", + "//folly/net:network_socket", + "//folly/portability:fcntl", + "//folly/portability:sys_uio", + "//folly/portability:unistd", + ], +) + +cpp_library( + name = "fingerprint", + srcs = ["Fingerprint.cpp"], + headers = ["Fingerprint.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":portability", + ":utility", + "//folly/detail:fingerprint_polynomial", + ], + exported_deps = [ + ":range", + ], +) + +cpp_library( + name = "fixed_string", + headers = ["FixedString.h"], + exported_deps = [ + ":constexpr_math", + ":portability", + ":range", + ":utility", + "//folly/lang:exception", + "//folly/lang:ordering", + "//folly/portability:constexpr", + ], +) + +cpp_library( + name = "format", + srcs = [ + "Format.cpp", + ], + headers = [ + "Format.h", + "Format-inl.h", + "FormatArg.h", + ], + compiler_flags = roar_no_jit(), + deps = [ + ":constexpr_math", + ":cpp_attributes", + "//folly/container:array", + ], + exported_deps = [ + ":c_portability", + ":conv", + ":exception", + ":format_traits", + ":likely", + ":map_util", + ":portability", + ":range", + ":string", + ":traits", + "//folly/lang:exception", + "//folly/lang:to_ascii", + "//folly/portability:windows", + ], + external_deps = [ + "double_conversion", + ], +) + +cpp_library( + name = "format_traits", + headers = ["FormatTraits.h"], +) + +cpp_library( + name = "function", + headers = ["Function.h"], + exported_deps = [ + ":cpp_attributes", + ":portability", + ":traits", + "//folly/functional:invoke", + "//folly/lang:align", + "//folly/lang:exception", + "//folly/lang:new", + ], +) + +cpp_library( + name = "group_varint", + srcs = [ + "GroupVarint.cpp", + ], + headers = ["GroupVarint.h"], + compiler_flags = roar_no_jit(), + deps = [ + "//folly/container:array", + ], + exported_deps = [ + ":portability", + ":range", + "//folly/detail:group_varint_detail", + "//folly/lang:bits", + "//folly/portability:builtins", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "hash", + headers = ["Hash.h"], + exported_deps = [ + "//folly/hash:hash", + ], +) + +cpp_library( + name = "indestructible", + headers = ["Indestructible.h"], + exported_deps = [ + ":traits", + ":utility", + ], +) + +cpp_library( + name = "indexed_mem_pool", + headers = ["IndexedMemPool.h"], + exported_deps = [ + ":portability", + "//folly/concurrency:cache_locality", + "//folly/portability:sys_mman", + "//folly/portability:unistd", + "//folly/synchronization:atomic_struct", + ], +) + +cpp_library( + name = "intrusive_list", + headers = [ + "IntrusiveList.h", + ], + exported_deps = [ + "//folly/container:intrusive_list", + ], +) + +cpp_library( + name = "json", + exported_deps = [ + ":dynamic", + ], +) + +cpp_library( + name = "json_pointer", + headers = [ + "json_pointer.h", + ], + exported_deps = [ + "//folly/json:json_pointer", + ], +) + +cpp_library( + name = "json_patch", + headers = [ + "json_patch.h", + ], + exported_deps = [ + "//folly/json:json_patch", + ], +) + +cpp_library( + name = "lazy", + headers = ["Lazy.h"], + exported_deps = [ + ":optional", + "//folly/functional:invoke", + ], +) + +cpp_library( + name = "likely", + headers = ["Likely.h"], + exported_deps = [ + "//folly/lang:builtin", + ], +) + +cpp_library( + name = "glog", + headers = ["GLog.h"], + exported_deps = [ + ":likely", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "map_util", + headers = [ + "MapUtil.h", + ], + exported_deps = [ + "//folly/container:map_util", + ], +) + +cpp_library( + name = "math", + headers = ["Math.h"], +) + +cpp_library( + name = "memset-impl", + srcs = [ + "FollyMemset.cpp", + ] + select({ + "DEFAULT": [], + "ovr_config//cpu:x86_64": [ + "memset.S", + ], + "ovr_config//os:linux-arm64": [ + "memset_select_aarch64.cpp", + ], + }), + auto_headers = AutoHeaders.NONE, + headers = [], + arch_preprocessor_flags = { + "x86_64": [ + "-mavx2", + ], + }, + compiler_flags = roar_no_jit(), + modular_headers = False, + exported_deps = select({ + "DEFAULT": [], + "ovr_config//os:linux-arm64": [ + "//folly/external/aor:memset_aarch64", # @manual + ], + }), +) + +# This exports the symbol __folly_memset to C++ via a header. +cpp_library( + name = "memset", + headers = ["FollyMemset.h"], + exported_deps = [ + ":memset-impl", # @manual + ], +) + +# This overrides the libc memset with __folly_memset. +cpp_library( + name = "memset-use", + srcs = [ + "FollyMemset.cpp", + ] + select({ + "DEFAULT": [], + "ovr_config//cpu:x86_64": [ + "memset.S", + ], + "ovr_config//os:linux-arm64": [ + "memset_select_aarch64.cpp", + ], + }), + auto_headers = AutoHeaders.NONE, + headers = [], + arch_preprocessor_flags = { + "aarch64": [ + "-DFOLLY_MEMSET_IS_MEMSET", + ], + "x86_64": [ + "-DFOLLY_MEMSET_IS_MEMSET", + "-mavx2", + ], + }, + compiler_flags = roar_no_jit(), + link_whole = True, # Set link_whole to force linker to use __folly_memset + modular_headers = False, + exported_deps = select({ + "DEFAULT": [], + "ovr_config//os:linux-arm64": [ + "//folly/external/aor:memset_aarch64-use", # @manual + ], + }), +) + +# This adds the symbol __folly_memcpy but does not replace the default memcpy. +cpp_library( + name = "memcpy-impl", + srcs = [ + "FollyMemcpy.cpp", + ] + select({ + "ovr_config//cpu:x86_64": [ + "memcpy.S", + ], + "ovr_config//os:linux-arm64": [ + "memcpy_select_aarch64.cpp", + ], + }), + auto_headers = AutoHeaders.NONE, + headers = [], + arch_preprocessor_flags = { + "x86_64": [ + "-mavx2", + ], + }, + compiler_flags = roar_no_jit(), + modular_headers = False, + exported_deps = select({ + "DEFAULT": [], + "ovr_config//os:linux-arm64": [ + "//folly/external/aor:memcpy_aarch64", # @manual + ], + }), +) + +# This exports the symbol __folly_memcpy to C++ via a header. +cpp_library( + name = "memcpy", + headers = ["FollyMemcpy.h"], + exported_deps = [ + ":memcpy-impl", # @manual + ], +) + +# This overrides the libc memcpy with __folly_memcpy. +cpp_library( + name = "memcpy-use", + srcs = [ + "FollyMemcpy.cpp", + ] + select({ + "DEFAULT": [], + "ovr_config//cpu:x86_64": [ + "memcpy.S", + ], + "ovr_config//os:linux-arm64": [ + "memcpy_select_aarch64.cpp", + ], + }), + auto_headers = AutoHeaders.NONE, + headers = [], + arch_preprocessor_flags = { + "aarch64": [ + "-DFOLLY_MEMCPY_IS_MEMCPY", + ], + "x86_64": [ + "-DFOLLY_MEMCPY_IS_MEMCPY", + "-mavx2", + "-march=haswell", + ], + }, + compiler_flags = roar_no_jit(), + link_whole = True, # Set link_whole to force linker to use __folly_memcpy + modular_headers = False, + exported_deps = select({ + "DEFAULT": [], + "ovr_config//os:linux-arm64": [ + "//folly/external/aor:memcpy_aarch64-use", # @manual + ], + }), +) + +cpp_library( + name = "memory", + headers = ["Memory.h"], + exported_deps = [ + ":constexpr_math", + ":likely", + ":portability", + ":traits", + ":utility", + "//folly/functional:invoke", + "//folly/lang:align", + "//folly/lang:exception", + "//folly/lang:thunk", + "//folly/memory:malloc", + "//folly/portability:config", + "//folly/portability:constexpr", + "//folly/portability:malloc", + ], +) + +cpp_library( + name = "micro_lock", + srcs = ["MicroLock.cpp"], + headers = ["MicroLock.h"], + compiler_flags = roar_no_jit(), + deps = [ + "//folly/portability:asm", + ], + exported_deps = [ + ":optional", + ":portability", + "//folly/detail:futex", + ], +) + +cpp_library( + # @shim + name = "micro_spin_lock", + headers = ["MicroSpinLock.h"], + exported_deps = ["//folly/synchronization:micro_spin_lock"], +) + +cpp_library( + name = "move_wrapper", + headers = ["MoveWrapper.h"], +) + +cpp_library( + name = "mpmc_pipeline", + headers = ["MPMCPipeline.h"], + exported_deps = [ + ":portability", + "//folly/detail:mpmc_pipeline_detail", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "mpmc_queue", + headers = ["MPMCQueue.h"], + exported_deps = [ + ":traits", + "//folly/concurrency:cache_locality", + "//folly/detail:turn_sequencer", + "//folly/portability:unistd", + ], +) + +cpp_library( + name = "network_address", + srcs = [ + "IPAddress.cpp", + "IPAddressV4.cpp", + "IPAddressV6.cpp", + "MacAddress.cpp", + "SocketAddress.cpp", + ], + headers = [ + "IPAddress.h", + "IPAddressException.h", + "IPAddressV4.h", + "IPAddressV6.h", + "MacAddress.h", + "SocketAddress.h", + ], + compiler_flags = roar_no_jit(), + deps = [ + "fbsource//third-party/fmt:fmt", + ":exception", + ":format", + ":scope_guard", + ":small_vector", + ":string", + "//folly/detail:ip_address_source", + "//folly/net:net_ops", + ], + exported_deps = [ + ":c_portability", + ":constexpr_math", + ":conv", + ":expected", + ":fbstring", + ":optional", + ":portability", + ":range", + ":unit", + "//folly/detail:ip_address", + "//folly/hash:hash", + "//folly/lang:bits", + "//folly/lang:exception", + "//folly/net:network_socket", + "//folly/portability:sockets", + ], + external_deps = [ + "boost", + ], +) + +cpp_library( + name = "observer_container", + headers = [ + "ObserverContainer.h", + ], + exported_deps = [ + ":constructor_callback_list", + ":function", + ":optional", + ":scope_guard", + ":small_vector", + "//folly/io/async:destructor_check", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "optional", + headers = ["Optional.h"], + exported_deps = [ + ":portability", + ":traits", + ":utility", + "//folly/coro:coroutine", + "//folly/hash:traits", + "//folly/lang:exception", + ], +) + +cpp_library( + name = "replaceable", + headers = [ + "Replaceable.h", + ], + exported_deps = [ + ":portability", + ":traits", + ":utility", + ], +) + +cpp_library( + name = "overload", + headers = ["Overload.h"], + exported_deps = [ + ":portability", + ":traits", + "//folly/functional:invoke", + ], +) + +cpp_library( + name = "packed_sync_ptr", + headers = ["PackedSyncPtr.h"], + exported_deps = [ + ":portability", + "//folly/synchronization:small_locks", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "padded", + headers = ["Padded.h"], + exported_deps = [ + ":portability", + ":traits", + "//folly/functional:invoke", + "//folly/portability:sys_types", + ], + exported_external_deps = [ + "boost", + ], +) + +cpp_library( + name = "portability", + headers = ["Portability.h"], + exported_deps = [ + ":c_portability", + "//folly/portability:config", + ], +) + +cpp_library( + name = "preprocessor", + headers = ["Preprocessor.h"], + exported_deps = [ + ":c_portability", + ], +) + +cpp_library( + name = "poly", + headers = [ + "Poly.h", + "Poly-inl.h", + ], + exported_deps = [ + ":c_portability", + ":cpp_attributes", + ":poly_exception", + ":traits", + "//folly/detail:poly_detail", + "//folly/detail:typelist", + "//folly/lang:assume", + ], +) + +cpp_library( + name = "poly_exception", + headers = ["PolyException.h"], + exported_deps = [ + "//folly:c_portability", + ], +) + +cpp_library( + name = "producer_consumer_queue", + headers = ["ProducerConsumerQueue.h"], + exported_deps = [ + "//folly/concurrency:cache_locality", + ], +) + +cpp_library( + name = "random", + srcs = [ + "Random.cpp", + ], + headers = [ + "Random.h", + "Random-inl.h", + ], + compiler_flags = roar_no_jit(), + os_deps = [( + "windows", + [ + "fbsource//third-party/toolchains/win:advapi32.lib", + ], + )], + deps = [ + ":cpp_attributes", + ":singleton_thread_local", + ":thread_local", + "//folly/detail:file_util_detail", + "//folly/portability:config", + "//folly/portability:sys_time", + "//folly/portability:unistd", + "//folly/synchronization:relaxed_atomic", + ], + exported_deps = [ + ":portability", + ":traits", + "//folly/functional:invoke", + "//folly/lang:bits", + ], + external_deps = [ + "glog", + ], +) + +cpp_library( + name = "range", + headers = ["Range.h"], + exported_deps = [ + "fbsource//third-party/fmt:fmt", + ":cpu_id", + ":likely", + ":portability", + ":traits", + "//folly/detail:range_common", + "//folly/detail:range_sse42", + "//folly/hash:spooky_hash_v2", + "//folly/lang:c_string", + "//folly/lang:exception", + "//folly/portability:constexpr", + ], +) + +cpp_library( + # @shim + name = "rw_spin_lock", + headers = ["RWSpinLock.h"], + exported_deps = ["//folly/synchronization:rw_spin_lock"], +) + +cpp_library( + name = "scope_guard", + srcs = ["ScopeGuard.cpp"], + headers = ["ScopeGuard.h"], + compiler_flags = roar_no_jit(), + exported_deps = [ + ":portability", + ":preprocessor", + ":utility", + "//folly/lang:exception", + "//folly/lang:uncaught_exceptions", + ], +) + +cpp_library( + name = "shared_mutex", + srcs = ["SharedMutex.cpp"], + headers = ["SharedMutex.h"], + compiler_flags = roar_no_jit(), + supports_python_dlopen = True, + deps = [ + ":indestructible", + "//folly/lang:exception", + "//folly/portability:sys_resource", + ], + exported_deps = [ + ":c_portability", + ":cpp_attributes", + ":likely", + "//folly/chrono:hardware", + "//folly/concurrency:cache_locality", + "//folly/detail:futex", + "//folly/portability:asm", + "//folly/synchronization:lock", + "//folly/synchronization:relaxed_atomic", + "//folly/synchronization:sanitize_thread", + "//folly/system:thread_id", + ], +) + +cpp_library( + name = "singleton", + srcs = [ + "Singleton.cpp", + ], + headers = [ + "Singleton.h", + "Singleton-inl.h", + ], + compiler_flags = roar_no_jit(), + deps = [ + "fbsource//third-party/fmt:fmt", + ":demangle", + ":scope_guard", + "//folly/experimental/symbolizer:symbolizer", + "//folly/lang:safe_assert", + "//folly/portability:config", + "//folly/portability:fmt_compile", + ], + exported_deps = [ + ":cancellation_token", + ":exception", + ":executor", + ":memory", + ":synchronized", + "//folly/concurrency:core_cached_shared_ptr", + "//folly/concurrency/memory:read_mostly_shared_ptr", + "//folly/detail:singleton", + "//folly/detail:static_singleton_manager", + "//folly/hash:hash", + "//folly/lang:exception", + "//folly/memory:sanitize_leak", + "//folly/synchronization:baton", + ], + external_deps = [ + ("glibc", None, "dl"), + ("glibc", None, "rt"), + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "singleton_thread_local", + srcs = ["SingletonThreadLocal.cpp"], + headers = ["SingletonThreadLocal.h"], + compiler_flags = roar_no_jit(), + exported_deps = [ + ":scope_guard", + ":thread_local", + "//folly/detail:iterators", + "//folly/detail:singleton", + "//folly/detail:unique_instance", + "//folly/functional:invoke", + "//folly/lang:hint", + ], +) + +cpp_library( + name = "small_vector", + headers = [ + "small_vector.h", + ], + exported_deps = [ + "//folly/container:small_vector", + ], +) + +cpp_library( + name = "sorted_vector_types", + headers = [ + "sorted_vector_types.h", + ], + exported_deps = [ + "//folly/container:sorted_vector_types", + ], +) + +cpp_library( + name = "spin_lock", + headers = [ + "SpinLock.h", + ], + exported_deps = [ + ":portability", + "//folly/synchronization:small_locks", + ], +) + +cpp_library( + name = "stop_watch", + headers = ["stop_watch.h"], + exported_deps = [ + ":chrono", + ":utility", + "//folly/portability:time", + ], +) + +cpp_library( + name = "string", + srcs = [ + "String.cpp", + ], + headers = [ + "String.h", + "String-inl.h", + ], + compiler_flags = roar_no_jit(), + deps = [ + "//folly/container:array", + ], + exported_deps = [ + ":conv", + ":cpp_attributes", + ":exception_string", + ":optional", + ":portability", + ":range", + ":scope_guard", + ":traits", + ":unit", + "//folly/container:reserve", + "//folly/detail:simple_simd_string_utils", + "//folly/detail:split_string_simd", + ], + external_deps = [ + "glog", + ], +) + +cpp_library( + name = "subprocess", + srcs = ["Subprocess.cpp"], + headers = ["Subprocess.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":conv", + ":scope_guard", + ":string", + "//folly/lang:assume", + "//folly/logging:logging", + "//folly/portability:dirent", + "//folly/portability:fcntl", + "//folly/portability:sockets", + "//folly/portability:stdlib", + "//folly/portability:sys_syscall", + "//folly/portability:unistd", + "//folly/system:at_fork", + "//folly/system:shell", + ], + exported_deps = [ + ":exception", + ":file", + ":file_util", + ":function", + ":map_util", + ":optional", + ":portability", + ":range", + "//folly/gen:string", + "//folly/io:iobuf", + "//folly/portability:sys_resource", + ], + external_deps = [ + ("boost", None, "boost_range"), + ], + exported_external_deps = [ + "boost", + ("boost", None, "boost_container"), + ], +) + +cpp_library( + name = "synchronized", + headers = ["Synchronized.h"], + exported_deps = [ + ":function", + ":likely", + ":preprocessor", + ":shared_mutex", + ":traits", + ":utility", + "//folly/container:foreach", + "//folly/functional:apply_tuple", + "//folly/synchronization:lock", + ], + exported_external_deps = [ + "glog", + ], +) + +cpp_library( + name = "synchronized_ptr", + headers = ["SynchronizedPtr.h"], + exported_deps = [":synchronized"], +) + +cpp_library( + name = "thread_cached_int", + headers = ["ThreadCachedInt.h"], + exported_deps = [ + ":likely", + ":thread_local", + ], +) + +cpp_library( + name = "thread_local", + headers = ["ThreadLocal.h"], + exported_deps = [ + ":likely", + ":portability", + ":scope_guard", + ":shared_mutex", + "//folly/detail:thread_local_detail", + ], +) + +cpp_library( + name = "timeout_queue", + srcs = ["TimeoutQueue.cpp"], + headers = ["TimeoutQueue.h"], + compiler_flags = roar_no_jit(), + exported_external_deps = [ + "boost", + ("boost", None, "boost_multi_index"), + ], +) + +cpp_library( + name = "token_bucket", + headers = ["TokenBucket.h"], + exported_deps = [ + ":constexpr_math", + ":likely", + ":optional", + "//folly/concurrency:cache_locality", + ], +) + +cpp_library( + name = "traits", + headers = ["Traits.h"], + exported_deps = [":portability"], +) + +cpp_library( + name = "try", + srcs = [ + "Try.cpp", + ], + headers = [ + "Try.h", + "Try-inl.h", + ], + compiler_flags = roar_no_jit(), + exported_deps = [ + ":exception_wrapper", + ":likely", + ":memory", + ":portability", + ":unit", + ":utility", + "//folly/functional:invoke", + "//folly/lang:exception", + ], +) + +cpp_library( + name = "unicode", + srcs = ["Unicode.cpp"], + headers = ["Unicode.h"], + compiler_flags = roar_no_jit(), + deps = [ + ":conv", + ], + exported_deps = [ + "//folly/lang:exception", + ], +) + +cpp_library( + name = "unit", + headers = ["Unit.h"], +) + +cpp_library( + name = "uri", + srcs = [ + "Uri.cpp", + ], + headers = [ + "Uri.h", + "Uri-inl.h", + ], + compiler_flags = roar_no_jit(), + exported_deps = [ + ":conv", + ":expected", + ":string", + "//folly/hash:hash", + ], + external_deps = [ + ("boost", None, "boost_regex"), + ], +) + +cpp_library( + name = "utf8_string", + headers = [ + "UTF8String.h", + ], + exported_deps = [ + ":range", + ], + exported_external_deps = [ + ("boost", None, "boost_regex"), + ], +) + +# For things that would go in c++ stdlib : +cpp_library( + name = "utility", + headers = [ + "Utility.h", + ], + exported_deps = [ + ":c_portability", + ":portability", + ":traits", + ], +) + +cpp_library( + name = "varint", + headers = ["Varint.h"], + exported_deps = [ + ":conv", + ":expected", + ":likely", + ":portability", + ":range", + ], +) + +cpp_library( + name = "virtual_executor", + headers = [ + "VirtualExecutor.h", + ], + exported_deps = [ + "//folly/executors:virtual_executor", + ], +) + +cpp_library( + name = "maybe_managed_ptr", + headers = ["MaybeManagedPtr.h"], + deps = [ + ], + exported_deps = [ + ], +) diff --git a/vnext/external/folly/folly/BUILD_MODE.bzl b/vnext/external/folly/folly/BUILD_MODE.bzl new file mode 100644 index 00000000000..0fb607dcd61 --- /dev/null +++ b/vnext/external/folly/folly/BUILD_MODE.bzl @@ -0,0 +1,72 @@ +""" build mode definitions for folly """ + +load("@fbcode//:BUILD_MODE.bzl", get_parent_modes = "get_empty_modes") +load("@fbcode_macros//build_defs:create_build_mode.bzl", "extend_build_modes") + +_extra_cflags = [ + "-Wsign-compare", + "-Wunused-parameter", +] + +_extra_cxxflags = [ +] + +_extra_clang_flags = [ + "-Wconditional-uninitialized", + "-Wconstant-conversion", + "-Wdeprecated-declarations", + "-Wextra", + "-Wextra-semi", + "-Wexceptions", + "-Wfloat-conversion", + "-Wgnu-conditional-omitted-operand", + "-Wheader-hygiene", + "-Wimplicit-fallthrough", + "-Wmismatched-tags", + "-Wmissing-braces", + "-Wmissing-noreturn", + "-Wshadow", + "-Wshift-sign-overflow", + "-Wsometimes-uninitialized", + "-Wuninitialized", + "-Wuninitialized-const-reference", + "-Wunused-const-variable", + "-Wunused-exception-parameter", + "-Wunused-function", + "-Wunused-lambda-capture", + "-Wunused-value", + "-Wunused-variable", + "-Wswitch-enum", +] + +_extra_gcc_flags = [ + "-Wdeprecated-declarations", + "-Wmaybe-uninitialized", + "-Wmissing-braces", + "-Wshadow", + "-Wuninitialized", + "-Wunused-but-set-variable", +] + +_extra_asan_options = { + "detect_leaks": "1", + "detect_odr_violation": "2", +} + +_tags = [ +] + +_modes = extend_build_modes( + get_parent_modes(), + asan_options = _extra_asan_options, + c_flags = _extra_cflags, + clang_flags = _extra_clang_flags, + cxx_flags = _extra_cxxflags, + cxx_modular_headers = True, + gcc_flags = _extra_gcc_flags, + tags = _tags, +) + +def get_modes(): + """ Return modes for this file """ + return _modes diff --git a/vnext/external/folly/folly/Benchmark.cpp b/vnext/external/folly/folly/Benchmark.cpp new file mode 100644 index 00000000000..02ad816a059 --- /dev/null +++ b/vnext/external/folly/folly/Benchmark.cpp @@ -0,0 +1,986 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +// This needs to be at the end because some versions end up including +// Windows.h without defining NOMINMAX, which breaks uses +// of `std::numeric_limits::max()`. We explicitly define NOMINMAX here +// explicitly instead. +#define NOMINMAX 1 +#include + +using namespace std; + +FOLLY_GFLAGS_DEFINE_bool(benchmark, false, "Run benchmarks."); + +FOLLY_GFLAGS_DEFINE_bool(json, false, "Output in JSON format."); + +FOLLY_GFLAGS_DEFINE_bool(bm_estimate_time, false, "Estimate running time"); + +#if FOLLY_PERF_IS_SUPPORTED +FOLLY_GFLAGS_DEFINE_string( + bm_perf_args, + "", + "Run selected benchmarks while attaching `perf` profiling tool." + "Advantage over attaching perf externally is that this skips " + "initialization. The first iteration of the benchmark is also " + "skipped to allow for all statics to be set up. This requires perf " + " to be available on the system. Example: --bm_perf_args=\"record -g\""); +#endif + +FOLLY_GFLAGS_DEFINE_bool( + bm_profile, false, "Run benchmarks with constant number of iterations"); + +FOLLY_GFLAGS_DEFINE_int64( + bm_profile_iters, 1000, "Number of iterations for profiling"); + +FOLLY_GFLAGS_DEFINE_string( + bm_relative_to, + "", + "Print benchmark results relative to an earlier dump (via --bm_json_verbose)"); + +FOLLY_GFLAGS_DEFINE_bool( + bm_warm_up_iteration, + false, + "Run one iteration of the benchmarks before measuring. Always true if `bm_perf_args` is passed"); + +FOLLY_GFLAGS_DEFINE_string( + bm_json_verbose, + "", + "File to write verbose JSON format (for BenchmarkCompare / --bm_relative_to). " + "NOTE: this file is written regardless of options --json and --bm_relative_to."); + +FOLLY_GFLAGS_DEFINE_string( + bm_regex, "", "Only benchmarks whose names match this regex will be run."); + +FOLLY_GFLAGS_DEFINE_string( + bm_file_regex, + "", + "Only benchmarks whose filenames match this regex will be run."); + +FOLLY_GFLAGS_DEFINE_int64( + bm_min_usec, + 100, + "Minimum # of microseconds we'll accept for each benchmark."); + +FOLLY_GFLAGS_DEFINE_int32( + bm_min_iters, 1, "Minimum # of iterations we'll try for each benchmark."); + +FOLLY_GFLAGS_DEFINE_int64( + bm_max_iters, + 1 << 30, + "Maximum # of iterations we'll try for each benchmark."); + +FOLLY_GFLAGS_DEFINE_int32( + bm_max_secs, 1, "Maximum # of seconds we'll spend on each benchmark."); + +FOLLY_GFLAGS_DEFINE_uint32( + bm_result_width_chars, 76, "Width of results table in characters"); + +FOLLY_GFLAGS_DEFINE_uint32( + bm_max_trials, + 1000, + "Maximum number of trials (iterations) executed for each benchmark."); + +FOLLY_GFLAGS_DEFINE_bool( + bm_list, + false, + "Print out list of all benchmark test names without running them."); + +namespace folly { +namespace detail { + +BenchmarkingState& globalBenchmarkState() { + static detail::BenchmarkingState state; + return state; +} + +} // namespace detail + +using BenchmarkFun = std::function; + +#define FB_FOLLY_GLOBAL_BENCHMARK_BASELINE fbFollyGlobalBenchmarkBaseline +#define FB_STRINGIZE_X2(x) FOLLY_PP_STRINGIZE(x) + +constexpr const char kGlobalBenchmarkBaseline[] = + FB_STRINGIZE_X2(FB_FOLLY_GLOBAL_BENCHMARK_BASELINE); + +// Add the global baseline +BENCHMARK(FB_FOLLY_GLOBAL_BENCHMARK_BASELINE) { +#ifdef _MSC_VER + _ReadWriteBarrier(); +#else + asm volatile(""); +#endif +} + +#undef FB_STRINGIZE_X2 +#undef FB_FOLLY_GLOBAL_BENCHMARK_BASELINE + +static std::pair runBenchmarkGetNSPerIteration( + const BenchmarkFun& fun, const double globalBaseline) { + using std::chrono::duration_cast; + using std::chrono::high_resolution_clock; + using std::chrono::microseconds; + using std::chrono::nanoseconds; + using std::chrono::seconds; + + // They key here is accuracy; too low numbers means the accuracy was + // coarse. We up the ante until we get to at least minNanoseconds + // timings. + static_assert( + std::is_same::value, + "High resolution clock must be nanosecond resolution."); + // We choose a minimum minimum (sic) of 100,000 nanoseconds, but if + // the clock resolution is worse than that, it will be larger. In + // essence we're aiming at making the quantization noise 0.01%. + static const auto minNanoseconds = std::max( + nanoseconds(100000), microseconds(FLAGS_bm_min_usec)); + + // We establish a total time budget as we don't want a measurement + // to take too long. This will curtail the number of actual trials. + const auto timeBudget = seconds(FLAGS_bm_max_secs); + auto global = high_resolution_clock::now(); + + std::vector> trialResults( + FLAGS_bm_max_trials); + size_t actualTrials = 0; + + // We do measurements in several trials (epochs) and take the minimum, to + // account for jitter. + for (; actualTrials < FLAGS_bm_max_trials; ++actualTrials) { + const auto maxIters = uint32_t(FLAGS_bm_max_iters); + for (auto n = uint32_t(FLAGS_bm_min_iters); n < maxIters; n *= 2) { + detail::TimeIterData timeIterData = fun(static_cast(n)); + if (timeIterData.duration < minNanoseconds) { + continue; + } + // We got an accurate enough timing, done. But only save if + // smaller than the current result. + auto nsecs = duration_cast(timeIterData.duration); + trialResults[actualTrials] = std::make_pair( + max(0.0, double(nsecs.count()) / timeIterData.niter - globalBaseline), + std::move(timeIterData.userCounters)); + // Done with the current trial, we got a meaningful timing. + break; + } + auto now = high_resolution_clock::now(); + if (now - global >= timeBudget) { + // No more time budget available. + ++actualTrials; + break; + } + } + + // Current state of the art: get the minimum. After some + // experimentation, it seems taking the minimum is the best. + auto iter = min_element( + trialResults.begin(), + trialResults.begin() + actualTrials, + [](const auto& a, const auto& b) { return a.first < b.first; }); + + // If the benchmark was basically drowned in baseline noise, it's + // possible it became negative. + return std::make_pair(max(0.0, iter->first), iter->second); +} + +static std::pair runBenchmarkGetNSPerIterationEstimate( + const BenchmarkFun& fun, const double globalBaseline) { + using std::chrono::duration_cast; + using std::chrono::high_resolution_clock; + using std::chrono::microseconds; + using std::chrono::nanoseconds; + using std::chrono::seconds; + using TrialResultType = std::pair; + + // They key here is accuracy; too low numbers means the accuracy was + // coarse. We up the ante until we get to at least minNanoseconds + // timings. + static_assert( + std::is_same::value, + "High resolution clock must be nanosecond resolution."); + + // Estimate single iteration running time for 1 sec + double estPerIter = 0.0; // Estimated nanosec per iteration + auto estStart = high_resolution_clock::now(); + const auto estBudget = seconds(1); + for (auto n = 1; n < 1000; n *= 2) { + detail::TimeIterData timeIterData = fun(static_cast(n)); + auto now = high_resolution_clock::now(); + auto nsecs = duration_cast(timeIterData.duration); + estPerIter = double(nsecs.count() - globalBaseline) / n; + if (now - estStart > estBudget) { + break; + } + } + // Can't estimate running time, so make it a baseline + if (estPerIter <= 0.0) { + estPerIter = globalBaseline; + } + + // We do measurements in several trials (epochs) to account for jitter. + size_t actualTrials = 0; + const unsigned int estimateCount = to_integral(max(1.0, 5e+7 / estPerIter)); + std::vector trialResults(FLAGS_bm_max_trials); + const auto maxRunTime = seconds(5); + auto globalStart = high_resolution_clock::now(); + + // Run benchmark up to trial times with at least 0.5 sec each + // Or until we run out of alowed time (5sec) + for (size_t tryId = 0; tryId < FLAGS_bm_max_trials; tryId++) { + detail::TimeIterData timeIterData = fun(estimateCount); + auto nsecs = duration_cast(timeIterData.duration); + + if (nsecs.count() > globalBaseline) { + auto nsecIter = + double(nsecs.count() - globalBaseline) / timeIterData.niter; + trialResults[actualTrials++] = + std::make_pair(nsecIter, std::move(timeIterData.userCounters)); + } + // Check if we are out of time quota + auto now = high_resolution_clock::now(); + if (now - globalStart > maxRunTime) { + break; + } + } + + // Sort results by running time + std::sort( + trialResults.begin(), + trialResults.begin() + actualTrials, + [](const TrialResultType& a, const TrialResultType& b) { + return a.first < b.first; + }); + + const auto getPercentile = [](size_t count, double p) -> size_t { + return static_cast(count * p); + }; + + const size_t trialP25 = getPercentile(actualTrials, 0.25); + const size_t trialP75 = getPercentile(actualTrials, 0.75); + if (trialP75 - trialP25 == 0) { + // Use first trial results if p75 == p25. + return std::make_pair(trialResults[0].first, trialResults[0].second); + } + + double geomeanNsec = 0.0; + for (size_t tryId = trialP25; tryId < trialP75; tryId++) { + geomeanNsec += std::log(trialResults[tryId].first); + } + geomeanNsec = std::exp(geomeanNsec / (1.0 * (trialP75 - trialP25))); + + return std::make_pair( + geomeanNsec, trialResults[trialP25 + (trialP75 - trialP25) / 2].second); +} + +static std::pair runProfilingGetNSPerIteration( + const BenchmarkFun& fun, const double globalBaseline) { + using std::chrono::duration_cast; + using std::chrono::high_resolution_clock; + using std::chrono::nanoseconds; + + // They key here is accuracy; too low numbers means the accuracy was + // coarse. We up the ante until we get to at least minNanoseconds + // timings. + static_assert( + std::is_same::value, + "High resolution clock must be nanosecond resolution."); + + // This is a very simple measurement with a single epoch + // and should be used only for profiling purposes + detail::TimeIterData timeIterData = fun(FLAGS_bm_profile_iters); + + auto nsecs = duration_cast(timeIterData.duration); + auto nsecIter = double(nsecs.count()) / timeIterData.niter - globalBaseline; + return std::make_pair(nsecIter, std::move(timeIterData.userCounters)); +} + +struct ScaleInfo { + double boundary; + const char* suffix; +}; + +static const ScaleInfo kTimeSuffixes[]{ + {365.25 * 24 * 3600, "years"}, + {24 * 3600, "days"}, + {3600, "hr"}, + {60, "min"}, + {1, "s"}, + {1E-3, "ms"}, + {1E-6, "us"}, + {1E-9, "ns"}, + {1E-12, "ps"}, + {1E-15, "fs"}, + {0, nullptr}, +}; + +static const ScaleInfo kMetricSuffixes[]{ + {1E24, "Y"}, // yotta + {1E21, "Z"}, // zetta + {1E18, "X"}, // "exa" written with suffix 'X' so as to not create + // confusion with scientific notation + {1E15, "P"}, // peta + {1E12, "T"}, // terra + {1E9, "G"}, // giga + {1E6, "M"}, // mega + {1E3, "K"}, // kilo + {1, ""}, + {1E-3, "m"}, // milli + {1E-6, "u"}, // micro + {1E-9, "n"}, // nano + {1E-12, "p"}, // pico + {1E-15, "f"}, // femto + {1E-18, "a"}, // atto + {1E-21, "z"}, // zepto + {1E-24, "y"}, // yocto + {0, nullptr}, +}; + +static string humanReadable( + double n, unsigned int decimals, const ScaleInfo* scales) { + if (std::isinf(n) || std::isnan(n)) { + return folly::to(n); + } + + const double absValue = fabs(n); + const ScaleInfo* scale = scales; + while (absValue < scale[0].boundary && scale[1].suffix != nullptr) { + ++scale; + } + + const double scaledValue = n / scale->boundary; + return stringPrintf("%.*f%s", decimals, scaledValue, scale->suffix); +} + +static string readableTime(double n, unsigned int decimals) { + return humanReadable(n, decimals, kTimeSuffixes); +} + +static string metricReadable(double n, unsigned int decimals) { + return humanReadable(n, decimals, kMetricSuffixes); +} + +namespace { + +constexpr std::string_view kUnitHeaders = "relative time/iter iters/s"; +constexpr std::string_view kUnitHeadersPadding = " "; +void printHeaderContents(std::string_view file) { + printf( + "%-.*s%*s%*s", + static_cast(file.size()), + file.data(), + static_cast(kUnitHeadersPadding.size()), + kUnitHeadersPadding.data(), + static_cast(kUnitHeaders.size()), + kUnitHeaders.data()); +} + +void printDefaultHeaderContents(std::string_view file, size_t columns) { + const size_t maxFileNameChars = + columns - kUnitHeaders.size() - kUnitHeadersPadding.size(); + + if (file.size() <= maxFileNameChars) { + printHeaderContents(file); + } else { + std::string truncatedFile = std::string(file.begin(), file.end()); + constexpr std::string_view overflowFilePrefix = "[...]"; + const auto overflow = truncatedFile.size() - maxFileNameChars; + truncatedFile.erase(0, overflow); + truncatedFile.replace(0, overflowFilePrefix.size(), overflowFilePrefix); + printHeaderContents(truncatedFile); + } +} + +void printSeparator(char pad, unsigned int columns) { + puts(string(columns, pad).c_str()); +} + +class BenchmarkResultsPrinter { + public: + BenchmarkResultsPrinter() : columns_(FLAGS_bm_result_width_chars) {} + explicit BenchmarkResultsPrinter(std::set counterNames) + : counterNames_(std::move(counterNames)), + namesLength_{std::accumulate( + counterNames_.begin(), + counterNames_.end(), + size_t{0}, + [](size_t acc, auto&& name) { return acc + 2 + name.length(); })}, + columns_(FLAGS_bm_result_width_chars + namesLength_) {} + + void separator(char pad) { printSeparator(pad, columns_); } + + void header(std::string_view file) { + separator('='); + printDefaultHeaderContents(file, columns_); + for (auto const& name : counterNames_) { + printf(" %s", name.c_str()); + } + printf("\n"); + separator('='); + } + + void print(const vector& data) { + for (auto& datum : data) { + auto file = datum.file; + if (file != lastFile_) { + // New file starting + header(file); + lastFile_ = file; + } + + string s = datum.name; + if (s == "-") { + // Simply draw a line across the benchmark results + separator('-'); + continue; + } + if (s[0] == '"') { + // Simply print some text. Strips implied quote characters + // from the beginning and end of the name. + printf("%s\n", s.substr(1, s.length() - 2).c_str()); + continue; + } + bool useBaseline = false; + // '%' indicates a relative benchmark. + if (s[0] == '%') { + s.erase(0, 1); + useBaseline = isBaselineSet(); + } else { + baselineNsPerIter_ = datum.timeInNs; + useBaseline = false; + } + s.resize(columns_ - kUnitHeaders.size(), ' '); + const auto nsPerIter = datum.timeInNs; + const auto secPerIter = nsPerIter / 1E9; + const auto itersPerSec = (secPerIter == 0) + ? std::numeric_limits::infinity() + : (1 / secPerIter); + if (!useBaseline) { + // Print without baseline + printf( + "%*s%8.8s %9.9s %8.8s", + static_cast(s.size()), + s.c_str(), + "", // Padding for "relative" header. + readableTime(secPerIter, 2).c_str(), + metricReadable(itersPerSec, 2).c_str()); + } else { + // Print with baseline + const auto rel = baselineNsPerIter_ / nsPerIter * 100.0; + printf( + "%*s%#7.5g%% %9.9s %8.8s", + static_cast(s.size()), + s.c_str(), + rel, + readableTime(secPerIter, 2).c_str(), + metricReadable(itersPerSec, 2).c_str()); + } + for (auto const& name : counterNames_) { + if (auto ptr = folly::get_ptr(datum.counters, name)) { + switch (ptr->type) { + case UserMetric::Type::TIME: + printf( + " %*s", + int(name.length()), + readableTime(ptr->value, 2).c_str()); + break; + case UserMetric::Type::METRIC: + printf( + " %*s", + int(name.length()), + metricReadable(ptr->value, 2).c_str()); + break; + case UserMetric::Type::CUSTOM: + default: + printf(" %*" PRId64, int(name.length()), ptr->value); + } + } else { + printf(" %*s", int(name.length()), "NaN"); + } + } + printf("\n"); + } + } + + private: + bool isBaselineSet() { + return baselineNsPerIter_ != numeric_limits::max(); + } + + std::set counterNames_; + size_t namesLength_{0}; + size_t columns_{0}; + double baselineNsPerIter_{numeric_limits::max()}; + string lastFile_; +}; +} // namespace + +static void printBenchmarkResultsAsJson( + const vector& data) { + dynamic d = dynamic::object; + for (auto& datum : data) { + d[datum.name] = datum.timeInNs * 1000.; + } + + printf("%s\n", toPrettyJson(d).c_str()); +} + +void benchmarkResultsToDynamic( + const vector& data, dynamic& out) { + out = dynamic::array; + for (auto& datum : data) { + if (!datum.counters.empty()) { + dynamic obj = dynamic::object; + for (auto& counter : datum.counters) { + dynamic counterInfo = dynamic::object; + counterInfo["value"] = counter.second.value; + counterInfo["type"] = static_cast(counter.second.type); + obj[counter.first] = counterInfo; + } + out.push_back( + dynamic::array(datum.file, datum.name, datum.timeInNs, obj)); + } else { + out.push_back(dynamic::array(datum.file, datum.name, datum.timeInNs)); + } + } +} + +void benchmarkResultsFromDynamic( + const dynamic& d, vector& results) { + for (auto& datum : d) { + results.push_back( + {datum[0].asString(), + datum[1].asString(), + datum[2].asDouble(), + UserCounters{}}); + } +} + +static pair resultKey( + const detail::BenchmarkResult& result) { + return pair(result.file, result.name); +} + +void printResultComparison( + const vector& base, + const vector& test) { + map, double> baselines; + + for (auto& baseResult : base) { + baselines[resultKey(baseResult)] = baseResult.timeInNs; + } + + // Width available + const size_t columns = FLAGS_bm_result_width_chars; + + auto header = [&](const string_view& file) { + printSeparator('=', columns); + printDefaultHeaderContents(file, columns); + printf("\n"); + printSeparator('=', columns); + }; + + string lastFile; + + for (auto& datum : test) { + folly::Optional baseline = + folly::get_optional(baselines, resultKey(datum)); + auto file = datum.file; + if (file != lastFile) { + // New file starting + header(file); + lastFile = file; + } + + string s = datum.name; + if (s == "-") { + printSeparator('-', columns); + continue; + } + if (s[0] == '%') { + s.erase(0, 1); + } + s.resize(columns - 29, ' '); + auto nsPerIter = datum.timeInNs; + auto secPerIter = nsPerIter / 1E9; + auto itersPerSec = (secPerIter == 0) + ? std::numeric_limits::infinity() + : (1 / secPerIter); + if (!baseline) { + // Print without baseline + printf( + "%*s %9s %7s\n", + static_cast(s.size()), + s.c_str(), + readableTime(secPerIter, 2).c_str(), + metricReadable(itersPerSec, 2).c_str()); + } else { + // Print with baseline + auto rel = *baseline / nsPerIter * 100.0; + printf( + "%*s %7.2f%% %9s %7s\n", + static_cast(s.size()), + s.c_str(), + rel, + readableTime(secPerIter, 2).c_str(), + metricReadable(itersPerSec, 2).c_str()); + } + } + printSeparator('=', columns); +} + +void checkRunMode() { + if (folly::kIsDebug || folly::kIsSanitize) { + std::cerr << "WARNING: Benchmark running " + << (folly::kIsDebug ? "in DEBUG mode" : "with SANITIZERS") + << std::endl; + } +} + +namespace { + +struct BenchmarksToRun { + const detail::BenchmarkRegistration* baseline = nullptr; + std::vector benchmarks; + std::vector separatorsAfter; +}; + +void addSeparator(BenchmarksToRun& res) { + size_t separatorAfter = res.benchmarks.size(); + if (separatorAfter == 0) { + return; + } + if (res.separatorsAfter.empty() || + res.separatorsAfter.back() != separatorAfter) { + res.separatorsAfter.push_back(res.benchmarks.size() - 1); + } +} + +BenchmarksToRun selectBenchmarksToRun( + const std::vector& benchmarks) { + BenchmarksToRun res; + + folly::Optional bmRegex; + folly::Optional bmFileRegex; + + res.benchmarks.reserve(benchmarks.size()); + + if (!FLAGS_bm_regex.empty()) { + bmRegex.emplace(FLAGS_bm_regex); + } + + if (!FLAGS_bm_file_regex.empty()) { + bmFileRegex.emplace(FLAGS_bm_file_regex); + } + + for (auto& bm : benchmarks) { + if (bm.name == "-") { + addSeparator(res); + continue; + } + + if (bm.name == kGlobalBenchmarkBaseline) { + res.baseline = &bm; + continue; + } + + bool matchedName = !bmRegex || boost::regex_search(bm.name, *bmRegex); + bool matchedFile = + !bmFileRegex || boost::regex_search(bm.file, *bmFileRegex); + + if (matchedName && matchedFile) { + res.benchmarks.push_back(&bm); + } + } + + if (bmRegex) { + res.separatorsAfter.clear(); + } + + CHECK(res.baseline); + + return res; +} + +void maybeRunWarmUpIteration(const BenchmarksToRun& toRun) { + bool shouldRun = FLAGS_bm_warm_up_iteration; + +#if FOLLY_PERF_IS_SUPPORTED + shouldRun = shouldRun || !FLAGS_bm_perf_args.empty(); +#endif + + if (!shouldRun) { + return; + } + + for (const auto* bm : toRun.benchmarks) { + bm->func(1); + } +} + +class ShouldDrawLineTracker { + public: + explicit ShouldDrawLineTracker(const BenchmarksToRun& toRun) + : separatorsAfter_(&toRun.separatorsAfter) {} + + bool operator()() { + std::size_t i = curI_++; + if (drawAfterI_ >= separatorsAfter_->size()) { + return false; + } + std::size_t nextToDrawAfter = (*separatorsAfter_)[drawAfterI_]; + if (i == nextToDrawAfter) { + ++drawAfterI_; + return true; + } + return false; + } + + private: + const std::vector* separatorsAfter_; + std::size_t curI_ = 0; + std::size_t drawAfterI_ = 0; +}; + +std::pair, std::vector> +runBenchmarksWithPrinterImpl( + BenchmarkResultsPrinter* FOLLY_NULLABLE printer, + const BenchmarksToRun& toRun) { + vector results; + results.reserve(toRun.benchmarks.size()); + + // PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS. + + auto const globalBaseline = + runBenchmarkGetNSPerIteration(toRun.baseline->func, 0); + + std::set counterNames; + ShouldDrawLineTracker shouldDrawLineTracker(toRun); + for (std::size_t i = 0; i != toRun.benchmarks.size(); ++i) { + std::pair elapsed; + const detail::BenchmarkRegistration& bm = *toRun.benchmarks[i]; + bool shoudDrawLineAfter = shouldDrawLineTracker(); + + if (FLAGS_bm_profile) { + elapsed = runProfilingGetNSPerIteration(bm.func, globalBaseline.first); + } else { + elapsed = FLAGS_bm_estimate_time + ? runBenchmarkGetNSPerIterationEstimate(bm.func, globalBaseline.first) + : runBenchmarkGetNSPerIteration(bm.func, globalBaseline.first); + } + + // if customized user counters is used, it cannot print the result in real + // time as it needs to run all cases first to know the complete set of + // counters have been used, then the header can be printed out properly + if (printer != nullptr) { + printer->print({{bm.file, bm.name, elapsed.first, elapsed.second}}); + if (shoudDrawLineAfter) { + printer->separator('-'); + } + } + results.push_back({bm.file, bm.name, elapsed.first, elapsed.second}); + + // get all counter names + for (auto const& kv : elapsed.second) { + counterNames.insert(kv.first); + } + } + + // MEASUREMENTS DONE. + + return std::make_pair(std::move(counterNames), std::move(results)); +} + +std::vector resultsFromFile( + const std::string& filename) { + std::string content; + readFile(filename.c_str(), content); + std::vector ret; + if (!content.empty()) { + benchmarkResultsFromDynamic(parseJson(content), ret); + } + return ret; +} + +bool writeResultsToFile( + const std::vector& results, + const std::string& filename) { + dynamic d; + benchmarkResultsToDynamic(results, d); + return writeFile(toPrettyJson(d), filename.c_str()); +} + +} // namespace + +namespace detail { + +std::ostream& operator<<(std::ostream& os, const BenchmarkResult& x) { + folly::dynamic r; + benchmarkResultsToDynamic({x}, r); + return os << r[0]; +} + +bool operator==(const BenchmarkResult& x, const BenchmarkResult& y) { + auto xtime = static_cast(x.timeInNs * 1000); + auto ytime = static_cast(y.timeInNs * 1000); + return x.name == y.name && x.file == y.file && xtime == ytime && + x.counters == y.counters; +} + +std::chrono::high_resolution_clock::duration BenchmarkSuspenderBase::timeSpent; + +void BenchmarkingStateBase::addBenchmarkImpl( + const char* file, StringPiece name, BenchmarkFun fun, bool useCounter) { + std::lock_guard guard(mutex_); + benchmarks_.push_back({file, name.str(), std::move(fun), useCounter}); +} + +bool BenchmarkingStateBase::useCounters() const { + std::lock_guard guard(mutex_); + return std::any_of( + benchmarks_.begin(), benchmarks_.end(), [](const auto& bm) { + return bm.useCounter; + }); +} + +std::vector BenchmarkingStateBase::getBenchmarkList() { + std::vector bmNames; + auto toRun = selectBenchmarksToRun(benchmarks_); + for (auto benchmarkRegistration : toRun.benchmarks) { + bmNames.push_back(benchmarkRegistration->name); + } + + return bmNames; +} + +// static +folly::StringPiece BenchmarkingStateBase::getGlobalBaselineNameForTests() { + return kGlobalBenchmarkBaseline; +} + +PerfScoped BenchmarkingStateBase::doSetUpPerfScoped( + const std::vector& args) const { + return PerfScoped{args}; +} + +PerfScoped BenchmarkingStateBase::setUpPerfScoped() const { + std::vector perfArgs; +#if FOLLY_PERF_IS_SUPPORTED + folly::split(' ', FLAGS_bm_perf_args, perfArgs, true); +#endif + if (perfArgs.empty()) { + return PerfScoped{}; + } + return doSetUpPerfScoped(perfArgs); +} + +template +std::pair, std::vector> +BenchmarkingStateBase::runBenchmarksWithPrinter(Printer* printer) const { + std::lock_guard guard(mutex_); + BenchmarksToRun toRun = selectBenchmarksToRun(benchmarks_); + maybeRunWarmUpIteration(toRun); + + detail::PerfScoped perf = setUpPerfScoped(); + return runBenchmarksWithPrinterImpl(printer, toRun); +} + +std::vector BenchmarkingStateBase::runBenchmarksWithResults() + const { + return runBenchmarksWithPrinter( + static_cast(nullptr)) + .second; +} + +std::vector runBenchmarksWithResults() { + return globalBenchmarkState().runBenchmarksWithResults(); +} + +} // namespace detail + +void runBenchmarks() { + auto& state = detail::globalBenchmarkState(); + + if (FLAGS_bm_list) { + auto bmNames = state.getBenchmarkList(); + for (auto testName : bmNames) { + std::cout << testName << std::endl; + } + return; + } + + if (FLAGS_bm_profile) { + printf( + "WARNING: Running with constant number of iterations. Results might be jittery.\n"); + } + + if (FLAGS_bm_min_iters >= FLAGS_bm_max_iters) { + std::cerr << "WARNING: bm_min_iters > bm_max_iters; increasing the max" + << std::endl; + FLAGS_bm_max_iters = FLAGS_bm_min_iters + 1; + } + + checkRunMode(); + + BenchmarkResultsPrinter printer; + bool useCounter = state.useCounters(); + + // PLEASE KEEP QUIET. MEASUREMENTS IN PROGRESS. + + const bool shouldPrintInline = + FLAGS_bm_relative_to.empty() && !FLAGS_json && !useCounter; + auto benchmarkResults = + state.runBenchmarksWithPrinter(shouldPrintInline ? &printer : nullptr); + + // PLEASE MAKE NOISE. MEASUREMENTS DONE. + + if (FLAGS_json) { + printBenchmarkResultsAsJson(benchmarkResults.second); + } else if (!FLAGS_bm_relative_to.empty()) { + printResultComparison( + resultsFromFile(FLAGS_bm_relative_to), benchmarkResults.second); + } else if (!shouldPrintInline) { + printer = BenchmarkResultsPrinter{std::move(benchmarkResults.first)}; + printer.print(benchmarkResults.second); + printer.separator('='); + } + + if (!FLAGS_bm_json_verbose.empty()) { + writeResultsToFile(benchmarkResults.second, FLAGS_bm_json_verbose); + } + + checkRunMode(); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/Benchmark.h b/vnext/external/folly/folly/Benchmark.h new file mode 100644 index 00000000000..26d42acba1e --- /dev/null +++ b/vnext/external/folly/folly/Benchmark.h @@ -0,0 +1,680 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include // for FB_ANONYMOUS_VARIABLE +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +FOLLY_GFLAGS_DECLARE_bool(benchmark); +FOLLY_GFLAGS_DECLARE_uint32(bm_result_width_chars); + +namespace folly { + +/** + * Runs all benchmarks defined. Usually put in main(). + */ +void runBenchmarks(); + +/** + * Runs all benchmarks defined if and only if the --benchmark flag has + * been passed to the program. Usually put in main(). + */ +inline bool runBenchmarksOnFlag() { + if (FLAGS_benchmark) { + runBenchmarks(); + } + return FLAGS_benchmark; +} + +class UserMetric { + public: + enum class Type { CUSTOM, TIME, METRIC }; + + int64_t value{}; + Type type{Type::CUSTOM}; + + UserMetric() = default; + /* implicit */ UserMetric(int64_t val, Type typ = Type::CUSTOM) + : value(val), type(typ) {} + + friend bool operator==(const UserMetric& x, const UserMetric& y) { + return x.value == y.value && x.type == y.type; + } + friend bool operator!=(const UserMetric& x, const UserMetric& y) { + return !(x == y); + } +}; + +using UserCounters = std::unordered_map; + +namespace detail { +struct TimeIterData { + std::chrono::high_resolution_clock::duration duration; + unsigned int niter; + UserCounters userCounters; +}; + +using BenchmarkFun = std::function; + +struct BenchmarkRegistration { + std::string file; + std::string name; + BenchmarkFun func; + bool useCounter = false; +}; + +struct BenchmarkResult { + std::string file; + std::string name; + double timeInNs; + UserCounters counters; + + friend std::ostream& operator<<(std::ostream&, const BenchmarkResult&); + + friend bool operator==(const BenchmarkResult&, const BenchmarkResult&); + friend bool operator!=(const BenchmarkResult& x, const BenchmarkResult& y) { + return !(x == y); + } +}; + +struct BenchmarkSuspenderBase { + /** + * Accumulates time spent outside benchmark. + */ + static std::chrono::high_resolution_clock::duration timeSpent; +}; + +template +struct BenchmarkSuspender : BenchmarkSuspenderBase { + using TimePoint = std::chrono::high_resolution_clock::time_point; + using Duration = std::chrono::high_resolution_clock::duration; + + struct DismissedTag {}; + static inline constexpr DismissedTag Dismissed{}; + + BenchmarkSuspender() : start(Clock::now()) {} + + explicit BenchmarkSuspender(DismissedTag) : start(TimePoint{}) {} + + BenchmarkSuspender(const BenchmarkSuspender&) = delete; + BenchmarkSuspender(BenchmarkSuspender&& rhs) noexcept { + start = rhs.start; + rhs.start = {}; + } + + BenchmarkSuspender& operator=(const BenchmarkSuspender&) = delete; + BenchmarkSuspender& operator=(BenchmarkSuspender&& rhs) noexcept { + if (start != TimePoint{}) { + tally(); + } + start = rhs.start; + rhs.start = {}; + return *this; + } + + ~BenchmarkSuspender() { + if (start != TimePoint{}) { + tally(); + } + } + + void dismiss() { + assert(start != TimePoint{}); + tally(); + start = {}; + } + + void rehire() { + assert(start == TimePoint{}); + start = Clock::now(); + } + + template + auto dismissing(F f) -> invoke_result_t { + SCOPE_EXIT { + rehire(); + }; + dismiss(); + return f(); + } + + /** + * This is for use inside of if-conditions, used in BENCHMARK macros. + * If-conditions bypass the explicit on operator bool. + */ + explicit operator bool() const { return false; } + + private: + void tally() { + auto end = Clock::now(); + timeSpent += end - start; + start = end; + } + + TimePoint start; +}; + +class PerfScoped; + +class BenchmarkingStateBase { + public: + template + std::pair, std::vector> + runBenchmarksWithPrinter(Printer* printer) const; + + std::vector runBenchmarksWithResults() const; + + static folly::StringPiece getGlobalBaselineNameForTests(); + + bool useCounters() const; + + void addBenchmarkImpl( + const char* file, StringPiece name, BenchmarkFun, bool useCounter); + + std::vector getBenchmarkList(); + + protected: + // There is no need for this virtual but we overcome a check + virtual ~BenchmarkingStateBase() = default; + + PerfScoped setUpPerfScoped() const; + + // virtual for purely testing purposes. + virtual PerfScoped doSetUpPerfScoped( + const std::vector& args) const; + + mutable std::mutex mutex_; + std::vector benchmarks_; +}; + +template +class BenchmarkingState : public BenchmarkingStateBase { + public: + template + typename std::enable_if>::type + addBenchmark(const char* file, StringPiece name, Lambda&& lambda) { + auto execute = [=](unsigned int times) { + BenchmarkSuspender::timeSpent = {}; + unsigned int niter; + + // CORE MEASUREMENT STARTS + auto start = Clock::now(); + niter = lambda(times); + auto end = Clock::now(); + // CORE MEASUREMENT ENDS + return detail::TimeIterData{ + (end - start) - BenchmarkSuspender::timeSpent, + niter, + UserCounters{}}; + }; + + this->addBenchmarkImpl(file, name, detail::BenchmarkFun(execute), false); + } + + template + typename std::enable_if>::type addBenchmark( + const char* file, StringPiece name, Lambda&& lambda) { + addBenchmark(file, name, [=](unsigned int times) { + unsigned int niter = 0; + while (times-- > 0) { + niter += lambda(); + } + return niter; + }); + } + + template + typename std::enable_if< + folly::is_invocable_v>::type + addBenchmark(const char* file, StringPiece name, Lambda&& lambda) { + auto execute = [=](unsigned int times) { + BenchmarkSuspender::timeSpent = {}; + unsigned int niter; + + // CORE MEASUREMENT STARTS + auto start = std::chrono::high_resolution_clock::now(); + UserCounters counters; + niter = lambda(counters, times); + auto end = std::chrono::high_resolution_clock::now(); + // CORE MEASUREMENT ENDS + return detail::TimeIterData{ + (end - start) - BenchmarkSuspender::timeSpent, + niter, + counters}; + }; + + this->addBenchmarkImpl( + file, + name, + std::function(execute), + true); + } + + template + typename std::enable_if>::type + addBenchmark(const char* file, StringPiece name, Lambda&& lambda) { + addBenchmark(file, name, [=](UserCounters& counters, unsigned int times) { + unsigned int niter = 0; + while (times-- > 0) { + niter += lambda(counters); + } + return niter; + }); + } +}; + +BenchmarkingState& globalBenchmarkState(); + +/** + * Runs all benchmarks defined in the program, doesn't print by default. + * Usually used when customized printing of results is desired. + */ +std::vector runBenchmarksWithResults(); + +/** + * Adds a benchmark wrapped in a std::function. + * Was designed to only be used internally but, unfortunately, + * is not. + */ +inline void addBenchmarkImpl( + const char* file, StringPiece name, BenchmarkFun f, bool useCounter) { + globalBenchmarkState().addBenchmarkImpl(file, name, std::move(f), useCounter); +} + +} // namespace detail + +/** + * Supporting type for BENCHMARK_SUSPEND defined below. + */ +struct BenchmarkSuspender + : detail::BenchmarkSuspender { + using Impl = detail::BenchmarkSuspender; + using Impl::Impl; +}; + +/** + * Adds a benchmark. Usually not called directly but instead through + * the macro BENCHMARK defined below. + * The lambda function involved can have one of the following forms: + * * take zero parameters, and the benchmark calls it repeatedly + * * take exactly one parameter of type unsigned, and the benchmark + * uses it with counter semantics (iteration occurs inside the + * function). + * * 2 versions of the above cases but also accept UserCounters& as + * as their first parameter. + */ +template +void addBenchmark(const char* file, StringPiece name, Lambda&& lambda) { + detail::globalBenchmarkState().addBenchmark(file, name, lambda); +} + +struct dynamic; + +void benchmarkResultsToDynamic( + const std::vector& data, dynamic&); + +void benchmarkResultsFromDynamic( + const dynamic&, std::vector&); + +void printResultComparison( + const std::vector& base, + const std::vector& test); + +} // namespace folly + +/** + * Introduces a benchmark function. Used internally, see BENCHMARK and + * friends below. + */ + +#define BENCHMARK_IMPL(funName, stringName, rv, paramType, paramName) \ + static void funName(paramType); \ + [[maybe_unused]] static bool FB_ANONYMOUS_VARIABLE(follyBenchmarkUnused) = \ + (::folly::addBenchmark( \ + __FILE__, \ + stringName, \ + [](paramType paramName) -> unsigned { \ + funName(paramName); \ + return rv; \ + }), \ + true); \ + static void funName(paramType paramName) + +#define BENCHMARK_IMPL_COUNTERS( \ + funName, stringName, counters, rv, paramType, paramName) \ + static void funName( \ + ::folly::UserCounters& FOLLY_PP_DETAIL_APPEND_VA_ARG(paramType)); \ + [[maybe_unused]] static bool FB_ANONYMOUS_VARIABLE(follyBenchmarkUnused) = \ + (::folly::addBenchmark( \ + __FILE__, \ + stringName, \ + [](::folly::UserCounters& counters FOLLY_PP_DETAIL_APPEND_VA_ARG( \ + paramType paramName)) -> unsigned { \ + funName(counters FOLLY_PP_DETAIL_APPEND_VA_ARG(paramName)); \ + return rv; \ + }), \ + true); \ + static void funName([[maybe_unused]] ::folly::UserCounters& counters \ + FOLLY_PP_DETAIL_APPEND_VA_ARG(paramType paramName)) + +/** + * Introduces a benchmark function with support for returning the actual + * number of iterations. Used internally, see BENCHMARK_MULTI and friends + * below. + */ +#define BENCHMARK_MULTI_IMPL(funName, stringName, paramType, paramName) \ + static unsigned funName(paramType); \ + [[maybe_unused]] static bool FB_ANONYMOUS_VARIABLE(follyBenchmarkUnused) = \ + (::folly::addBenchmark( \ + __FILE__, \ + stringName, \ + [](paramType paramName) { return funName(paramName); }), \ + true); \ + static unsigned funName(paramType paramName) + +/** + * Introduces a benchmark function. Use with either one or two arguments. + * The first is the name of the benchmark. Use something descriptive, such + * as insertVectorBegin. The second argument may be missing, or could be a + * symbolic counter. The counter dictates how many internal iteration the + * benchmark does. Example: + * + * BENCHMARK(vectorPushBack) { + * vector v; + * v.push_back(42); + * } + * + * BENCHMARK(insertVectorBegin, iters) { + * vector v; + * for (unsigned int i = 0; i < iters; ++i) { + * v.insert(v.begin(), 42); + * } + * } + */ +#define BENCHMARK(name, ...) \ + BENCHMARK_IMPL( \ + name, \ + FOLLY_PP_STRINGIZE(name), \ + FB_ARG_2_OR_1(1, ##__VA_ARGS__), \ + FB_ONE_OR_NONE(unsigned, ##__VA_ARGS__), \ + __VA_ARGS__) + +/** + * Allow users to record customized counter during benchmarking, + * there will be one extra column showing in the output result for each counter + * + * BENCHMARK_COUNTERS(insertVectorBegin, counters, iters) { + * vector v; + * for (unsigned int i = 0; i < iters; ++i) { + * v.insert(v.begin(), 42); + * } + * BENCHMARK_SUSPEND { + * counters["foo"] = 10; + * } + * } + */ +#define BENCHMARK_COUNTERS(name, counters, ...) \ + BENCHMARK_IMPL_COUNTERS( \ + name, \ + FOLLY_PP_STRINGIZE(name), \ + counters, \ + FB_ARG_2_OR_1(1, ##__VA_ARGS__), \ + FB_ONE_OR_NONE(unsigned, ##__VA_ARGS__), \ + __VA_ARGS__) +/** + * Like BENCHMARK above, but allows the user to return the actual + * number of iterations executed in the function body. This can be + * useful if the benchmark function doesn't know upfront how many + * iterations it's going to run or if it runs through a certain + * number of test cases, e.g.: + * + * BENCHMARK_MULTI(benchmarkSomething) { + * std::vector testCases { 0, 1, 1, 2, 3, 5 }; + * for (int c : testCases) { + * doSomething(c); + * } + * return testCases.size(); + * } + */ +#define BENCHMARK_MULTI(name, ...) \ + BENCHMARK_MULTI_IMPL( \ + name, \ + FOLLY_PP_STRINGIZE(name), \ + FB_ONE_OR_NONE(unsigned, ##__VA_ARGS__), \ + __VA_ARGS__) + +/** + * Defines a benchmark that passes a parameter to another one. This is + * common for benchmarks that need a "problem size" in addition to + * "number of iterations". Consider: + * + * void pushBack(uint32_t n, size_t initialSize) { + * vector v; + * BENCHMARK_SUSPEND { + * v.resize(initialSize); + * } + * for (uint32_t i = 0; i < n; ++i) { + * v.push_back(i); + * } + * } + * BENCHMARK_PARAM(pushBack, 0) + * BENCHMARK_PARAM(pushBack, 1000) + * BENCHMARK_PARAM(pushBack, 1000000) + * + * The benchmark above estimates the speed of push_back at different + * initial sizes of the vector. The framework will pass 0, 1000, and + * 1000000 for initialSize, and the iteration count for n. + */ +#define BENCHMARK_PARAM(name, param) BENCHMARK_NAMED_PARAM(name, param, param) + +/** + * Same as BENCHMARK_PARAM, but allows one to return the actual number of + * iterations that have been run. + */ +#define BENCHMARK_PARAM_MULTI(name, param) \ + BENCHMARK_NAMED_PARAM_MULTI(name, param, param) + +/* + * Like BENCHMARK_PARAM(), but allows a custom name to be specified for each + * parameter, rather than using the parameter value. + * + * Useful when the parameter value is not a valid token for string pasting, + * of when you want to specify multiple parameter arguments. + * + * For example: + * + * void addValue(uint32_t n, int64_t bucketSize, int64_t min, int64_t max) { + * Histogram hist(bucketSize, min, max); + * int64_t num = min; + * for (uint32_t i = 0; i < n; ++i) { + * hist.addValue(num); + * ++num; + * if (num > max) { num = min; } + * } + * } + * + * BENCHMARK_NAMED_PARAM(addValue, 0_to_100, 1, 0, 100) + * BENCHMARK_NAMED_PARAM(addValue, 0_to_1000, 10, 0, 1000) + * BENCHMARK_NAMED_PARAM(addValue, 5k_to_20k, 250, 5000, 20000) + */ +#define BENCHMARK_NAMED_PARAM(name, param_name, ...) \ + BENCHMARK_IMPL( \ + FB_CONCATENATE(name, FB_CONCATENATE(_, param_name)), \ + FOLLY_PP_STRINGIZE(name) "(" FOLLY_PP_STRINGIZE(param_name) ")", \ + iters, \ + unsigned, \ + iters) { \ + name(iters, ##__VA_ARGS__); \ + } + +/** + * Same as BENCHMARK_NAMED_PARAM, but allows one to return the actual number + * of iterations that have been run. + */ +#define BENCHMARK_NAMED_PARAM_MULTI(name, param_name, ...) \ + BENCHMARK_MULTI_IMPL( \ + FB_CONCATENATE(name, FB_CONCATENATE(_, param_name)), \ + FOLLY_PP_STRINGIZE(name) "(" FOLLY_PP_STRINGIZE(param_name) ")", \ + unsigned, \ + iters) { \ + return name(iters, ##__VA_ARGS__); \ + } + +/** + * Just like BENCHMARK, but prints the time relative to a + * baseline. The baseline is the most recent BENCHMARK() seen in + * the current scope. Example: + * + * // This is the baseline + * BENCHMARK(insertVectorBegin, n) { + * vector v; + * for (unsigned int i = 0; i < n; ++i) { + * v.insert(v.begin(), 42); + * } + * } + * + * BENCHMARK_RELATIVE(insertListBegin, n) { + * list s; + * for (unsigned int i = 0; i < n; ++i) { + * s.insert(s.begin(), 42); + * } + * } + * + * Any number of relative benchmark can be associated with a + * baseline. Another BENCHMARK() occurrence effectively establishes a + * new baseline. + */ +#define BENCHMARK_RELATIVE(name, ...) \ + BENCHMARK_IMPL( \ + name, \ + "%" FOLLY_PP_STRINGIZE(name), \ + FB_ARG_2_OR_1(1, ##__VA_ARGS__), \ + FB_ONE_OR_NONE(unsigned, ##__VA_ARGS__), \ + __VA_ARGS__) + +#define BENCHMARK_COUNTERS_RELATIVE(name, counters, ...) \ + BENCHMARK_IMPL_COUNTERS( \ + name, \ + "%" FOLLY_PP_STRINGIZE(name), \ + counters, \ + FB_ARG_2_OR_1(1, ##__VA_ARGS__), \ + FB_ONE_OR_NONE(unsigned, ##__VA_ARGS__), \ + __VA_ARGS__) +/** + * Same as BENCHMARK_RELATIVE, but allows one to return the actual number + * of iterations that have been run. + */ +#define BENCHMARK_RELATIVE_MULTI(name, ...) \ + BENCHMARK_MULTI_IMPL( \ + name, \ + "%" FOLLY_PP_STRINGIZE(name), \ + FB_ONE_OR_NONE(unsigned, ##__VA_ARGS__), \ + __VA_ARGS__) + +/** + * A combination of BENCHMARK_RELATIVE and BENCHMARK_PARAM. + */ +#define BENCHMARK_RELATIVE_PARAM(name, param) \ + BENCHMARK_RELATIVE_NAMED_PARAM(name, param, param) + +/** + * Same as BENCHMARK_RELATIVE_PARAM, but allows one to return the actual + * number of iterations that have been run. + */ +#define BENCHMARK_RELATIVE_PARAM_MULTI(name, param) \ + BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(name, param, param) + +/** + * A combination of BENCHMARK_RELATIVE and BENCHMARK_NAMED_PARAM. + */ +#define BENCHMARK_RELATIVE_NAMED_PARAM(name, param_name, ...) \ + BENCHMARK_IMPL( \ + FB_CONCATENATE(name, FB_CONCATENATE(_, param_name)), \ + "%" FOLLY_PP_STRINGIZE(name) "(" FOLLY_PP_STRINGIZE(param_name) ")", \ + iters, \ + unsigned, \ + iters) { \ + name(iters, ##__VA_ARGS__); \ + } + +/** + * Same as BENCHMARK_RELATIVE_NAMED_PARAM, but allows one to return the + * actual number of iterations that have been run. + */ +#define BENCHMARK_RELATIVE_NAMED_PARAM_MULTI(name, param_name, ...) \ + BENCHMARK_MULTI_IMPL( \ + FB_CONCATENATE(name, FB_CONCATENATE(_, param_name)), \ + "%" FOLLY_PP_STRINGIZE(name) "(" FOLLY_PP_STRINGIZE(param_name) ")", \ + unsigned, \ + iters) { \ + return name(iters, ##__VA_ARGS__); \ + } + +/** + * Draws a line of dashes. + */ +#define BENCHMARK_DRAW_LINE() \ + [[maybe_unused]] static bool FB_ANONYMOUS_VARIABLE(follyBenchmarkUnused) = \ + (::folly::addBenchmark(__FILE__, "-", []() -> unsigned { return 0; }), \ + true) + +/** + * Prints arbitrary text. + */ +#define BENCHMARK_DRAW_TEXT(text) \ + [[maybe_unused]] static bool FB_ANONYMOUS_VARIABLE(follyBenchmarkUnused) = \ + (::folly::addBenchmark(__FILE__, #text, []() -> unsigned { return 0; }), \ + true) + +/** + * Allows execution of code that doesn't count torward the benchmark's + * time budget. Example: + * + * BENCHMARK_START_GROUP(insertVectorBegin, n) { + * vector v; + * BENCHMARK_SUSPEND { + * v.reserve(n); + * } + * for (unsigned int i = 0; i < n; ++i) { + * v.insert(v.begin(), 42); + * } + * } + */ +#define BENCHMARK_SUSPEND \ + if (auto FB_ANONYMOUS_VARIABLE(BENCHMARK_SUSPEND) = \ + ::folly::BenchmarkSuspender()) { \ + } else diff --git a/vnext/external/folly/folly/BenchmarkUtil.h b/vnext/external/folly/folly/BenchmarkUtil.h new file mode 100644 index 00000000000..3fe8f7803c2 --- /dev/null +++ b/vnext/external/folly/folly/BenchmarkUtil.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace folly { + +/** + * Call doNotOptimizeAway(var) to ensure that var will be computed even + * post-optimization. Use it for variables that are computed during + * benchmarking but otherwise are useless. The compiler tends to do a + * good job at eliminating unused variables, and this function fools it + * into thinking var is in fact needed. + * + * Call makeUnpredictable(var) when you don't want the optimizer to use + * its knowledge of var to shape the following code. This is useful + * when constant propagation or power reduction is possible during your + * benchmark but not in real use cases. + */ + +template +FOLLY_ALWAYS_INLINE void doNotOptimizeAway(const T& datum) { + compiler_must_not_elide(datum); +} + +template +FOLLY_ALWAYS_INLINE void makeUnpredictable(T& datum) { + compiler_must_not_predict(datum); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/Bits.h b/vnext/external/folly/folly/Bits.h new file mode 100644 index 00000000000..9453bb0f9ef --- /dev/null +++ b/vnext/external/folly/folly/Bits.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include // @shim diff --git a/vnext/external/folly/folly/CMakeLists.txt b/vnext/external/folly/folly/CMakeLists.txt new file mode 100644 index 00000000000..57b4dbcc431 --- /dev/null +++ b/vnext/external/folly/folly/CMakeLists.txt @@ -0,0 +1,110 @@ +# Copyright (c) Meta Platforms, Inc. and affiliates. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +add_library( + follybenchmark + Benchmark.cpp +) +set_property(TARGET follybenchmark PROPERTY VERSION ${PACKAGE_VERSION}) +target_compile_definitions(follybenchmark PRIVATE BOOST_NO_AUTO_PTR) +target_link_libraries(follybenchmark PUBLIC folly) +apply_folly_compile_options_to_target(follybenchmark) +install( + TARGETS follybenchmark + EXPORT folly + RUNTIME DESTINATION ${BIN_INSTALL_DIR} + LIBRARY DESTINATION ${LIB_INSTALL_DIR} + ARCHIVE DESTINATION ${LIB_INSTALL_DIR} +) + +add_subdirectory(debugging/exception_tracer) +add_subdirectory(logging/example) + +if (PYTHON_EXTENSIONS) + # Create tree of symbolic links in structure required for successful + # compliation by Cython. + # - must be in path named same as extension + + set(_cybld "${CMAKE_CURRENT_BINARY_DIR}/cybld") + + add_custom_target(create_binding_symlink ALL) + file(GLOB BindingFiles + "${CMAKE_CURRENT_SOURCE_DIR}/python/*.pyx" + "${CMAKE_CURRENT_SOURCE_DIR}/python/*.pxd" + "${CMAKE_CURRENT_SOURCE_DIR}/python/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/python/*.cpp" + ) + file(MAKE_DIRECTORY "${_cybld}/folly/") + + foreach(_src ${BindingFiles}) + get_filename_component(_target_file "${_src}" NAME) + + message( + STATUS + "Linking ${_src} " + "to ${_cybld}/folly/${_target_file}" + ) + add_custom_command(TARGET create_binding_symlink PRE_BUILD + COMMAND + ${CMAKE_COMMAND} -E create_symlink + "${_src}" + "${_cybld}/folly/${_target_file}" + ) + endforeach() + + # Tell setup.py where to find includes and libfolly.so + set(prop "$") + set(incs "$<$:-I$>") + set(libs "-L${CMAKE_BINARY_DIR}") + + add_custom_target(folly_python_bindings ALL + DEPENDS folly create_binding_symlink + WORKING_DIRECTORY ${_cybld}) + + add_custom_command(TARGET folly_python_bindings POST_BUILD + COMMAND + python3 ${CMAKE_CURRENT_SOURCE_DIR}/python/setup.py + build_ext -f ${incs} ${libs} + BYPRODUCTS ${_cybld}/folly/executor_api.h + WORKING_DIRECTORY ${_cybld} + ) + + add_custom_command(TARGET folly_python_bindings POST_BUILD + COMMAND + python3 ${CMAKE_CURRENT_SOURCE_DIR}/python/setup.py + bdist_wheel + WORKING_DIRECTORY ${_cybld} + ) + + install( + FILES ${_cybld}/folly/executor_api.h + DESTINATION ${INCLUDE_INSTALL_DIR}/folly/python + COMPONENT dev + ) + + # Install Folly Python Bindings + if (UNIX) + set(ROOT_ARG "--root \$DESTDIR/") + endif () + + install(CODE " + execute_process( + COMMAND + python3 ${CMAKE_CURRENT_SOURCE_DIR}/python/setup.py install + --prefix ${CMAKE_INSTALL_PREFIX} ${ROOT_ARG} + COMMAND_ECHO STDOUT + WORKING_DIRECTORY ${_cybld} + )" + ) +endif () diff --git a/vnext/external/folly/folly/CPortability.h b/vnext/external/folly/folly/CPortability.h new file mode 100644 index 00000000000..eef20cbaeaa --- /dev/null +++ b/vnext/external/folly/folly/CPortability.h @@ -0,0 +1,338 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +/* These definitions are in a separate file so that they + * may be included from C- as well as C++-based projects. */ + +#include + +/** + * Portable version check. + */ +#ifndef __GNUC_PREREQ +#if defined __GNUC__ && defined __GNUC_MINOR__ +/* nolint */ +#define __GNUC_PREREQ(maj, min) \ + ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) +#else +/* nolint */ +#define __GNUC_PREREQ(maj, min) 0 +#endif +#endif + +// portable version check for clang +#ifndef __CLANG_PREREQ +#if defined __clang__ && defined __clang_major__ && defined __clang_minor__ +/* nolint */ +#define __CLANG_PREREQ(maj, min) \ + ((__clang_major__ << 16) + __clang_minor__ >= ((maj) << 16) + (min)) +#else +/* nolint */ +#define __CLANG_PREREQ(maj, min) 0 +#endif +#endif + +#if defined(__has_builtin) +#define FOLLY_HAS_BUILTIN(...) __has_builtin(__VA_ARGS__) +#else +#define FOLLY_HAS_BUILTIN(...) 0 +#endif + +#if defined(__has_feature) +#define FOLLY_HAS_FEATURE(...) __has_feature(__VA_ARGS__) +#else +#define FOLLY_HAS_FEATURE(...) 0 +#endif + +/* FOLLY_SANITIZE_ADDRESS is defined to 1 if the current compilation unit + * is being compiled with ASAN or HWASAN enabled. + * + * Beware when using this macro in a header file: this macro may change values + * across compilation units if some libraries are built with ASAN/HWASAN enabled + * and some built with ASAN/HWSAN disabled. For instance, this may occur, if + * folly itself was compiled without ASAN/HWSAN but a downstream project that + * uses folly is compiling with ASAN/HWSAN enabled. + * + * Use FOLLY_LIBRARY_SANITIZE_ADDRESS (defined in folly-config.h) to check if + * folly itself was compiled with ASAN enabled. + */ +#ifndef FOLLY_SANITIZE_ADDRESS +#if FOLLY_HAS_FEATURE(address_sanitizer) || defined(__SANITIZE_ADDRESS__) || \ + FOLLY_HAS_FEATURE(hwaddress_sanitizer) +#define FOLLY_SANITIZE_ADDRESS 1 +#endif +#endif + +/* Define attribute wrapper for function attribute used to disable + * address sanitizer instrumentation. Unfortunately, this attribute + * has issues when inlining is used, so disable that as well. */ +#ifdef FOLLY_SANITIZE_ADDRESS +#if defined(__clang__) +#if __has_attribute(__no_sanitize__) +#define FOLLY_DISABLE_ADDRESS_SANITIZER \ + __attribute__((__no_sanitize__("address"), __noinline__)) \ + __attribute__((__no_sanitize__("hwaddress"), __noinline__)) +#elif __has_attribute(__no_address_safety_analysis__) +#define FOLLY_DISABLE_ADDRESS_SANITIZER \ + __attribute__((__no_address_safety_analysis__, __noinline__)) +#elif __has_attribute(__no_sanitize_address__) +#define FOLLY_DISABLE_ADDRESS_SANITIZER \ + __attribute__((__no_sanitize_address__, __noinline__)) +#endif +#elif defined(__GNUC__) +#define FOLLY_DISABLE_ADDRESS_SANITIZER \ + __attribute__((__no_address_safety_analysis__, __noinline__)) +#elif defined(_MSC_VER) +#define FOLLY_DISABLE_ADDRESS_SANITIZER __declspec(no_sanitize_address) +#endif +#endif +#ifndef FOLLY_DISABLE_ADDRESS_SANITIZER +#define FOLLY_DISABLE_ADDRESS_SANITIZER +#endif + +/* Define a convenience macro to test when thread sanitizer is being used + * across the different compilers (e.g. clang, gcc) */ +#ifndef FOLLY_SANITIZE_THREAD +#if FOLLY_HAS_FEATURE(thread_sanitizer) || defined(__SANITIZE_THREAD__) +#define FOLLY_SANITIZE_THREAD 1 +#endif +#endif + +#ifdef FOLLY_SANITIZE_THREAD +#define FOLLY_DISABLE_THREAD_SANITIZER \ + __attribute__((no_sanitize_thread, noinline)) +#else +#define FOLLY_DISABLE_THREAD_SANITIZER +#endif + +/** + * Define a convenience macro to test when memory sanitizer is being used + * across the different compilers (e.g. clang, gcc) + */ +#ifndef FOLLY_SANITIZE_MEMORY +#if FOLLY_HAS_FEATURE(memory_sanitizer) || defined(__SANITIZE_MEMORY__) +#define FOLLY_SANITIZE_MEMORY 1 +#endif +#endif + +#ifdef FOLLY_SANITIZE_MEMORY +#define FOLLY_DISABLE_MEMORY_SANITIZER \ + __attribute__((no_sanitize_memory, noinline)) +#else +#define FOLLY_DISABLE_MEMORY_SANITIZER +#endif + +/** + * Define a convenience macro to test when dataflow sanitizer is being used + * across the different compilers (e.g. clang, gcc) + */ +#ifndef FOLLY_SANITIZE_DATAFLOW +#if FOLLY_HAS_FEATURE(dataflow_sanitizer) || defined(__SANITIZE_DATAFLOW__) +#define FOLLY_SANITIZE_DATAFLOW 1 +#endif +#endif + +#ifdef FOLLY_SANITIZE_DATAFLOW +#define FOLLY_DISABLE_DATAFLOW_SANITIZER \ + __attribute__((no_sanitize_dataflow, noinline)) +#else +#define FOLLY_DISABLE_DATAFLOW_SANITIZER +#endif + +/** + * Define a convenience macro to test when undefined-behavior sanitizer is being + * used across the different compilers (e.g. clang, gcc) + */ +#ifndef FOLLY_SANITIZE_UNDEFINED_BEHAVIOR +#if FOLLY_HAS_FEATURE(undefined_behavior_sanitizer) || \ + defined(__SANITIZER_UNDEFINED__) +#define FOLLY_SANITIZE_UNDEFINED_BEHAVIOR(...) 1 +#endif +#endif + +#ifdef FOLLY_SANITIZE_UNDEFINED_BEHAVIOR +#define FOLLY_DISABLE_UNDEFINED_BEHAVIOR_SANITIZER(...) \ + __attribute__((no_sanitize(__VA_ARGS__))) +#else +#define FOLLY_DISABLE_UNDEFINED_BEHAVIOR_SANITIZER(...) +#endif + +/** + * Define a convenience macro to test when ASAN, UBSAN, TSAN or MSAN sanitizer + * are being used + */ +#ifndef FOLLY_SANITIZE +#if defined(FOLLY_SANITIZE_ADDRESS) || defined(FOLLY_SANITIZE_THREAD) || \ + defined(FOLLY_SANITIZE_MEMORY) || defined(FOLLY_SANITIZE_DATAFLOW) || \ + defined(FOLLY_SANITIZE_UNDEFINED_BEHAVIOR) +#define FOLLY_SANITIZE 1 +#endif +#endif + +#define FOLLY_DISABLE_SANITIZERS \ + FOLLY_DISABLE_ADDRESS_SANITIZER \ + FOLLY_DISABLE_THREAD_SANITIZER \ + FOLLY_DISABLE_MEMORY_SANITIZER \ + FOLLY_DISABLE_UNDEFINED_BEHAVIOR_SANITIZER("undefined") + +/** + * Macro for marking functions as having public visibility. + */ +#if defined(__GNUC__) +#define FOLLY_EXPORT __attribute__((__visibility__("default"))) +#else +#define FOLLY_EXPORT +#endif + +// noinline +#ifdef _MSC_VER +#define FOLLY_NOINLINE __declspec(noinline) +#elif defined(__HIP_PLATFORM_HCC__) +// HIP software stack defines its own __noinline__ macro. +#define FOLLY_NOINLINE __attribute__((noinline)) +#elif defined(__GNUC__) +#define FOLLY_NOINLINE __attribute__((__noinline__)) +#else +#define FOLLY_NOINLINE +#endif + +// always inline +#ifdef _MSC_VER +#define FOLLY_ALWAYS_INLINE __forceinline +#elif defined(__GNUC__) +#define FOLLY_ALWAYS_INLINE inline __attribute__((__always_inline__)) +#else +#define FOLLY_ALWAYS_INLINE inline +#endif + +// attribute hidden +#if defined(_MSC_VER) +#define FOLLY_ATTR_VISIBILITY_HIDDEN +#elif defined(__GNUC__) +#define FOLLY_ATTR_VISIBILITY_HIDDEN __attribute__((__visibility__("hidden"))) +#else +#define FOLLY_ATTR_VISIBILITY_HIDDEN +#endif + +// An attribute for marking symbols as weak, if supported +#if FOLLY_HAVE_WEAK_SYMBOLS +#define FOLLY_ATTR_WEAK __attribute__((__weak__)) +#else +#define FOLLY_ATTR_WEAK +#endif + +// Microsoft ABI version (can be overridden manually if necessary) +#ifndef FOLLY_MICROSOFT_ABI_VER +#ifdef _MSC_VER +#define FOLLY_MICROSOFT_ABI_VER _MSC_VER +#endif +#endif + +// FOLLY_ERASE +// +// A conceptual attribute/syntax combo for erasing a function from the build +// artifacts and forcing all call-sites to inline the callee, at least as far +// as each compiler supports. +// +// Semantically includes the inline specifier. +#define FOLLY_ERASE FOLLY_ALWAYS_INLINE FOLLY_ATTR_VISIBILITY_HIDDEN + +// FOLLY_ERASE_NOINLINE +// +// Like FOLLY_ERASE, but also noinline. The naming similarity with FOLLY_ERASE +// is specifically desirable. +#define FOLLY_ERASE_NOINLINE FOLLY_NOINLINE FOLLY_ATTR_VISIBILITY_HIDDEN + +// FOLLY_ERASE_HACK_GCC +// +// Equivalent to FOLLY_ERASE, but without hiding under gcc. Useful when applied +// to a function which may sometimes be hidden separately, for example by being +// declared in an anonymous namespace, since in such cases with -Wattributes +// enabled, gcc would emit: 'visibility' attribute ignored. +// +// Semantically includes the inline specifier. +#if defined(__GNUC__) && !defined(__clang__) +#define FOLLY_ERASE_HACK_GCC FOLLY_ALWAYS_INLINE +#else +#define FOLLY_ERASE_HACK_GCC FOLLY_ERASE +#endif + +// FOLLY_ERASE_TRYCATCH +// +// Equivalent to FOLLY_ERASE, but for code which might contain explicit +// exception handling. Has the effect of FOLLY_ERASE, except under MSVC which +// warns about __forceinline when functions contain exception handling. +// +// Semantically includes the inline specifier. +#ifdef _MSC_VER +#define FOLLY_ERASE_TRYCATCH inline +#else +#define FOLLY_ERASE_TRYCATCH FOLLY_ERASE +#endif + +// Generalize warning push/pop. +#if defined(__GNUC__) || defined(__clang__) +// Clang & GCC +#define FOLLY_PUSH_WARNING _Pragma("GCC diagnostic push") +#define FOLLY_POP_WARNING _Pragma("GCC diagnostic pop") +#define FOLLY_GNU_DISABLE_WARNING_INTERNAL2(warningName) #warningName +#define FOLLY_GNU_DISABLE_WARNING(warningName) \ + _Pragma( \ + FOLLY_GNU_DISABLE_WARNING_INTERNAL2(GCC diagnostic ignored warningName)) +#ifdef __clang__ +#define FOLLY_CLANG_DISABLE_WARNING(warningName) \ + FOLLY_GNU_DISABLE_WARNING(warningName) +#define FOLLY_GCC_DISABLE_WARNING(warningName) +#else +#define FOLLY_CLANG_DISABLE_WARNING(warningName) +#define FOLLY_GCC_DISABLE_WARNING(warningName) \ + FOLLY_GNU_DISABLE_WARNING(warningName) +#endif +#define FOLLY_MSVC_DISABLE_WARNING(warningNumber) +#elif defined(_MSC_VER) +#define FOLLY_PUSH_WARNING __pragma(warning(push)) +#define FOLLY_POP_WARNING __pragma(warning(pop)) +// Disable the GCC warnings. +#define FOLLY_GNU_DISABLE_WARNING(warningName) +#define FOLLY_GCC_DISABLE_WARNING(warningName) +#define FOLLY_CLANG_DISABLE_WARNING(warningName) +#define FOLLY_MSVC_DISABLE_WARNING(warningNumber) \ + __pragma(warning(disable : warningNumber)) +#else +#define FOLLY_PUSH_WARNING +#define FOLLY_POP_WARNING +#define FOLLY_GNU_DISABLE_WARNING(warningName) +#define FOLLY_GCC_DISABLE_WARNING(warningName) +#define FOLLY_CLANG_DISABLE_WARNING(warningName) +#define FOLLY_MSVC_DISABLE_WARNING(warningNumber) +#endif + +#ifdef FOLLY_HAVE_SHADOW_LOCAL_WARNINGS +#define FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS \ + FOLLY_GNU_DISABLE_WARNING("-Wshadow-compatible-local") \ + FOLLY_GNU_DISABLE_WARNING("-Wshadow-local") \ + FOLLY_GNU_DISABLE_WARNING("-Wshadow") +#else +#define FOLLY_GCC_DISABLE_NEW_SHADOW_WARNINGS /* empty */ +#endif + +#if defined(_MSC_VER) +#define FOLLY_MSVC_DECLSPEC(...) __declspec(__VA_ARGS__) +#else +#define FOLLY_MSVC_DECLSPEC(...) +#endif diff --git a/vnext/external/folly/folly/CancellationToken-inl.h b/vnext/external/folly/folly/CancellationToken-inl.h new file mode 100644 index 00000000000..e50dc88a7f3 --- /dev/null +++ b/vnext/external/folly/folly/CancellationToken-inl.h @@ -0,0 +1,449 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include + +namespace folly { + +namespace detail { + +struct FixedMergingCancellationStateTag {}; + +// Internal cancellation state object. +class CancellationState { + public: + FOLLY_NODISCARD static CancellationStateSourcePtr create(); + + protected: + // Constructed initially with a CancellationSource reference count of 1. + CancellationState() noexcept; + // Constructed initially with a CancellationToken reference count of 1. + explicit CancellationState(FixedMergingCancellationStateTag) noexcept; + + virtual ~CancellationState(); + + friend struct CancellationStateTokenDeleter; + friend struct CancellationStateSourceDeleter; + + void removeTokenReference() noexcept; + void removeSourceReference() noexcept; + + public: + FOLLY_NODISCARD CancellationStateTokenPtr addTokenReference() noexcept; + + FOLLY_NODISCARD CancellationStateSourcePtr addSourceReference() noexcept; + + bool tryAddCallback( + CancellationCallback* callback, + bool incrementRefCountIfSuccessful) noexcept; + + void removeCallback(CancellationCallback* callback) noexcept; + + bool isCancellationRequested() const noexcept; + bool canBeCancelled() const noexcept; + + // Request cancellation. + // Return 'true' if cancellation had already been requested. + // Return 'false' if this was the first thread to request + // cancellation. + bool requestCancellation() noexcept; + + private: + void lock() noexcept; + void unlock() noexcept; + void unlockAndIncrementTokenCount() noexcept; + void unlockAndDecrementTokenCount() noexcept; + bool tryLockAndCancelUnlessCancelled() noexcept; + + template + bool tryLock(Predicate predicate) noexcept; + + static bool canBeCancelled(std::uint64_t state) noexcept; + static bool isCancellationRequested(std::uint64_t state) noexcept; + static bool isLocked(std::uint64_t state) noexcept; + + static constexpr std::uint64_t kCancellationRequestedFlag = 1; + static constexpr std::uint64_t kLockedFlag = 2; + static constexpr std::uint64_t kMergingFlag = 4; + static constexpr std::uint64_t kTokenReferenceCountIncrement = 8; + static constexpr std::uint64_t kSourceReferenceCountIncrement = + std::uint64_t(1) << 34u; + static constexpr std::uint64_t kTokenReferenceCountMask = + (kSourceReferenceCountIncrement - 1u) - + (kTokenReferenceCountIncrement - 1u); + static constexpr std::uint64_t kSourceReferenceCountMask = + std::numeric_limits::max() - + (kSourceReferenceCountIncrement - 1u); + + // Bit 0 - Cancellation Requested + // Bit 1 - Locked Flag + // Bit 2 - MergingCancellationState Flag + // Bits 3-33 - Token reference count (max ~2 billion) + // Bits 34-63 - Source reference count (max ~1 billion) + std::atomic state_; + CancellationCallback* head_{nullptr}; + std::thread::id signallingThreadId_; +}; + +template +class FixedMergingCancellationState : public CancellationState { + template + FixedMergingCancellationState(Ts&&... tokens); + + public: + template + FOLLY_NODISCARD static CancellationStateTokenPtr create(Ts&&... tokens); + + private: + std::array callbacks_; +}; + +template +class CancellationStateWithData : public CancellationState { + template + CancellationStateWithData(Args&&... data); + + public: + template + FOLLY_NODISCARD static std:: + pair*> + create(Args&&... data); + + private: + std::tuple data_; +}; + +inline void CancellationStateTokenDeleter::operator()( + CancellationState* state) noexcept { + state->removeTokenReference(); +} + +inline void CancellationStateSourceDeleter::operator()( + CancellationState* state) noexcept { + state->removeSourceReference(); +} + +} // namespace detail + +inline CancellationToken::CancellationToken( + const CancellationToken& other) noexcept + : state_() { + if (other.state_) { + state_ = other.state_->addTokenReference(); + } +} + +inline CancellationToken::CancellationToken(CancellationToken&& other) noexcept + : state_(std::move(other.state_)) {} + +inline CancellationToken& CancellationToken::operator=( + const CancellationToken& other) noexcept { + if (state_ != other.state_) { + CancellationToken temp{other}; + swap(temp); + } + return *this; +} + +inline CancellationToken& CancellationToken::operator=( + CancellationToken&& other) noexcept { + state_ = std::move(other.state_); + return *this; +} + +inline bool CancellationToken::isCancellationRequested() const noexcept { + return state_ != nullptr && state_->isCancellationRequested(); +} + +inline bool CancellationToken::canBeCancelled() const noexcept { + return state_ != nullptr && state_->canBeCancelled(); +} + +inline void CancellationToken::swap(CancellationToken& other) noexcept { + std::swap(state_, other.state_); +} + +inline CancellationToken::CancellationToken( + detail::CancellationStateTokenPtr state) noexcept + : state_(std::move(state)) {} + +inline bool operator==( + const CancellationToken& a, const CancellationToken& b) noexcept { + return a.state_ == b.state_; +} + +inline bool operator!=( + const CancellationToken& a, const CancellationToken& b) noexcept { + return !(a == b); +} + +inline CancellationSource::CancellationSource() + : state_(detail::CancellationState::create()) {} + +inline CancellationSource::CancellationSource( + const CancellationSource& other) noexcept + : state_() { + if (other.state_) { + state_ = other.state_->addSourceReference(); + } +} + +inline CancellationSource::CancellationSource( + CancellationSource&& other) noexcept + : state_(std::move(other.state_)) {} + +inline CancellationSource& CancellationSource::operator=( + const CancellationSource& other) noexcept { + if (state_ != other.state_) { + CancellationSource temp{other}; + swap(temp); + } + return *this; +} + +inline CancellationSource& CancellationSource::operator=( + CancellationSource&& other) noexcept { + state_ = std::move(other.state_); + return *this; +} + +inline CancellationSource CancellationSource::invalid() noexcept { + return CancellationSource{detail::CancellationStateSourcePtr{}}; +} + +inline bool CancellationSource::isCancellationRequested() const noexcept { + return state_ != nullptr && state_->isCancellationRequested(); +} + +inline bool CancellationSource::canBeCancelled() const noexcept { + return state_ != nullptr; +} + +inline CancellationToken CancellationSource::getToken() const noexcept { + if (state_ != nullptr) { + return CancellationToken{state_->addTokenReference()}; + } + return CancellationToken{}; +} + +inline bool CancellationSource::requestCancellation() const noexcept { + if (state_ != nullptr) { + return state_->requestCancellation(); + } + return false; +} + +inline void CancellationSource::swap(CancellationSource& other) noexcept { + std::swap(state_, other.state_); +} + +inline CancellationSource::CancellationSource( + detail::CancellationStateSourcePtr&& state) noexcept + : state_(std::move(state)) {} + +template < + typename Callable, + std::enable_if_t< + std::is_constructible:: + value, + int>> +inline CancellationCallback::CancellationCallback( + CancellationToken&& ct, Callable&& callable) + : next_(nullptr), + prevNext_(nullptr), + state_(nullptr), + callback_(static_cast(callable)), + destructorHasRunInsideCallback_(nullptr), + callbackCompleted_(false) { + if (ct.state_ != nullptr && ct.state_->tryAddCallback(this, false)) { + state_ = ct.state_.release(); + } +} + +template < + typename Callable, + std::enable_if_t< + std::is_constructible:: + value, + int>> +inline CancellationCallback::CancellationCallback( + const CancellationToken& ct, Callable&& callable) + : next_(nullptr), + prevNext_(nullptr), + state_(nullptr), + callback_(static_cast(callable)), + destructorHasRunInsideCallback_(nullptr), + callbackCompleted_(false) { + if (ct.state_ != nullptr && ct.state_->tryAddCallback(this, true)) { + state_ = ct.state_.get(); + } +} + +inline CancellationCallback::~CancellationCallback() { + if (state_ != nullptr) { + state_->removeCallback(this); + } +} + +inline void CancellationCallback::invokeCallback() noexcept { + // Invoke within a noexcept context so that we std::terminate() if it throws. + callback_(); +} + +namespace detail { + +inline CancellationStateSourcePtr CancellationState::create() { + return CancellationStateSourcePtr{new CancellationState()}; +} + +inline CancellationState::CancellationState() noexcept + : state_(kSourceReferenceCountIncrement) {} +inline CancellationState::CancellationState( + FixedMergingCancellationStateTag) noexcept + : state_(kTokenReferenceCountIncrement | kMergingFlag) {} + +inline CancellationStateTokenPtr +CancellationState::addTokenReference() noexcept { + state_.fetch_add(kTokenReferenceCountIncrement, std::memory_order_relaxed); + return CancellationStateTokenPtr{this}; +} + +inline void CancellationState::removeTokenReference() noexcept { + const auto oldState = state_.fetch_sub( + kTokenReferenceCountIncrement, std::memory_order_acq_rel); + DCHECK( + (oldState & kTokenReferenceCountMask) >= kTokenReferenceCountIncrement); + if (oldState < (2 * kTokenReferenceCountIncrement)) { + delete this; + } +} + +inline CancellationStateSourcePtr +CancellationState::addSourceReference() noexcept { + state_.fetch_add(kSourceReferenceCountIncrement, std::memory_order_relaxed); + return CancellationStateSourcePtr{this}; +} + +inline void CancellationState::removeSourceReference() noexcept { + const auto oldState = state_.fetch_sub( + kSourceReferenceCountIncrement, std::memory_order_acq_rel); + DCHECK( + (oldState & kSourceReferenceCountMask) >= kSourceReferenceCountIncrement); + if (oldState < + (kSourceReferenceCountIncrement + kTokenReferenceCountIncrement)) { + delete this; + } +} + +inline bool CancellationState::isCancellationRequested() const noexcept { + return isCancellationRequested(state_.load(std::memory_order_acquire)); +} + +inline bool CancellationState::canBeCancelled() const noexcept { + return canBeCancelled(state_.load(std::memory_order_acquire)); +} + +inline bool CancellationState::canBeCancelled(std::uint64_t state) noexcept { + // Can be cancelled if there is at least one CancellationSource ref-count + // or if cancellation has been requested. + return (state >= kSourceReferenceCountIncrement) || + (state & kMergingFlag) != 0 || isCancellationRequested(state); +} + +inline bool CancellationState::isCancellationRequested( + std::uint64_t state) noexcept { + return (state & kCancellationRequestedFlag) != 0; +} + +inline bool CancellationState::isLocked(std::uint64_t state) noexcept { + return (state & kLockedFlag) != 0; +} + +template +template +inline CancellationStateTokenPtr FixedMergingCancellationState::create( + Ts&&... tokens) { + return CancellationStateTokenPtr{ + new FixedMergingCancellationState(std::forward(tokens)...)}; +} + +template +struct WithDataTag {}; + +template +template +inline FixedMergingCancellationState::FixedMergingCancellationState( + Ts&&... tokens) + : CancellationState(FixedMergingCancellationStateTag{}), + callbacks_{ + {{std::forward(tokens), [this] { requestCancellation(); }}...}} {} + +template +template +CancellationStateWithData::CancellationStateWithData(Args&&... data) + : data_(std::forward(data)...) {} + +template +template +std::pair*> +CancellationStateWithData::create(Args&&... data) { + auto* state = + new CancellationStateWithData(std::forward(data)...); + return {CancellationStateSourcePtr{state}, &state->data_}; +} + +inline bool variadicDisjunction() { + return false; +} + +inline bool variadicDisjunction(bool first) { + return first; +} + +template +bool variadicDisjunction(bool first, Bools... bools) { + return first || variadicDisjunction(bools...); +} +} // namespace detail + +template +std::pair*> CancellationSource::create( + detail::WithDataTag, Args&&... data) { + auto cancellationStateWithData = + detail::CancellationStateWithData::create( + std::forward(data)...); + return { + CancellationSource{std::move(cancellationStateWithData.first)}, + cancellationStateWithData.second}; +} + +template +inline CancellationToken CancellationToken::merge(Ts&&... tokens) { + bool canBeCancelled = detail::variadicDisjunction(tokens.canBeCancelled()...); + return canBeCancelled + ? CancellationToken( + detail::FixedMergingCancellationState::create( + std::forward(tokens)...)) + : CancellationToken(); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/CancellationToken.cpp b/vnext/external/folly/folly/CancellationToken.cpp new file mode 100644 index 00000000000..aa29e189889 --- /dev/null +++ b/vnext/external/folly/folly/CancellationToken.cpp @@ -0,0 +1,250 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include + +#include + +#include +#include +#include +#include + +namespace folly { +namespace detail { + +CancellationState::~CancellationState() { + DCHECK(head_ == nullptr); + DCHECK(!isLocked(state_.load(std::memory_order_relaxed))); + DCHECK( + state_.load(std::memory_order_relaxed) < kTokenReferenceCountIncrement); +} + +bool CancellationState::tryAddCallback( + CancellationCallback* callback, + bool incrementRefCountIfSuccessful) noexcept { + // Try to acquire the lock, but abandon trying to acquire the lock if + // cancellation has already been requested (we can just immediately invoke + // the callback) or if cancellation can never be requested (we can just + // skip registration). + if (!tryLock([callback](std::uint64_t oldState) noexcept { + if (isCancellationRequested(oldState)) { + callback->invokeCallback(); + return false; + } + return canBeCancelled(oldState); + })) { + return false; + } + + // We've acquired the lock and cancellation has not yet been requested. + // Push this callback onto the head of the list. + if (head_ != nullptr) { + head_->prevNext_ = &callback->next_; + } + callback->next_ = head_; + callback->prevNext_ = &head_; + head_ = callback; + + if (incrementRefCountIfSuccessful) { + // Combine multiple atomic operations into a single atomic operation. + unlockAndIncrementTokenCount(); + } else { + unlock(); + } + + // Successfully added the callback. + return true; +} + +void CancellationState::removeCallback( + CancellationCallback* callback) noexcept { + DCHECK(callback != nullptr); + + lock(); + + if (callback->prevNext_ != nullptr) { + // Still registered in the list => not yet executed. + // Just remove it from the list. + *callback->prevNext_ = callback->next_; + if (callback->next_ != nullptr) { + callback->next_->prevNext_ = callback->prevNext_; + } + + unlockAndDecrementTokenCount(); + return; + } + + unlock(); + + // Callback has either already executed or is executing concurrently on + // another thread. + + if (signallingThreadId_ == std::this_thread::get_id()) { + // Callback executed on this thread or is still currently executing + // and is deregistering itself from within the callback. + if (callback->destructorHasRunInsideCallback_ != nullptr) { + // Currently inside the callback, let the requestCancellation() method + // know the object is about to be destructed and that it should + // not try to access the object when the callback returns. + *callback->destructorHasRunInsideCallback_ = true; + } + } else { + // Callback is currently executing on another thread, block until it + // finishes executing. + folly::detail::Sleeper sleeper; + while (!callback->callbackCompleted_.load(std::memory_order_acquire)) { + sleeper.wait(); + } + } + + removeTokenReference(); +} + +bool CancellationState::requestCancellation() noexcept { + if (!tryLockAndCancelUnlessCancelled()) { + // Was already marked as cancelled + return true; + } + + // This thread marked as cancelled and acquired the lock + + signallingThreadId_ = std::this_thread::get_id(); + + while (head_ != nullptr) { + // Dequeue the first item on the queue. + CancellationCallback* callback = head_; + head_ = callback->next_; + const bool anyMore = head_ != nullptr; + if (anyMore) { + head_->prevNext_ = &head_; + } + // Mark this item as removed from the list. + callback->prevNext_ = nullptr; + + // Don't hold the lock while executing the callback + // as we don't want to block other threads from + // deregistering callbacks. + unlock(); + + // TRICKY: Need to store a flag on the stack here that the callback + // can use to signal that the destructor was executed inline + // during the call. + // If the destructor was executed inline then it's not safe to + // dereference 'callback' after 'invokeCallback()' returns. + // If the destructor runs on some other thread then the other + // thread will block waiting for this thread to signal that the + // callback has finished executing. + bool destructorHasRunInsideCallback = false; + callback->destructorHasRunInsideCallback_ = &destructorHasRunInsideCallback; + + callback->invokeCallback(); + + if (!destructorHasRunInsideCallback) { + callback->destructorHasRunInsideCallback_ = nullptr; + callback->callbackCompleted_.store(true, std::memory_order_release); + } + + if (!anyMore) { + // This was the last item in the queue when we dequeued it. + // No more items should be added to the queue after we have + // marked the state as cancelled, only removed from the queue. + // Avoid acquiring/releasing the lock in this case. + return false; + } + + lock(); + } + + unlock(); + + return false; +} + +void CancellationState::lock() noexcept { + folly::detail::Sleeper sleeper; + std::uint64_t oldState = state_.load(std::memory_order_relaxed); + do { + while (isLocked(oldState)) { + sleeper.wait(); + oldState = state_.load(std::memory_order_relaxed); + } + } while (!state_.compare_exchange_weak( + oldState, + oldState | kLockedFlag, + std::memory_order_acquire, + std::memory_order_relaxed)); +} + +void CancellationState::unlock() noexcept { + state_.fetch_sub(kLockedFlag, std::memory_order_release); +} + +void CancellationState::unlockAndIncrementTokenCount() noexcept { + state_.fetch_sub( + kLockedFlag - kTokenReferenceCountIncrement, std::memory_order_release); +} + +void CancellationState::unlockAndDecrementTokenCount() noexcept { + auto oldState = state_.fetch_sub( + kLockedFlag + kTokenReferenceCountIncrement, std::memory_order_acq_rel); + if (oldState < (kLockedFlag + 2 * kTokenReferenceCountIncrement)) { + delete this; + } +} + +bool CancellationState::tryLockAndCancelUnlessCancelled() noexcept { + folly::detail::Sleeper sleeper; + std::uint64_t oldState = state_.load(std::memory_order_acquire); + while (true) { + if (isCancellationRequested(oldState)) { + return false; + } else if (isLocked(oldState)) { + sleeper.wait(); + oldState = state_.load(std::memory_order_acquire); + } else if (state_.compare_exchange_weak( + oldState, + oldState | kLockedFlag | kCancellationRequestedFlag, + std::memory_order_acq_rel, + std::memory_order_acquire)) { + return true; + } + } +} + +template +bool CancellationState::tryLock(Predicate predicate) noexcept { + folly::detail::Sleeper sleeper; + std::uint64_t oldState = state_.load(std::memory_order_acquire); + while (true) { + if (!predicate(oldState)) { + return false; + } else if (isLocked(oldState)) { + sleeper.wait(); + oldState = state_.load(std::memory_order_acquire); + } else if (state_.compare_exchange_weak( + oldState, + oldState | kLockedFlag, + std::memory_order_acquire)) { + return true; + } + } +} + +} // namespace detail +} // namespace folly diff --git a/vnext/external/folly/folly/CancellationToken.h b/vnext/external/folly/folly/CancellationToken.h new file mode 100644 index 00000000000..ab147e30238 --- /dev/null +++ b/vnext/external/folly/folly/CancellationToken.h @@ -0,0 +1,365 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include +#include + +namespace folly { + +class CancellationCallback; +class CancellationSource; +struct OperationCancelled : public std::exception { + const char* what() const noexcept override { + return "coroutine operation cancelled"; + } +}; + +namespace detail { +class CancellationState; +struct CancellationStateTokenDeleter { + void operator()(CancellationState*) noexcept; +}; +struct CancellationStateSourceDeleter { + void operator()(CancellationState*) noexcept; +}; +using CancellationStateTokenPtr = + std::unique_ptr; +using CancellationStateSourcePtr = + std::unique_ptr; +template +struct WithDataTag; +} // namespace detail + +/** + * A CancellationToken is an object that can be passed into an function or + * operation that allows the caller to later request that the operation be + * cancelled. + * + * A CancellationToken object can be obtained by calling the .getToken() + * method on a CancellationSource or by copying another CancellationToken + * object. All CancellationToken objects obtained from the same original + * CancellationSource object all reference the same underlying cancellation + * state and will all be cancelled together. + * + * If your function needs to be cancellable but does not need to request + * cancellation then you should take a CancellationToken as a parameter. + * If your function needs to be able to request cancellation then you + * should instead take a CancellationSource as a parameter. + * + * @refcode folly/docs/examples/folly/CancellationToken.cpp + * @class folly::CancellationToken + */ +class CancellationToken { + public: + /** + * Constructs to a token that can never be cancelled. + * + * Pass a default-constructed CancellationToken into an operation that + * you never intend to cancel. These objects are very cheap to create. + */ + CancellationToken() noexcept = default; + + /// Construct a copy of the token that shares the same underlying state. + CancellationToken(const CancellationToken& other) noexcept; + + /// Construct a token by moving the underlying state + CancellationToken(CancellationToken&& other) noexcept; + + CancellationToken& operator=(const CancellationToken& other) noexcept; + CancellationToken& operator=(CancellationToken&& other) noexcept; + + /** + * Query whether someone has called .requestCancellation() on an instance + * of CancellationSource object associated with this CancellationToken. + */ + bool isCancellationRequested() const noexcept; + + /** + * Query whether this CancellationToken can ever have cancellation requested + * on it. + * + * This will return false if the CancellationToken is not associated with a + * CancellationSource object. eg. because the CancellationToken was + * default-constructed, has been moved-from or because the last + * CancellationSource object associated with the underlying cancellation state + * has been destroyed and the operation has not yet been cancelled and so + * never will be. + * + * Implementations of operations may be able to take more efficient code-paths + * if they know they can never be cancelled. + */ + bool canBeCancelled() const noexcept; + + /** + * Obtain a CancellationToken linked to any number of other + * CancellationTokens. + * + * This token will have cancellation requested when any of the passed-in + * tokens do. + * This token is cancellable if any of the passed-in tokens are at the time of + * construction. + */ + template + static CancellationToken merge(Ts&&... tokens); + + /** + * Swaps the underlying state of the cancellation token with the token that is + * passed-in. + */ + void swap(CancellationToken& other) noexcept; + + friend bool operator==( + const CancellationToken& a, const CancellationToken& b) noexcept; + + private: + friend class CancellationCallback; + friend class CancellationSource; + + explicit CancellationToken(detail::CancellationStateTokenPtr state) noexcept; + + detail::CancellationStateTokenPtr state_; +}; + +bool operator==( + const CancellationToken& a, const CancellationToken& b) noexcept; +bool operator!=( + const CancellationToken& a, const CancellationToken& b) noexcept; + +/** + * A CancellationSource object provides the ability to request cancellation of + * operations that an associated CancellationToken was passed to. + * + * @refcode folly/docs/examples/folly/CancellationSource.cpp + * @class folly::CancellationSource + */ +// Example usage: +// CancellationSource cs; +// Future f = startSomeOperation(cs.getToken()); +// +// // Later... +// cs.requestCancellation(); +class CancellationSource { + public: + /// Construct to a new, independent cancellation source. + CancellationSource(); + + /** + * Construct a new reference to the same underlying cancellation state. + * + * Either the original or the new copy can be used to request cancellation + * of associated work. + */ + CancellationSource(const CancellationSource& other) noexcept; + + /** + * This leaves 'other' in an empty state where 'requestCancellation()' is a + * no-op and 'canBeCancelled()' returns false. + */ + CancellationSource(CancellationSource&& other) noexcept; + + CancellationSource& operator=(const CancellationSource& other) noexcept; + CancellationSource& operator=(CancellationSource&& other) noexcept; + + /** + * Construct a CancellationSource that cannot be cancelled. + * + * This factory function can be used to obtain a CancellationSource that + * is equivalent to a moved-from CancellationSource object without needing + * to allocate any shared-state. + */ + static CancellationSource invalid() noexcept; + + /** + * Query if cancellation has already been requested on this CancellationSource + * or any other CancellationSource object copied from the same original + * CancellationSource object. + */ + bool isCancellationRequested() const noexcept; + + /** + * Query if cancellation can be requested through this CancellationSource + * object. This will only return false if the CancellationSource object has + * been moved-from. + */ + bool canBeCancelled() const noexcept; + + /** + * Obtain a CancellationToken linked to this CancellationSource. + * + * This token can be passed into cancellable operations to allow the caller + * to later request cancellation of that operation. + */ + CancellationToken getToken() const noexcept; + + /** + * Request cancellation of work associated with this CancellationSource. + * + * This will ensure subsequent calls to isCancellationRequested() on any + * CancellationSource or CancellationToken object associated with the same + * underlying cancellation state to return true. + * + * If this is the first call to requestCancellation() on any + * CancellationSource object with the same underlying state then this call + * will also execute the callbacks associated with any CancellationCallback + * objects that were constructed with an associated CancellationToken. + * + * Note that it is possible that another thread may be concurrently + * registering a callback with CancellationCallback. This method guarantees + * that either this thread will see the callback registration and will + * ensure that the callback is called, or the CancellationCallback constructor + * will see the cancellation-requested signal and will execute the callback + * inline inside the constructor. + * + * Returns the previous state of 'isCancellationRequested()'. i.e. + * - 'true' if cancellation had previously been requested. + * - 'false' if this was the first call to request cancellation. + */ + bool requestCancellation() const noexcept; + + /** + * Swaps the underlying state of the cancellation source with the source that + * is passed-in. + * + * @param other The other cancellation source to copy the underlying state + * from. + */ + void swap(CancellationSource& other) noexcept; + + friend bool operator==( + const CancellationSource& a, const CancellationSource& b) noexcept; + + /** + * Returns a pair of where the underlying state is + * created using the arguments that is passed-in. + */ + template + static std::pair*> create( + detail::WithDataTag, Args&&...); + + private: + explicit CancellationSource( + detail::CancellationStateSourcePtr&& state) noexcept; + + detail::CancellationStateSourcePtr state_; +}; + +bool operator==( + const CancellationSource& a, const CancellationSource& b) noexcept; +bool operator!=( + const CancellationSource& a, const CancellationSource& b) noexcept; + +/** + * A CancellationCallback object registers the callback with the specified + * CancellationToken such that the callback will be + * executed if the corresponding CancellationSource object has the + * requestCancellation() method called on it. + * + * If the CancellationToken object already had cancellation requested + * then the callback will be executed inline on the current thread before + * the constructor returns. Otherwise, the callback will be executed on + * in the execution context of the first thread to call requestCancellation() + * on a corresponding CancellationSource. + * + * The callback object must not throw any unhandled exceptions. Doing so + * will result in the program terminating via std::terminate(). + * + * A CancellationCallback object is neither copyable nor movable. + * + * @refcode folly/docs/examples/folly/CancellationCallback.cpp + * @class folly::CancellationCallback + */ +class CancellationCallback { + using VoidFunction = folly::Function; + + public: + template < + typename Callable, + std::enable_if_t< + std::is_constructible::value, + int> = 0> + CancellationCallback(CancellationToken&& ct, Callable&& callable); + template < + typename Callable, + std::enable_if_t< + std::is_constructible::value, + int> = 0> + CancellationCallback(const CancellationToken& ct, Callable&& callable); + + /** + * Deregisters the callback from the CancellationToken. + * + * If cancellation has been requested concurrently on another thread and the + * callback is currently executing then the destructor will block until after + * the callback has returned (otherwise it might be left with a dangling + * reference). + * + * You should generally try to implement your callback functions to be lock + * free to avoid deadlocks between the callback executing and the + * CancellationCallback destructor trying to deregister the callback. + * + * If the callback has not started executing yet then the callback will be + * deregistered from the CancellationToken before the destructor completes. + * + * Once the destructor returns you can be guaranteed that the callback will + * not be called by a subsequent call to 'requestCancellation()' on a + * CancellationSource associated with the CancellationToken passed to the + * constructor. + */ + ~CancellationCallback(); + + // Not copyable/movable + CancellationCallback(const CancellationCallback&) = delete; + CancellationCallback(CancellationCallback&&) = delete; + CancellationCallback& operator=(const CancellationCallback&) = delete; + CancellationCallback& operator=(CancellationCallback&&) = delete; + + private: + friend class detail::CancellationState; + + void invokeCallback() noexcept; + + CancellationCallback* next_; + + // Pointer to the pointer that points to this node in the linked list. + // This could be the 'next_' of a previous CancellationCallback or could + // be the 'head_' pointer of the CancellationState. + // If this node is inserted in the list then this will be non-null. + CancellationCallback** prevNext_; + + detail::CancellationState* state_; + VoidFunction callback_; + + // Pointer to a flag stored on the stack of the caller to invokeCallback() + // that is used to indicate to the caller of invokeCallback() that the + // destructor has run and it is no longer valid to access the callback + // object. + bool* destructorHasRunInsideCallback_; + + // Flag used to signal that the callback has completed executing on another + // thread and it is now safe to exit the destructor. + std::atomic callbackCompleted_; +}; + +} // namespace folly + +#include diff --git a/vnext/external/folly/folly/Chrono.h b/vnext/external/folly/folly/Chrono.h new file mode 100644 index 00000000000..873b4fb6cb0 --- /dev/null +++ b/vnext/external/folly/folly/Chrono.h @@ -0,0 +1,132 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include + +#include +#include +#include + +namespace folly { +namespace chrono { + +/* using override */ using std::chrono::abs; +/* using override */ using std::chrono::ceil; +/* using override */ using std::chrono::floor; +/* using override */ using std::chrono::round; + +// steady_clock_spec +// +// All clocks with this spec share epoch and tick rate. +struct steady_clock_spec {}; + +// system_clock_spec +// +// All clocks with this spec share epoch and tick rate. +struct system_clock_spec {}; + +// clock_traits +// +// Detects and reexports per-clock traits. +// +// Specializeable for clocks for which trait detection fails.. +template +struct clock_traits { + private: + template + using detect_spec_ = typename C::folly_spec; + + public: + using spec = detected_or_t; +}; + +template <> +struct clock_traits { + using spec = steady_clock_spec; +}; +template <> +struct clock_traits { + using spec = system_clock_spec; +}; + +struct coarse_steady_clock { + using folly_spec = steady_clock_spec; + + using duration = std::chrono::steady_clock::duration; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point; + constexpr static bool is_steady = true; + + static time_point now() noexcept { +#ifndef CLOCK_MONOTONIC_COARSE + auto time = std::chrono::steady_clock::now().time_since_epoch(); +#else + timespec ts; + int ret = clock_gettime(CLOCK_MONOTONIC_COARSE, &ts); + if (kIsDebug && (ret != 0)) { + throw_exception( + "Error using CLOCK_MONOTONIC_COARSE."); + } + auto time = + std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec); +#endif + return time_point(std::chrono::duration_cast(time)); + } +}; + +struct coarse_system_clock { + using folly_spec = system_clock_spec; + + using duration = std::chrono::system_clock::duration; + using rep = duration::rep; + using period = duration::period; + using time_point = std::chrono::time_point; + constexpr static bool is_steady = false; + + static time_point now() noexcept { +#ifndef CLOCK_REALTIME_COARSE + auto time = std::chrono::system_clock::now().time_since_epoch(); +#else + timespec ts; + int ret = clock_gettime(CLOCK_REALTIME_COARSE, &ts); + if (kIsDebug && (ret != 0)) { + throw_exception("Error using CLOCK_REALTIME_COARSE."); + } + auto time = + std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec); +#endif + return time_point(std::chrono::duration_cast(time)); + } + + static std::time_t to_time_t(const time_point& t) noexcept { + auto d = t.time_since_epoch(); + return std::chrono::duration_cast(d).count(); + } + + static time_point from_time_t(std::time_t t) noexcept { + return time_point( + std::chrono::duration_cast(std::chrono::seconds(t))); + } +}; + +} // namespace chrono +} // namespace folly diff --git a/vnext/external/folly/folly/ClockGettimeWrappers.cpp b/vnext/external/folly/folly/ClockGettimeWrappers.cpp new file mode 100644 index 00000000000..f1e36664446 --- /dev/null +++ b/vnext/external/folly/folly/ClockGettimeWrappers.cpp @@ -0,0 +1,93 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include +#include + +#include + +#include + +#ifndef _WIN32 +#define _GNU_SOURCE 1 +#include +#endif + +namespace folly { +namespace chrono { + +static int64_t clock_gettime_ns_fallback(clockid_t clock) { + struct timespec ts; + int r = clock_gettime(clock, &ts); + if (FOLLY_UNLIKELY(r != 0)) { + // Mimic what __clock_gettime_ns does (even though this can be a legit + // value). + return -1; + } + std::chrono::nanoseconds result = + std::chrono::seconds(ts.tv_sec) + std::chrono::nanoseconds(ts.tv_nsec); + return result.count(); +} + +// Initialize with default behavior, which we might override on Linux hosts +// with VDSO support. +int (*clock_gettime)(clockid_t, timespec* ts) = &::clock_gettime; +int64_t (*clock_gettime_ns)(clockid_t) = &clock_gettime_ns_fallback; + +// In MSAN mode use glibc's versions as they are intercepted by the MSAN +// runtime which properly tracks memory initialization. +#if defined(FOLLY_HAVE_LINUX_VDSO) && !defined(FOLLY_SANITIZE_MEMORY) + +namespace { + +struct VdsoInitializer { + VdsoInitializer() { + m_handle = dlopen("linux-vdso.so.1", RTLD_LAZY | RTLD_LOCAL | RTLD_NOLOAD); + if (!m_handle) { + return; + } + + void* p = dlsym(m_handle, "__vdso_clock_gettime"); + if (p) { + folly::chrono::clock_gettime = (int (*)(clockid_t, timespec*))p; + } + p = dlsym(m_handle, "__vdso_clock_gettime_ns"); + if (p) { + folly::chrono::clock_gettime_ns = (int64_t(*)(clockid_t))p; + } + } + + ~VdsoInitializer() { + if (m_handle) { + clock_gettime = &::clock_gettime; + clock_gettime_ns = &clock_gettime_ns_fallback; + dlclose(m_handle); + } + } + + private: + void* m_handle; +}; + +const VdsoInitializer vdso_initializer; +} // namespace + +#endif +} // namespace chrono +} // namespace folly diff --git a/vnext/external/folly/folly/ClockGettimeWrappers.h b/vnext/external/folly/folly/ClockGettimeWrappers.h new file mode 100644 index 00000000000..f6b1817b1eb --- /dev/null +++ b/vnext/external/folly/folly/ClockGettimeWrappers.h @@ -0,0 +1,29 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace folly { +namespace chrono { + +extern int (*clock_gettime)(clockid_t, timespec* ts); +extern int64_t (*clock_gettime_ns)(clockid_t); +} // namespace chrono +} // namespace folly diff --git a/vnext/external/folly/folly/ConcurrentBitSet.h b/vnext/external/folly/folly/ConcurrentBitSet.h new file mode 100644 index 00000000000..2b5f9f7d955 --- /dev/null +++ b/vnext/external/folly/folly/ConcurrentBitSet.h @@ -0,0 +1,157 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +namespace folly { + +/** + * An atomic bitset of fixed size (specified at compile time). + * + * Formerly known as AtomicBitSet. It was renamed while fixing a bug + * to avoid any silent breakages during run time. + */ +template +class ConcurrentBitSet { + public: + /** + * Construct a ConcurrentBitSet; all bits are initially false. + */ + ConcurrentBitSet(); + + ConcurrentBitSet(const ConcurrentBitSet&) = delete; + ConcurrentBitSet& operator=(const ConcurrentBitSet&) = delete; + + /** + * Set bit idx to true, using the given memory order. Returns the + * previous value of the bit. + * + * Note that the operation is a read-modify-write operation due to the use + * of fetch_or. + */ + bool set(size_t idx, std::memory_order order = std::memory_order_seq_cst); + + /** + * Set bit idx to false, using the given memory order. Returns the + * previous value of the bit. + * + * Note that the operation is a read-modify-write operation due to the use + * of fetch_and. + */ + bool reset(size_t idx, std::memory_order order = std::memory_order_seq_cst); + + /** + * Set bit idx to the given value, using the given memory order. Returns + * the previous value of the bit. + * + * Note that the operation is a read-modify-write operation due to the use + * of fetch_and or fetch_or. + * + * Yes, this is an overload of set(), to keep as close to std::bitset's + * interface as possible. + */ + bool set( + size_t idx, + bool value, + std::memory_order order = std::memory_order_seq_cst); + + /** + * Read bit idx. + */ + bool test( + size_t idx, std::memory_order order = std::memory_order_seq_cst) const; + + /** + * Same as test() with the default memory order. + */ + bool operator[](size_t idx) const; + + /** + * Return the size of the bitset. + */ + constexpr size_t size() const { return N; } + + private: + // Pick the largest lock-free type available +#if (ATOMIC_LLONG_LOCK_FREE == 2) + typedef unsigned long long BlockType; +#elif (ATOMIC_LONG_LOCK_FREE == 2) + typedef unsigned long BlockType; +#else + // Even if not lock free, what can we do? + typedef unsigned int BlockType; +#endif + typedef std::atomic AtomicBlockType; + + static constexpr size_t kBitsPerBlock = + std::numeric_limits::digits; + + static constexpr size_t blockIndex(size_t bit) { return bit / kBitsPerBlock; } + + static constexpr size_t bitOffset(size_t bit) { return bit % kBitsPerBlock; } + + // avoid casts + static constexpr BlockType kOne = 1; + static constexpr size_t kNumBlocks = (N + kBitsPerBlock - 1) / kBitsPerBlock; + std::array data_; +}; + +// value-initialize to zero +template +inline ConcurrentBitSet::ConcurrentBitSet() : data_() {} + +template +inline bool ConcurrentBitSet::set(size_t idx, std::memory_order order) { + assert(idx < N); + BlockType mask = kOne << bitOffset(idx); + return data_[blockIndex(idx)].fetch_or(mask, order) & mask; +} + +template +inline bool ConcurrentBitSet::reset(size_t idx, std::memory_order order) { + assert(idx < N); + BlockType mask = kOne << bitOffset(idx); + return data_[blockIndex(idx)].fetch_and(~mask, order) & mask; +} + +template +inline bool ConcurrentBitSet::set( + size_t idx, bool value, std::memory_order order) { + return value ? set(idx, order) : reset(idx, order); +} + +template +inline bool ConcurrentBitSet::test( + size_t idx, std::memory_order order) const { + assert(idx < N); + BlockType mask = kOne << bitOffset(idx); + return data_[blockIndex(idx)].load(order) & mask; +} + +template +inline bool ConcurrentBitSet::operator[](size_t idx) const { + return test(idx); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/ConcurrentLazy.h b/vnext/external/folly/folly/ConcurrentLazy.h new file mode 100644 index 00000000000..55066a90c4f --- /dev/null +++ b/vnext/external/folly/folly/ConcurrentLazy.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include + +namespace folly { + +/* + * ConcurrentLazy is for thread-safe, delayed initialization of a value. This + * combines the benefits of both `folly::Lazy` and `folly::DelayedInit` to + * compute the value, once, at access time. + * + * There are a few differences between the non-concurrent Lazy, most notably: + * + * - this only safely initializes the value; thread-safety of the underlying + * value is left up to the caller. + * - the underlying types are not copyable or moveable, which means that this + * type is also not copyable or moveable. + * + * Otherwise, all design considerations from `folly::Lazy` are reflected here. + */ + +template +struct ConcurrentLazy { + using result_type = invoke_result_t; + + static_assert( + !std::is_const::value, "Func should not be a const-qualified type"); + static_assert( + !std::is_reference::value, "Func should not be a reference type"); + + template < + typename F, + std::enable_if_t, int> = 0> + explicit ConcurrentLazy(F&& f) noexcept( + std::is_nothrow_constructible_v) + : ctor_(static_cast(f)) {} + + const result_type& operator()() const { + return value_.try_emplace_with(std::ref(ctor_)); + } + + result_type& operator()() { return value_.try_emplace_with(std::ref(ctor_)); } + + private: + mutable folly::DelayedInit value_; + mutable Ctor ctor_; +}; + +template +ConcurrentLazy> concurrent_lazy(Func&& func) { + return ConcurrentLazy>(static_cast(func)); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/ConcurrentSkipList-inl.h b/vnext/external/folly/folly/ConcurrentSkipList-inl.h new file mode 100644 index 00000000000..f7b3b16e1be --- /dev/null +++ b/vnext/external/folly/folly/ConcurrentSkipList-inl.h @@ -0,0 +1,341 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +namespace folly { +namespace detail { + +template +class csl_iterator; + +template +class SkipListNode { + enum : uint16_t { + IS_HEAD_NODE = 1, + MARKED_FOR_REMOVAL = (1 << 1), + FULLY_LINKED = (1 << 2), + }; + + public: + typedef T value_type; + + SkipListNode(const SkipListNode&) = delete; + SkipListNode& operator=(const SkipListNode&) = delete; + + template < + typename NodeAlloc, + typename U, + typename = + typename std::enable_if::value>::type> + static SkipListNode* create( + NodeAlloc& alloc, int height, U&& data, bool isHead = false) { + DCHECK(height >= 1 && height < 64) << height; + + size_t size = + sizeof(SkipListNode) + height * sizeof(std::atomic); + auto storage = std::allocator_traits::allocate(alloc, size); + // do placement new + return new (storage) + SkipListNode(uint8_t(height), std::forward(data), isHead); + } + + template + static void destroy(NodeAlloc& alloc, SkipListNode* node) { + size_t size = sizeof(SkipListNode) + + node->height_ * sizeof(std::atomic); + node->~SkipListNode(); + std::allocator_traits::deallocate( + alloc, typename std::allocator_traits::pointer(node), size); + } + + template + struct DestroyIsNoOp : StrictConjunction< + AllocatorHasTrivialDeallocate, + std::is_trivially_destructible> {}; + + // copy the head node to a new head node assuming lock acquired + SkipListNode* copyHead(SkipListNode* node) { + DCHECK(node != nullptr && height_ > node->height_); + setFlags(node->getFlags()); + for (uint8_t i = 0; i < node->height_; ++i) { + setSkip(i, node->skip(i)); + } + return this; + } + + inline SkipListNode* skip(int layer) const { + DCHECK_LT(layer, height_); + return skip_[layer].load(std::memory_order_acquire); + } + + // next valid node as in the linked list + SkipListNode* next() { + SkipListNode* node; + for (node = skip(0); (node != nullptr && node->markedForRemoval()); + node = node->skip(0)) { + } + return node; + } + + void setSkip(uint8_t h, SkipListNode* next) { + DCHECK_LT(h, height_); + skip_[h].store(next, std::memory_order_release); + } + + value_type& data() { return data_; } + const value_type& data() const { return data_; } + int maxLayer() const { return height_ - 1; } + int height() const { return height_; } + + std::unique_lock acquireGuard() { + return std::unique_lock(spinLock_); + } + + bool fullyLinked() const { return getFlags() & FULLY_LINKED; } + bool markedForRemoval() const { return getFlags() & MARKED_FOR_REMOVAL; } + bool isHeadNode() const { return getFlags() & IS_HEAD_NODE; } + + void setIsHeadNode() { setFlags(uint16_t(getFlags() | IS_HEAD_NODE)); } + void setFullyLinked() { setFlags(uint16_t(getFlags() | FULLY_LINKED)); } + void setMarkedForRemoval() { + setFlags(uint16_t(getFlags() | MARKED_FOR_REMOVAL)); + } + + private: + // Note! this can only be called from create() as a placement new. + template + SkipListNode(uint8_t height, U&& data, bool isHead) + : height_(height), data_(std::forward(data)) { + spinLock_.init(); + setFlags(0); + if (isHead) { + setIsHeadNode(); + } + // need to explicitly init the dynamic atomic pointer array + for (uint8_t i = 0; i < height_; ++i) { + new (&skip_[i]) std::atomic(nullptr); + } + } + + ~SkipListNode() { + for (uint8_t i = 0; i < height_; ++i) { + skip_[i].~atomic(); + } + } + + uint16_t getFlags() const { return flags_.load(std::memory_order_acquire); } + void setFlags(uint16_t flags) { + flags_.store(flags, std::memory_order_release); + } + + // TODO(xliu): on x86_64, it's possible to squeeze these into + // skip_[0] to maybe save 8 bytes depending on the data alignments. + // NOTE: currently this is x86_64 only anyway, due to the + // MicroSpinLock. + std::atomic flags_; + const uint8_t height_; + MicroSpinLock spinLock_; + + value_type data_; + + std::atomic skip_[0]; +}; + +class SkipListRandomHeight { + enum { kMaxHeight = 64 }; + + public: + // make it a singleton. + static SkipListRandomHeight* instance() { + static SkipListRandomHeight instance_; + return &instance_; + } + + int getHeight(int maxHeight) const { + DCHECK_LE(maxHeight, kMaxHeight) << "max height too big!"; + double p = randomProb(); + for (int i = 0; i < maxHeight; ++i) { + if (p < lookupTable_[i]) { + return i + 1; + } + } + return maxHeight; + } + + size_t getSizeLimit(int height) const { + DCHECK_LT(height, kMaxHeight); + return sizeLimitTable_[height]; + } + + private: + SkipListRandomHeight() { initLookupTable(); } + + void initLookupTable() { + // set skip prob = 1/E + static const double kProbInv = exp(1); + static const double kProb = 1.0 / kProbInv; + static const size_t kMaxSizeLimit = std::numeric_limits::max(); + + double sizeLimit = 1; + double p = lookupTable_[0] = (1 - kProb); + sizeLimitTable_[0] = 1; + for (int i = 1; i < kMaxHeight - 1; ++i) { + p *= kProb; + sizeLimit *= kProbInv; + lookupTable_[i] = lookupTable_[i - 1] + p; + sizeLimitTable_[i] = folly::constexpr_clamp_cast(sizeLimit); + } + lookupTable_[kMaxHeight - 1] = 1; + sizeLimitTable_[kMaxHeight - 1] = kMaxSizeLimit; + } + + static double randomProb() { + static ThreadLocal rng_; + return (*rng_)(); + } + + double lookupTable_[kMaxHeight]; + size_t sizeLimitTable_[kMaxHeight]; +}; + +template +class NodeRecycler; + +template +class NodeRecycler< + NodeType, + NodeAlloc, + typename std::enable_if< + !NodeType::template DestroyIsNoOp::value>::type> { + public: + explicit NodeRecycler(const NodeAlloc& alloc) + : refs_(0), dirty_(false), alloc_(alloc) { + lock_.init(); + } + + explicit NodeRecycler() : refs_(0), dirty_(false) { lock_.init(); } + + ~NodeRecycler() { + CHECK_EQ(refs(), 0); + if (nodes_) { + for (auto& node : *nodes_) { + NodeType::destroy(alloc_, node); + } + } + } + + void add(NodeType* node) { + std::lock_guard g(lock_); + if (nodes_.get() == nullptr) { + nodes_ = std::make_unique>(1, node); + } else { + nodes_->push_back(node); + } + DCHECK_GT(refs(), 0); + dirty_.store(true, std::memory_order_relaxed); + } + + int addRef() { return refs_.fetch_add(1, std::memory_order_acq_rel); } + + int releaseRef() { + // This if statement is purely an optimization. It's possible that this + // misses an opportunity to delete, but that's OK, we'll try again at + // the next opportunity. It does not harm the thread safety. For this + // reason, we can use relaxed loads to make the decision. + if (!dirty_.load(std::memory_order_relaxed) || refs() > 1) { + return refs_.fetch_add(-1, std::memory_order_acq_rel); + } + + std::unique_ptr> newNodes; + int ret; + { + // The order at which we lock, add, swap, is very important for + // correctness. + std::lock_guard g(lock_); + ret = refs_.fetch_add(-1, std::memory_order_acq_rel); + if (ret == 1) { + // When releasing the last reference, it is safe to remove all the + // current nodes in the recycler, as we already acquired the lock here + // so no more new nodes can be added, even though new accessors may be + // added after this. + newNodes.swap(nodes_); + dirty_.store(false, std::memory_order_relaxed); + } + } + // TODO(xliu) should we spawn a thread to do this when there are large + // number of nodes in the recycler? + if (newNodes) { + for (auto& node : *newNodes) { + NodeType::destroy(alloc_, node); + } + } + return ret; + } + + NodeAlloc& alloc() { return alloc_; } + + private: + int refs() const { return refs_.load(std::memory_order_relaxed); } + + std::unique_ptr> nodes_; + std::atomic refs_; // current number of visitors to the list + std::atomic dirty_; // whether *nodes_ is non-empty + MicroSpinLock lock_; // protects access to *nodes_ + NodeAlloc alloc_; +}; + +// In case of arena allocator, no recycling is necessary, and it's possible +// to save on ConcurrentSkipList size. +template +class NodeRecycler< + NodeType, + NodeAlloc, + typename std::enable_if< + NodeType::template DestroyIsNoOp::value>::type> { + public: + explicit NodeRecycler(const NodeAlloc& alloc) : alloc_(alloc) {} + + void addRef() {} + void releaseRef() {} + + void add(NodeType* /* node */) {} + + NodeAlloc& alloc() { return alloc_; } + + private: + NodeAlloc alloc_; +}; + +} // namespace detail +} // namespace folly diff --git a/vnext/external/folly/folly/ConcurrentSkipList.h b/vnext/external/folly/folly/ConcurrentSkipList.h new file mode 100644 index 00000000000..bb70c770e39 --- /dev/null +++ b/vnext/external/folly/folly/ConcurrentSkipList.h @@ -0,0 +1,824 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// A concurrent skip list (CSL) implementation. +// Ref: http://www.cs.tau.ac.il/~shanir/nir-pubs-web/Papers/OPODIS2006-BA.pdf + +/* + +This implements a sorted associative container that supports only +unique keys. (Similar to std::set.) + +Features: + + 1. Small memory overhead: ~40% less memory overhead compared with + std::set (1.6 words per node versus 3). It has an minimum of 4 + words (7 words if there nodes got deleted) per-list overhead + though. + + 2. Read accesses (count, find iterator, skipper) are lock-free and + mostly wait-free (the only wait a reader may need to do is when + the node it is visiting is in a pending stage, i.e. deleting, + adding and not fully linked). Write accesses (remove, add) need + to acquire locks, but locks are local to the predecessor nodes + and/or successor nodes. + + 3. Good high contention performance, comparable single-thread + performance. In the multithreaded case (12 workers), CSL tested + 10x faster than a RWSpinLocked std::set for an averaged sized + list (1K - 1M nodes). + + Comparable read performance to std::set when single threaded, + especially when the list size is large, and scales better to + larger lists: when the size is small, CSL can be 20-50% slower on + find()/contains(). As the size gets large (> 1M elements), + find()/contains() can be 30% faster. + + Iterating through a skiplist is similar to iterating through a + linked list, thus is much (2-6x) faster than on a std::set + (tree-based). This is especially true for short lists due to + better cache locality. Based on that, it's also faster to + intersect two skiplists. + + 4. Lazy removal with GC support. The removed nodes get deleted when + the last Accessor to the skiplist is destroyed. + +Caveats: + + 1. Write operations are usually 30% slower than std::set in a single + threaded environment. + + 2. Need to have a head node for each list, which has a 4 word + overhead. + + 3. When the list is quite small (< 1000 elements), single threaded + benchmarks show CSL can be 10x slower than std:set. + + 4. The interface requires using an Accessor to access the skiplist. + (See below.) + + 5. Currently x64 only, due to use of MicroSpinLock. + + 6. Freed nodes will not be reclaimed as long as there are ongoing + uses of the list. + +Sample usage: + + typedef ConcurrentSkipList SkipListT; + shared_ptr sl(SkipListT::createInstance(init_head_height); + { + // It's usually good practice to hold an accessor only during + // its necessary life cycle (but not in a tight loop as + // Accessor creation incurs ref-counting overhead). + // + // Holding it longer delays garbage-collecting the deleted + // nodes in the list. + SkipListT::Accessor accessor(sl); + accessor.insert(23); + accessor.erase(2); + for (auto &elem : accessor) { + // use elem to access data + } + ... ... + } + + Another useful type is the Skipper accessor. This is useful if you + want to skip to locations in the way std::lower_bound() works, + i.e. it can be used for going through the list by skipping to the + node no less than a specified key. The Skipper keeps its location as + state, which makes it convenient for things like implementing + intersection of two sets efficiently, as it can start from the last + visited position. + + { + SkipListT::Accessor accessor(sl); + SkipListT::Skipper skipper(accessor); + skipper.to(30); + if (skipper) { + CHECK_LE(30, *skipper); + } + ... ... + // GC may happen when the accessor gets destructed. + } +*/ + +#pragma once + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include + +namespace folly { + +template < + typename T, + typename Comp = std::less, + // All nodes are allocated using provided SysAllocator, + // it should be thread-safe. + typename NodeAlloc = SysAllocator, + int MAX_HEIGHT = 24> +class ConcurrentSkipList { + // MAX_HEIGHT needs to be at least 2 to suppress compiler + // warnings/errors (Werror=uninitialized triggered due to preds_[1] + // being treated as a scalar in the compiler). + static_assert( + MAX_HEIGHT >= 2 && MAX_HEIGHT < 64, + "MAX_HEIGHT can only be in the range of [2, 64)"); + typedef std::unique_lock ScopedLocker; + typedef ConcurrentSkipList SkipListType; + + public: + typedef detail::SkipListNode NodeType; + typedef T value_type; + typedef T key_type; + + typedef detail::csl_iterator iterator; + typedef detail::csl_iterator const_iterator; + + class Accessor; + class Skipper; + + explicit ConcurrentSkipList(int height, const NodeAlloc& alloc) + : recycler_(alloc), + head_(NodeType::create(recycler_.alloc(), height, value_type(), true)) { + } + + explicit ConcurrentSkipList(int height) + : recycler_(), + head_(NodeType::create(recycler_.alloc(), height, value_type(), true)) { + } + + // Convenience function to get an Accessor to a new instance. + static Accessor create(int height, const NodeAlloc& alloc) { + return Accessor(createInstance(height, alloc)); + } + + static Accessor create(int height = 1) { + return Accessor(createInstance(height)); + } + + // Create a shared_ptr skiplist object with initial head height. + static std::shared_ptr createInstance( + int height, const NodeAlloc& alloc) { + return std::make_shared(height, alloc); + } + + static std::shared_ptr createInstance(int height = 1) { + return std::make_shared(height); + } + + size_t size() const { return size_.load(std::memory_order_relaxed); } + bool empty() const { return size() == 0; } + + //=================================================================== + // Below are implementation details. + // Please see ConcurrentSkipList::Accessor for stdlib-like APIs. + //=================================================================== + + ~ConcurrentSkipList() { + if /* constexpr */ (NodeType::template DestroyIsNoOp::value) { + // Avoid traversing the list if using arena allocator. + return; + } + for (NodeType* current = head_.load(std::memory_order_relaxed); current;) { + NodeType* tmp = current->skip(0); + NodeType::destroy(recycler_.alloc(), current); + current = tmp; + } + } + + private: + static bool greater(const value_type& data, const NodeType* node) { + return node && Comp()(node->data(), data); + } + + static bool less(const value_type& data, const NodeType* node) { + return (node == nullptr) || Comp()(data, node->data()); + } + + static int findInsertionPoint( + NodeType* cur, + int cur_layer, + const value_type& data, + NodeType* preds[], + NodeType* succs[]) { + int foundLayer = -1; + NodeType* pred = cur; + NodeType* foundNode = nullptr; + for (int layer = cur_layer; layer >= 0; --layer) { + NodeType* node = pred->skip(layer); + while (greater(data, node)) { + pred = node; + node = node->skip(layer); + } + if (foundLayer == -1 && !less(data, node)) { // the two keys equal + foundLayer = layer; + foundNode = node; + } + preds[layer] = pred; + + // if found, succs[0..foundLayer] need to point to the cached foundNode, + // as foundNode might be deleted at the same time thus pred->skip() can + // return nullptr or another node. + succs[layer] = foundNode ? foundNode : node; + } + return foundLayer; + } + + int height() const { return head_.load(std::memory_order_acquire)->height(); } + + int maxLayer() const { return height() - 1; } + + size_t incrementSize(int delta) { + return size_.fetch_add(delta, std::memory_order_relaxed) + delta; + } + + // Returns the node if found, nullptr otherwise. + NodeType* find(const value_type& data) { + auto ret = findNode(data); + if (ret.second && !ret.first->markedForRemoval()) { + return ret.first; + } + return nullptr; + } + + // lock all the necessary nodes for changing (adding or removing) the list. + // returns true if all the lock acquired successfully and the related nodes + // are all validate (not in certain pending states), false otherwise. + bool lockNodesForChange( + int nodeHeight, + ScopedLocker guards[MAX_HEIGHT], + NodeType* preds[MAX_HEIGHT], + NodeType* succs[MAX_HEIGHT], + bool adding = true) { + NodeType *pred, *succ, *prevPred = nullptr; + bool valid = true; + for (int layer = 0; valid && layer < nodeHeight; ++layer) { + pred = preds[layer]; + DCHECK(pred != nullptr) << "layer=" << layer << " height=" << height() + << " nodeheight=" << nodeHeight; + succ = succs[layer]; + if (pred != prevPred) { + guards[layer] = pred->acquireGuard(); + prevPred = pred; + } + valid = !pred->markedForRemoval() && + pred->skip(layer) == succ; // check again after locking + + if (adding) { // when adding a node, the succ shouldn't be going away + valid = valid && (succ == nullptr || !succ->markedForRemoval()); + } + } + + return valid; + } + + // Returns a paired value: + // pair.first always stores the pointer to the node with the same input key. + // It could be either the newly added data, or the existed data in the + // list with the same key. + // pair.second stores whether the data is added successfully: + // 0 means not added, otherwise returns the new size. + template + std::pair addOrGetData(U&& data) { + NodeType *preds[MAX_HEIGHT], *succs[MAX_HEIGHT]; + NodeType* newNode; + size_t newSize; + while (true) { + int max_layer = 0; + int layer = findInsertionPointGetMaxLayer(data, preds, succs, &max_layer); + + if (layer >= 0) { + NodeType* nodeFound = succs[layer]; + DCHECK(nodeFound != nullptr); + if (nodeFound->markedForRemoval()) { + continue; // if it's getting deleted retry finding node. + } + // wait until fully linked. + while (FOLLY_UNLIKELY(!nodeFound->fullyLinked())) { + } + return std::make_pair(nodeFound, 0); + } + + // need to capped at the original height -- the real height may have grown + int nodeHeight = + detail::SkipListRandomHeight::instance()->getHeight(max_layer + 1); + + ScopedLocker guards[MAX_HEIGHT]; + if (!lockNodesForChange(nodeHeight, guards, preds, succs)) { + continue; // give up the locks and retry until all valid + } + + // locks acquired and all valid, need to modify the links under the locks. + newNode = NodeType::create( + recycler_.alloc(), nodeHeight, std::forward(data)); + for (int k = 0; k < nodeHeight; ++k) { + newNode->setSkip(k, succs[k]); + preds[k]->setSkip(k, newNode); + } + + newNode->setFullyLinked(); + newSize = incrementSize(1); + break; + } + + int hgt = height(); + size_t sizeLimit = + detail::SkipListRandomHeight::instance()->getSizeLimit(hgt); + + if (hgt < MAX_HEIGHT && newSize > sizeLimit) { + growHeight(hgt + 1); + } + CHECK_GT(newSize, 0); + return std::make_pair(newNode, newSize); + } + + bool remove(const value_type& data) { + NodeType* nodeToDelete = nullptr; + ScopedLocker nodeGuard; + bool isMarked = false; + int nodeHeight = 0; + NodeType *preds[MAX_HEIGHT], *succs[MAX_HEIGHT]; + + while (true) { + int max_layer = 0; + int layer = findInsertionPointGetMaxLayer(data, preds, succs, &max_layer); + if (!isMarked && (layer < 0 || !okToDelete(succs[layer], layer))) { + return false; + } + + if (!isMarked) { + nodeToDelete = succs[layer]; + nodeHeight = nodeToDelete->height(); + nodeGuard = nodeToDelete->acquireGuard(); + if (nodeToDelete->markedForRemoval()) { + return false; + } + nodeToDelete->setMarkedForRemoval(); + isMarked = true; + } + + // acquire pred locks from bottom layer up + ScopedLocker guards[MAX_HEIGHT]; + if (!lockNodesForChange(nodeHeight, guards, preds, succs, false)) { + continue; // this will unlock all the locks + } + + for (int k = nodeHeight - 1; k >= 0; --k) { + preds[k]->setSkip(k, nodeToDelete->skip(k)); + } + + incrementSize(-1); + break; + } + recycle(nodeToDelete); + return true; + } + + const value_type* first() const { + auto node = head_.load(std::memory_order_acquire)->skip(0); + return node ? &node->data() : nullptr; + } + + const value_type* last() const { + NodeType* pred = head_.load(std::memory_order_acquire); + NodeType* node = nullptr; + for (int layer = maxLayer(); layer >= 0; --layer) { + do { + node = pred->skip(layer); + if (node) { + pred = node; + } + } while (node != nullptr); + } + return pred == head_.load(std::memory_order_relaxed) ? nullptr + : &pred->data(); + } + + static bool okToDelete(NodeType* candidate, int layer) { + DCHECK(candidate != nullptr); + return candidate->fullyLinked() && candidate->maxLayer() == layer && + !candidate->markedForRemoval(); + } + + // find node for insertion/deleting + int findInsertionPointGetMaxLayer( + const value_type& data, + NodeType* preds[], + NodeType* succs[], + int* max_layer) const { + *max_layer = maxLayer(); + return findInsertionPoint( + head_.load(std::memory_order_acquire), *max_layer, data, preds, succs); + } + + // Find node for access. Returns a paired values: + // pair.first = the first node that no-less than data value + // pair.second = 1 when the data value is founded, or 0 otherwise. + // This is like lower_bound, but not exact: we could have the node marked for + // removal so still need to check that. + std::pair findNode(const value_type& data) const { + return findNodeDownRight(data); + } + + // Find node by first stepping down then stepping right. Based on benchmark + // results, this is slightly faster than findNodeRightDown for better + // locality on the skipping pointers. + std::pair findNodeDownRight(const value_type& data) const { + NodeType* pred = head_.load(std::memory_order_acquire); + int ht = pred->height(); + NodeType* node = nullptr; + + bool found = false; + while (!found) { + // stepping down + for (; ht > 0 && less(data, node = pred->skip(ht - 1)); --ht) { + } + if (ht == 0) { + return std::make_pair(node, 0); // not found + } + // node <= data now, but we need to fix up ht + --ht; + + // stepping right + while (greater(data, node)) { + pred = node; + node = node->skip(ht); + } + found = !less(data, node); + } + return std::make_pair(node, found); + } + + // find node by first stepping right then stepping down. + // We still keep this for reference purposes. + std::pair findNodeRightDown(const value_type& data) const { + NodeType* pred = head_.load(std::memory_order_acquire); + NodeType* node = nullptr; + auto top = maxLayer(); + int found = 0; + for (int layer = top; !found && layer >= 0; --layer) { + node = pred->skip(layer); + while (greater(data, node)) { + pred = node; + node = node->skip(layer); + } + found = !less(data, node); + } + return std::make_pair(node, found); + } + + NodeType* lower_bound(const value_type& data) const { + auto node = findNode(data).first; + while (node != nullptr && node->markedForRemoval()) { + node = node->skip(0); + } + return node; + } + + void growHeight(int height) { + NodeType* oldHead = head_.load(std::memory_order_acquire); + if (oldHead->height() >= height) { // someone else already did this + return; + } + + NodeType* newHead = + NodeType::create(recycler_.alloc(), height, value_type(), true); + + { // need to guard the head node in case others are adding/removing + // nodes linked to the head. + ScopedLocker g = oldHead->acquireGuard(); + newHead->copyHead(oldHead); + NodeType* expected = oldHead; + if (!head_.compare_exchange_strong( + expected, newHead, std::memory_order_release)) { + // if someone has already done the swap, just return. + NodeType::destroy(recycler_.alloc(), newHead); + return; + } + oldHead->setMarkedForRemoval(); + } + recycle(oldHead); + } + + void recycle(NodeType* node) { recycler_.add(node); } + + detail::NodeRecycler recycler_; + std::atomic head_; + std::atomic size_{0}; +}; + +template +class ConcurrentSkipList::Accessor { + typedef detail::SkipListNode NodeType; + typedef ConcurrentSkipList SkipListType; + + public: + typedef T value_type; + typedef T key_type; + typedef T& reference; + typedef T* pointer; + typedef const T& const_reference; + typedef const T* const_pointer; + typedef size_t size_type; + typedef Comp key_compare; + typedef Comp value_compare; + + typedef typename SkipListType::iterator iterator; + typedef typename SkipListType::const_iterator const_iterator; + typedef typename SkipListType::Skipper Skipper; + + explicit Accessor(std::shared_ptr skip_list) + : slHolder_(std::move(skip_list)) { + sl_ = slHolder_.get(); + DCHECK(sl_ != nullptr); + sl_->recycler_.addRef(); + } + + // Unsafe initializer: the caller assumes the responsibility to keep + // skip_list valid during the whole life cycle of the Accessor. + explicit Accessor(ConcurrentSkipList* skip_list) : sl_(skip_list) { + DCHECK(sl_ != nullptr); + sl_->recycler_.addRef(); + } + + Accessor(const Accessor& accessor) + : sl_(accessor.sl_), slHolder_(accessor.slHolder_) { + sl_->recycler_.addRef(); + } + + Accessor& operator=(const Accessor& accessor) { + if (this != &accessor) { + slHolder_ = accessor.slHolder_; + sl_->recycler_.releaseRef(); + sl_ = accessor.sl_; + sl_->recycler_.addRef(); + } + return *this; + } + + ~Accessor() { sl_->recycler_.releaseRef(); } + + bool empty() const { return sl_->size() == 0; } + size_t size() const { return sl_->size(); } + size_type max_size() const { return std::numeric_limits::max(); } + + // returns end() if the value is not in the list, otherwise returns an + // iterator pointing to the data, and it's guaranteed that the data is valid + // as far as the Accessor is hold. + iterator find(const key_type& value) { return iterator(sl_->find(value)); } + const_iterator find(const key_type& value) const { + return iterator(sl_->find(value)); + } + size_type count(const key_type& data) const { return contains(data); } + + iterator begin() const { + NodeType* head = sl_->head_.load(std::memory_order_acquire); + return iterator(head->next()); + } + iterator end() const { return iterator(nullptr); } + const_iterator cbegin() const { return begin(); } + const_iterator cend() const { return end(); } + + template < + typename U, + typename = + typename std::enable_if::value>::type> + std::pair insert(U&& data) { + auto ret = sl_->addOrGetData(std::forward(data)); + return std::make_pair(iterator(ret.first), ret.second); + } + size_t erase(const key_type& data) { return remove(data); } + + iterator lower_bound(const key_type& data) const { + return iterator(sl_->lower_bound(data)); + } + + size_t height() const { return sl_->height(); } + + // first() returns pointer to the first element in the skiplist, or + // nullptr if empty. + // + // last() returns the pointer to the last element in the skiplist, + // nullptr if list is empty. + // + // Note: As concurrent writing can happen, first() is not + // guaranteed to be the min_element() in the list. Similarly + // last() is not guaranteed to be the max_element(), and both of them can + // be invalid (i.e. nullptr), so we name them differently from front() and + // tail() here. + const key_type* first() const { return sl_->first(); } + const key_type* last() const { return sl_->last(); } + + // Try to remove the last element in the skip list. + // + // Returns true if we removed it, false if either the list is empty + // or a race condition happened (i.e. the used-to-be last element + // was already removed by another thread). + bool pop_back() { + auto last = sl_->last(); + return last ? sl_->remove(*last) : false; + } + + std::pair addOrGetData(const key_type& data) { + auto ret = sl_->addOrGetData(data); + return std::make_pair(&ret.first->data(), ret.second); + } + + SkipListType* skiplist() const { return sl_; } + + // legacy interfaces + // TODO:(xliu) remove these. + // Returns true if the node is added successfully, false if not, i.e. the + // node with the same key already existed in the list. + bool contains(const key_type& data) const { return sl_->find(data); } + bool add(const key_type& data) { return sl_->addOrGetData(data).second; } + bool remove(const key_type& data) { return sl_->remove(data); } + + private: + SkipListType* sl_; + std::shared_ptr slHolder_; +}; + +// implements forward iterator concept. +template +class detail::csl_iterator : public detail::IteratorFacade< + csl_iterator, + ValT, + std::forward_iterator_tag> { + public: + typedef ValT value_type; + typedef value_type& reference; + typedef value_type* pointer; + typedef ptrdiff_t difference_type; + + explicit csl_iterator(NodeT* node = nullptr) : node_(node) {} + + template + csl_iterator( + const csl_iterator& other, + typename std::enable_if< + std::is_convertible::value>::type* = nullptr) + : node_(other.node_) {} + + size_t nodeSize() const { + return node_ == nullptr ? 0 + : node_->height() * sizeof(NodeT*) + sizeof(*this); + } + + bool good() const { return node_ != nullptr; } + + private: + template + friend class csl_iterator; + friend class detail:: + IteratorFacade; + + void increment() { node_ = node_->next(); } + bool equal(const csl_iterator& other) const { return node_ == other.node_; } + value_type& dereference() const { return node_->data(); } + + NodeT* node_; +}; + +// Skipper interface +template +class ConcurrentSkipList::Skipper { + typedef detail::SkipListNode NodeType; + typedef ConcurrentSkipList SkipListType; + typedef typename SkipListType::Accessor Accessor; + + public: + typedef T value_type; + typedef T& reference; + typedef T* pointer; + typedef ptrdiff_t difference_type; + + Skipper(std::shared_ptr skipList) + : accessor_(std::move(skipList)) { + init(); + } + + Skipper(const Accessor& accessor) : accessor_(accessor) { init(); } + + void init() { + // need to cache the head node + NodeType* head_node = head(); + headHeight_ = head_node->height(); + for (int i = 0; i < headHeight_; ++i) { + preds_[i] = head_node; + succs_[i] = head_node->skip(i); + } + int max_layer = maxLayer(); + for (int i = 0; i < max_layer; ++i) { + hints_[i] = uint8_t(i + 1); + } + hints_[max_layer] = max_layer; + } + + // advance to the next node in the list. + Skipper& operator++() { + preds_[0] = succs_[0]; + succs_[0] = preds_[0]->skip(0); + int height = curHeight(); + for (int i = 1; i < height && preds_[0] == succs_[i]; ++i) { + preds_[i] = succs_[i]; + succs_[i] = preds_[i]->skip(i); + } + return *this; + } + + Accessor& accessor() { return accessor_; } + const Accessor& accessor() const { return accessor_; } + + bool good() const { return succs_[0] != nullptr; } + + int maxLayer() const { return headHeight_ - 1; } + + int curHeight() const { + // need to cap the height to the cached head height, as the current node + // might be some newly inserted node and also during the time period the + // head height may have grown. + return succs_[0] ? std::min(headHeight_, succs_[0]->height()) : 0; + } + + const value_type& data() const { + DCHECK(succs_[0] != nullptr); + return succs_[0]->data(); + } + + value_type& operator*() const { + DCHECK(succs_[0] != nullptr); + return succs_[0]->data(); + } + + value_type* operator->() { + DCHECK(succs_[0] != nullptr); + return &succs_[0]->data(); + } + + /* + * Skip to the position whose data is no less than the parameter. + * (I.e. the lower_bound). + * + * Returns true if the data is found, false otherwise. + */ + bool to(const value_type& data) { + int layer = curHeight() - 1; + if (layer < 0) { + return false; // reaches the end of the list + } + + int lyr = hints_[layer]; + int max_layer = maxLayer(); + while (SkipListType::greater(data, succs_[lyr]) && lyr < max_layer) { + ++lyr; + } + hints_[layer] = lyr; // update the hint + + int foundLayer = SkipListType::findInsertionPoint( + preds_[lyr], lyr, data, preds_, succs_); + if (foundLayer < 0) { + return false; + } + + DCHECK(succs_[0] != nullptr) + << "lyr=" << lyr << "; max_layer=" << max_layer; + return !succs_[0]->markedForRemoval(); + } + + private: + NodeType* head() const { + return accessor_.skiplist()->head_.load(std::memory_order_acquire); + } + + Accessor accessor_; + int headHeight_; + NodeType *succs_[MAX_HEIGHT], *preds_[MAX_HEIGHT]; + uint8_t hints_[MAX_HEIGHT]; +}; + +} // namespace folly diff --git a/vnext/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h b/vnext/external/folly/folly/ConstexprMath.h similarity index 100% rename from vnext/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h rename to vnext/external/folly/folly/ConstexprMath.h diff --git a/vnext/external/folly/folly/ConstructorCallbackList.h b/vnext/external/folly/folly/ConstructorCallbackList.h new file mode 100644 index 00000000000..44ee7288f40 --- /dev/null +++ b/vnext/external/folly/folly/ConstructorCallbackList.h @@ -0,0 +1,158 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +namespace folly { + +// A mixin to register and issue callbacks every time a class constructor is +// invoked +// +// For example: +// #include +// +// class Foo { +// ... +// private: +// ... +// // add this member last to minimize partially constructed errors +// ConstructorCallbackList constructorCB_{this}; +// } +// +// int main() { +// auto cb = [](Foo * f) { +// std::cout << "New Foo" << f << std::endl; +// }; +// ConstructorCallbackList::addCallback(cb); +// Foo f{}; // will call callback, print to stdout +// } +// +// This code is designed to be light weight so as to mixin to many +// places with low overhead. +// +// NOTE: The callback is triggered with a *partially* constructed object. +// This implies that that callback code can only access members that are +// constructed *before* the ConstructorCallbackList object. Also, at the time +// of the callback, none of the Foo() constructor code will have run. +// Per the example above, +// the best practice is to place the ConstructorCallbackList declaration last +// in the parent class. This will minimize the amount of uninitialized +// data in the Foo instance, but will not eliminate it unless it has a trivial +// constructor. +// +// Implementation/Overhead Notes: +// +// By design, adding ConstructorCallbackList to an object should be very +// light weight. From a memory context, this adds 1 byte of memory to the +// parent class. From a CPU/performance perspective, the constructor does a load +// of an atomic int and the cost of the actual callbacks themselves. So if this +// is put in place and only used infrequently, e.g., during debugging, +// this cost should be quite small. +// +// A compile-time static array is used intentionally over a dynamic one for +// two reasons: (1) a dynamic array seems to require a proper lock in +// the constructor which would exceed our perf target, and (2) having a +// finite array provides some sanity checking on the number of callbacks +// that can be registered. + +template +class ConstructorCallbackList { + public: + static constexpr std::size_t kMaxCallbacks = MaxCallbacks; + + using This = ConstructorCallbackList; + using Callback = folly::Function; + using CallbackArray = std::array; + + explicit ConstructorCallbackList(T* t) { + // This code depends on the C++ standard where values that are + // initialized to zero ("Zero Initiation") are initialized before any more + // complex static pre-main() dynamic initialization - see + // https://en.cppreference.com/w/cpp/language/initialization) for + // more details. + // + // This assumption prevents a subtle initialization race condition + // where something could call this code pre-main() before + // numCallbacks_ was set to zero, and thus prevents issuing + // callbacks on garbage data. + + auto nCBs = This::global().numCallbacks_.load(std::memory_order_acquire); + + // fire callbacks to inform listeners about the new constructor + /**** + * We don't need the full lock here, just the atomic int to tell us + * how far into the array to go/how many callbacks are registered + * + * NOTE that nCBs > 0 will always imply that callbacks_ is non-nullptr + */ + for (size_t i = 0; i < nCBs; i++) { + (This::global().callbacks_)[i](t); + } + } + + /** + * Add a callback to the static class that will fire every time + * someone creates a new one. + * + * Implement this as a static array of callbacks rather than a dynamic + * vector to avoid nasty race conditions on resize, startup and shutdown. + * + * Implement this with functions rather than an observer pattern classes + * to avoid race conditions on shutdown + * + * Intentionally don't implement removeConstructorCallbackList to simplify + * implementation (e.g., just the counter is atomic rather than the whole + * array) and thus reduce computational cost. + * + * @throw std::length_error() if this callback would exceed our max + */ + static void addCallback(Callback cb) { + // Ensure that a single callback is added at a time + std::lock_guard g(This::global().mutex_); + auto idx = This::global().numCallbacks_.load(std::memory_order_acquire); + + if (idx >= (This::global().callbacks_).size()) { + throw std::length_error( + folly::sformat("Too many callbacks - max {}", MaxCallbacks)); + } + (This::global().callbacks_)[idx] = std::move(cb); + // Only increment numCallbacks_ after fully initializing the array + // entry. This step makes the new array entry visible to other threads. + This::global().numCallbacks_.store(idx + 1, std::memory_order_release); + } + + private: + // use createGlobal to avoid races on shutdown + struct GlobalStorage { + mutable folly::SharedMutex mutex_; + This::CallbackArray callbacks_{}; + std::atomic numCallbacks_{0}; + }; + static auto& global() { + return folly::detail::createGlobal(); + } +}; +} // namespace folly diff --git a/vnext/Folly/TEMP_UntilFollyUpdate/Conv.cpp b/vnext/external/folly/folly/Conv.cpp similarity index 100% rename from vnext/Folly/TEMP_UntilFollyUpdate/Conv.cpp rename to vnext/external/folly/folly/Conv.cpp diff --git a/vnext/external/folly/folly/Conv.h b/vnext/external/folly/folly/Conv.h new file mode 100644 index 00000000000..c7b61cacfc8 --- /dev/null +++ b/vnext/external/folly/folly/Conv.h @@ -0,0 +1,2026 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +// +// Docs: https://fburl.com/fbcref_conv +// + +/** + * Conv provides the ubiquitous method `to(source)`, along with + * a few other generic interfaces for converting objects to and from + * string-like types (std::string, fbstring, StringPiece), as well as + * range-checked conversions between numeric and enum types. The mechanisms are + * extensible, so that user-specified types can add folly::to support. + * + * folly::to(123) + * // "123" + * + ******************************************************************************* + * ## TYPE -> STRING CONVERSIONS + ******************************************************************************* + * You can call the `to` or `to`. These are variadic + * functions that convert their arguments to strings, and concatenate them to + * form a result. So, for example, + * + * auto str = to(123, "456", 789); + * + * Sets str to `"123456789"`. + * + * In addition to just concatenating the arguments, related functions can + * delimit them with some string: `toDelim(",", "123", 456, "789")` + * will return the string `"123,456,789"`. + * + * toAppend does not return a string; instead, it takes a pointer to a string as + * its last argument, and appends the result of the concatenation into it: + * std::string str = "123"; + * toAppend(456, "789", &str); // Now str is "123456789". + * + * The toAppendFit function acts like toAppend, but it precalculates the size + * required to perform the append operation, and reserves that space in the + * output string before actually inserting its arguments. This can sometimes + * save on string expansion, but beware: appending to the same string many times + * with toAppendFit is likely a pessimization, since it will resize the string + * once per append. + * + * The combination of the append and delim variants also exist: toAppendDelim + * and toAppendDelimFit are defined, with the obvious semantics. + * + ******************************************************************************* + * ## STRING -> TYPE CONVERSIONS + ******************************************************************************* + * Going in the other direction, and parsing a string into a C++ type, is also + * supported: + * to("123"); // Returns 123. + * + * Out of range (e.g. `to("1000")`), or invalidly formatted (e.g. + * `to("four")`) inputs will throw. If throw-on-error is undesirable (for + * instance: you're dealing with untrusted input, and want to protect yourself + * from users sending you down a very slow exception-throwing path), you can use + * `tryTo`, which will return an `Expected`. + * + * There are overloads of to() and tryTo() that take a `StringPiece*`. These + * parse out a type from the beginning of a string, and modify the passed-in + * StringPiece to indicate the portion of the string not consumed. + * + ******************************************************************************* + * ## NUMERIC / ENUM CONVERSIONS + ******************************************************************************* + * Conv also supports a `to(S)` overload, where T and S are numeric or enum + * types, that checks to see that the target type can represent its argument, + * and will throw if it cannot. This includes cases where a floating point to + * integral conversion is attempted on a value with a non-zero fractional + * component, and integral to floating point conversions that would lose + * precision. Enum conversions are range-checked for the underlying type of the + * enum, but there is no check that the input value is a valid choice of enum + * value. + * + ******************************************************************************* + * ## CUSTOM TYPE CONVERSIONS + ******************************************************************************* + * Users may customize the string conversion functionality for their own data + * types. The key functions you should implement are: + * // Two functions to allow conversion to your type from a string. + * Expected parseTo(folly::StringPiece in, + * YourType& out); + * YourErrorType makeConversionError(YourErrorType in, StringPiece in); + * // Two functions to allow conversion from your type to a string. + * template + * void toAppend(const YourType& in, String* out); + * size_t estimateSpaceNeeded(const YourType& in); + * + * These are documented below, inline. + * + * @file Conv.h + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if __has_include() +#include +#endif + +#include // V8 JavaScript implementation + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +// FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT indicates that +// std::to_chars for floating point is available +#if (defined(__cpp_lib_to_chars) && __cpp_lib_to_chars >= 201611L) +#define FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT 1 +#elif defined(_LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS) && \ + defined(_LIBCPP_AVAILABILITY_TO_CHARS_FLOATING_POINT) +#define FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT 1 +#elif defined(__APPLE__) && \ + ((defined(__ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ >= 130300) || \ + (defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__ >= 160300) || \ + (defined(__ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_TV_OS_VERSION_MIN_REQUIRED__ >= 160300) || \ + (defined(__ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__) && \ + __ENVIRONMENT_WATCH_OS_VERSION_MIN_REQUIRED__ >= 90300)) +// Apple introduces std::to_chars & std::from_chars support for floating +// point types for: macOS 13.3, iOS 16.3, tvOS 16.3, watchOS 9.3. +// https://developer.apple.com/xcode/cpp/#c++17 +// __builtin_available(macOS 13.3, iOS 16.3, tvOS 16.3, watchOS 9.3, *)) { +// The avaliability attributes are marked as strict, so preprocessor +// conditionals must be used to check if it's available. +#define FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT 1 +#else +#define FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT 0 +#endif + +// FOLLY_CONV_USE_TO_CHARS set to 1 indicates that std::to_chars will be used +// because it's available and it was requested. +#if defined(FOLLY_CONV_DTOA_TO_CHARS) && FOLLY_CONV_DTOA_TO_CHARS == 1 && \ + defined(FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT) && \ + FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT == 1 +#define FOLLY_CONV_USE_TO_CHARS 1 +#else +#define FOLLY_CONV_USE_TO_CHARS 0 +#endif + +namespace folly { + +// Keep this in sync with kErrorStrings in Conv.cpp +enum class ConversionCode : unsigned char { + SUCCESS, + EMPTY_INPUT_STRING, + NO_DIGITS, + BOOL_OVERFLOW, + BOOL_INVALID_VALUE, + NON_DIGIT_CHAR, + INVALID_LEADING_CHAR, + POSITIVE_OVERFLOW, + NEGATIVE_OVERFLOW, + STRING_TO_FLOAT_ERROR, + NON_WHITESPACE_AFTER_END, + ARITH_POSITIVE_OVERFLOW, + ARITH_NEGATIVE_OVERFLOW, + ARITH_LOSS_OF_PRECISION, + NUM_ERROR_CODES, // has to be the last entry +}; + +struct FOLLY_EXPORT ConversionErrorBase : std::range_error { + using std::range_error::range_error; +}; + +class FOLLY_EXPORT ConversionError : public ConversionErrorBase { + public: + ConversionError(const std::string& str, ConversionCode code) + : ConversionErrorBase(str), code_(code) {} + + ConversionError(const char* str, ConversionCode code) + : ConversionErrorBase(str), code_(code) {} + + ConversionCode errorCode() const { return code_; } + + private: + ConversionCode code_; +}; + +/** + * Custom Error Translation + * + * Your overloaded parseTo() function can return a custom error code on failure. + * ::folly::to() will call makeConversionError to translate that error code into + * an object to throw. makeConversionError is found by argument-dependent + * lookup. It should have this signature: + * + * namespace other_namespace { + * enum YourErrorCode { BAD_ERROR, WORSE_ERROR }; + * + * struct YourConversionError : ConversionErrorBase { + * YourConversionError(const char* what) : ConversionErrorBase(what) {} + * }; + * + * YourConversionError + * makeConversionError(YourErrorCode code, ::folly::StringPiece sp) { + * ... + * return YourConversionError(messageString); + * } + */ +ConversionError makeConversionError(ConversionCode code, StringPiece input); + +namespace detail { +/** + * Enforce that the suffix following a number is made up only of whitespace. + */ +inline ConversionCode enforceWhitespaceErr(StringPiece sp) { + for (auto c : sp) { + if (FOLLY_UNLIKELY(!std::isspace(c))) { + return ConversionCode::NON_WHITESPACE_AFTER_END; + } + } + return ConversionCode::SUCCESS; +} + +/** + * Keep this implementation around for prettyToDouble(). + */ +inline void enforceWhitespace(StringPiece sp) { + auto err = enforceWhitespaceErr(sp); + if (err != ConversionCode::SUCCESS) { + throw_exception(makeConversionError(err, sp)); + } +} +} // namespace detail + +/** + * @overloadbrief to, but return an Expected + * + * The identity conversion function. + * tryTo(T) returns itself for all types T. + */ +template +typename std::enable_if< + std::is_same::type>::value, + Expected>::type +tryTo(Src&& value) noexcept { + return static_cast(value); +} + +/** + * @overloadbrief Convert from one type to another. + */ +template +typename std::enable_if< + std::is_same::type>::value, + Tgt>::type +to(Src&& value) { + return static_cast(value); +} + +/** + * Arithmetic to boolean + */ + +/** + * Unchecked conversion from arithmetic to boolean. This is different from the + * other arithmetic conversions because we use the C convention of treating any + * non-zero value as true, instead of range checking. + */ +template +typename std::enable_if< + is_arithmetic_v && !std::is_same::value && + std::is_same::value, + Expected>::type +tryTo(const Src& value) noexcept { + return value != Src(); +} + +template +typename std::enable_if< + is_arithmetic_v && !std::is_same::value && + std::is_same::value, + Tgt>::type +to(const Src& value) { + return value != Src(); +} + +/** + * Anything to string + */ + +namespace detail { + +template +using LastElement = type_pack_element_t; + +#ifdef _MSC_VER +// MSVC can't quite figure out the LastElementImpl::call() stuff +// in the base implementation, so we have to use tuples instead, +// which result in significantly more templates being compiled, +// though the runtime performance is the same. + +template > +const R& getLastElement(const Ts&... ts) { + return std::get(std::forward_as_tuple(ts...)); +} + +inline void getLastElement() {} +#else +template +struct LastElementImpl; +template <> +struct LastElementImpl<> { + static void call() {} +}; +template +struct LastElementImpl { + template + static const Last& call(Igns..., const Last& last) { + return last; + } +}; + +template > +const R& getLastElement(const Ts&... ts) { + return LastElementImpl...>::call(ts...); +} +#endif + +} // namespace detail + +/** + * Conversions from integral types to string types. + */ + +#if FOLLY_HAVE_INT128_T +namespace detail { + +template +constexpr unsigned int digitsEnough() { + // digits10 returns the number of decimal digits that this type can represent, + // not the number of characters required for the max value, so we need to add + // one. ex: char digits10 returns 2, because 256-999 cannot be represented, + // but we need 3. + auto const digits10 = std::numeric_limits::digits10; + return static_cast(digits10) + 1; +} + +inline size_t unsafeTelescope128(char* outb, char* oute, unsigned __int128 x) { + using Usrc = unsigned __int128; + + // Decompose the input into at most 3 components using the largest power-of-10 + // base that fits in a 64-bit unsigned integer, and then convert the + // components using 64-bit arithmetic and concatenate them. + constexpr static auto kBase = UINT64_C(10'000'000'000'000'000'000); + constexpr static size_t kBaseDigits = 19; + + size_t p = 0; + const auto leading = [&](Usrc v) { + assert(v >> 64 == 0); + p = detail::to_ascii_with_route<10, to_ascii_alphabet_lower>( + outb, oute, static_cast(v)); + }; + const auto append = [&](uint64_t v) { + assert(v < kBase); + assert(outb + p + kBaseDigits <= oute); + auto v64 = static_cast(v); + detail::to_ascii_with_route<10, to_ascii_alphabet_lower>( + outb + p, kBaseDigits, v64); + p += kBaseDigits; + }; + + if (x >> 64 > 0) { + const auto rem = static_cast(x % kBase); + x /= kBase; + + if (x >> 64 > 0) { + const auto rem2 = static_cast(x % kBase); + x /= kBase; + + leading(x); + append(rem2); + append(rem); + return p; + } + + leading(x); + append(rem); + return p; + } + + leading(x); + return p; +} + +} // namespace detail +#endif + +/** + * @overloadbrief Appends conversion to string. + * + * A single char gets appended. + */ +template +void toAppend(char value, Tgt* result) { + *result += value; +} + +/** + * @overloadbrief Estimates the number of characters in a value's string + * representation. + */ +template +constexpr typename std::enable_if::value, size_t>::type +estimateSpaceNeeded(T) { + return 1; +} + +template +constexpr size_t estimateSpaceNeeded(const char (&)[N]) { + return N; +} + +/** + * Everything implicitly convertible to const char* gets appended. + */ +template +typename std::enable_if< + std::is_convertible::value && + IsSomeString::value>::type +toAppend(Src value, Tgt* result) { + // Treat null pointers like an empty string, as in: + // operator<<(std::ostream&, const char*). + const char* c = value; + if (c) { + result->append(value); + } +} + +template +typename std::enable_if::value, size_t>:: + type + estimateSpaceNeeded(Src value) { + const char* c = value; + return c ? std::strlen(c) : 0; +} + +template +typename std::enable_if::value, size_t>::type +estimateSpaceNeeded(Src const& value) { + return value.size(); +} + +template +typename std::enable_if< + std::is_convertible::value && + !IsSomeString::value && + !std::is_convertible::value, + size_t>::type +estimateSpaceNeeded(Src value) { + return folly::StringPiece(value).size(); +} + +template <> +inline size_t estimateSpaceNeeded(std::nullptr_t /* value */) { + return 0; +} + +template +typename std::enable_if< + std::is_pointer::value && + IsSomeString>::value, + size_t>::type +estimateSpaceNeeded(Src value) { + return value->size(); +} + +/** + * Strings get appended, too. + */ +template +typename std::enable_if< + IsSomeString::value && IsSomeString::value>::type +toAppend(const Src& value, Tgt* result) { + result->append(value); +} + +/** + * and StringPiece objects too + */ +template +typename std::enable_if::value>::type toAppend( + StringPiece value, Tgt* result) { + result->append(value.data(), value.size()); +} + +/** + * There's no implicit conversion from fbstring to other string types, + * so make a specialization. + */ +template +typename std::enable_if::value>::type toAppend( + const fbstring& value, Tgt* result) { + result->append(value.data(), value.size()); +} + +#if FOLLY_HAVE_INT128_T +/** + * Special handling for 128 bit integers. + */ + +template +void toAppend(__int128 value, Tgt* result) { + typedef unsigned __int128 Usrc; + char buffer[detail::digitsEnough() + 1]; + const auto oute = buffer + sizeof(buffer); + size_t p; + + if (value < 0) { + buffer[0] = '-'; + p = 1 + detail::unsafeTelescope128(buffer + 1, oute, -Usrc(value)); + } else { + p = detail::unsafeTelescope128(buffer, oute, value); + } + + result->append(buffer, p); +} + +template +void toAppend(unsigned __int128 value, Tgt* result) { + char buffer[detail::digitsEnough()]; + size_t p = detail::unsafeTelescope128(buffer, buffer + sizeof(buffer), value); + result->append(buffer, p); +} + +template +constexpr + typename std::enable_if::value, size_t>::type + estimateSpaceNeeded(T) { + return detail::digitsEnough<__int128>(); +} + +template +constexpr typename std:: + enable_if::value, size_t>::type + estimateSpaceNeeded(T) { + return detail::digitsEnough(); +} + +#endif + +/** + * int32_t and int64_t to string (by appending) go through here. The + * result is APPENDED to a preexisting string passed as the second + * parameter. This should be efficient with fbstring because fbstring + * incurs no dynamic allocation below 23 bytes and no number has more + * than 22 bytes in its textual representation (20 for digits, one for + * sign, one for the terminating 0). + */ +template +typename std::enable_if< + is_integral_v && is_signed_v && IsSomeString::value && + sizeof(Src) >= 4>::type +toAppend(Src value, Tgt* result) { + char buffer[to_ascii_size_max_decimal]; + auto uvalue = value < 0 ? ~static_cast(value) + 1 + : static_cast(value); + if (value < 0) { + result->push_back('-'); + } + result->append(buffer, to_ascii_decimal(buffer, uvalue)); +} + +template +typename std::enable_if< + is_integral_v && is_signed_v && sizeof(Src) >= 4 && + sizeof(Src) < 16, + size_t>::type +estimateSpaceNeeded(Src value) { + auto uvalue = value < 0 ? ~static_cast(value) + 1 + : static_cast(value); + return size_t(value < 0) + to_ascii_size_decimal(uvalue); +} + +/** + * As above, but for uint32_t and uint64_t. + */ +template +typename std::enable_if< + is_integral_v && !is_signed_v && IsSomeString::value && + sizeof(Src) >= 4>::type +toAppend(Src value, Tgt* result) { + char buffer[to_ascii_size_max_decimal]; + result->append(buffer, to_ascii_decimal(buffer, value)); +} + +template +typename std::enable_if< + is_integral_v && !is_signed_v && sizeof(Src) >= 4 && + sizeof(Src) < 16, + size_t>::type +estimateSpaceNeeded(Src value) { + return to_ascii_size_decimal(value); +} + +/** + * All small signed and unsigned integers to string go through 32-bit + * types int32_t and uint32_t, respectively. + */ +template +typename std::enable_if< + is_integral_v && IsSomeString::value && sizeof(Src) < 4>::type +toAppend(Src value, Tgt* result) { + typedef typename std::conditional, int64_t, uint64_t>::type + Intermediate; + toAppend(static_cast(value), result); +} + +template +typename std::enable_if< + is_integral_v && sizeof(Src) < 4 && !std::is_same::value, + size_t>::type +estimateSpaceNeeded(Src value) { + typedef typename std::conditional, int64_t, uint64_t>::type + Intermediate; + return estimateSpaceNeeded(static_cast(value)); +} + +/** + * Enumerated values get appended as integers. + */ +template +typename std::enable_if< + std::is_enum::value && IsSomeString::value>::type +toAppend(Src value, Tgt* result) { + toAppend(to_underlying(value), result); +} + +template +typename std::enable_if::value, size_t>::type +estimateSpaceNeeded(Src value) { + return estimateSpaceNeeded(to_underlying(value)); +} + +/** + * Conversions from floating-point types to string types. + */ + +/// Operating mode for the floating point type version of +/// `folly::ToAppend`. This is modeled after +/// `double_conversion::DoubleToStringConverter::DtoaMode`. +/// Dtoa is an acryonym for Double to ASCII. +enum class DtoaMode { + /// Outputs the shortest representation of a `double`. + /// The output is either in decimal or exponential notation; which ever is + /// shortest. + SHORTEST, + /// Outputs the shortest representation of a `float`. + /// This outputs in either decimal or exponential notation, which ever is + /// shortest. + SHORTEST_SINGLE, + /// Outputs fixed precision after the decimal point. Similar to + /// `printf`'s %f. + /// The output is in decimal notation. + /// Use the `numDigits` parameter to specify the precision. + FIXED, + /// Outputs with a precision that is independent of the decimal point. + /// The outputs is either decimal or exponential notation, depending on the + /// value and the precision. + /// Similar to `printf`'s %g formating. + /// Use the `numDigits` parameter to specify the precision. + PRECISION, +}; + +/// Flags for the floating point type version of `folly::ToAppend`. +/// This is modeled after `double_conversion::DoubleToStringConverter::Flags`. +/// Dtoa is an acryonym for Double to ASCII. +/// This enum is used to store bit wise flags, so a variable of this type may be +/// a bitwise combination of these definitions. +enum class DtoaFlags { + NO_FLAGS = 0, + /// Emits a plus sign for positive exponents. e.g., 1.2e+3 + EMIT_POSITIVE_EXPONENT_SIGN = 1, + /// Emits a trailing decimal point. e.g., 123. + EMIT_TRAILING_DECIMAL_POINT = 2, + /// Emits a trailing decimal point. e.g., 123.0 + /// Requires `EMIT_TRAILING_DECIMAL_POINT` to be set. + EMIT_TRAILING_ZERO_AFTER_POINT = 4, + /// -0.0 outputs as 0.0 + UNIQUE_ZERO = 8, + /// Trailing zeros are removed from the fractional portion + /// of the result in precision mode. Matches `printf`'s %g. + /// When `EMIT_TRAILING_ZERO_AFTER_POINT` is also given, one trailing zero is + /// preserved. + NO_TRAILING_ZERO = 16, +}; + +constexpr DtoaFlags operator|(DtoaFlags a, DtoaFlags b) { + return static_cast(to_underlying(a) | to_underlying(b)); +} + +constexpr DtoaFlags operator&(DtoaFlags a, DtoaFlags b) { + return static_cast(to_underlying(a) & to_underlying(b)); +} + +namespace detail { +constexpr int kConvMaxDecimalInShortestLow = -6; +/// 10^kConvMaxDecimalInShortestLow. Replace with constexpr std::pow in C++26. +constexpr double kConvMaxDecimalInShortestLowValue = 0.000001; +constexpr int kConvMaxDecimalInShortestHigh = 21; +/// 10^kConvMaxDecimalInShortestHigh. Replace with constexpr std::pow in C++26. +constexpr double kConvMaxDecimalInShortestHighValue = + 1'000'000'000'000'000'000'000.0; +constexpr int kBase10MaximalLength = 17; + +enum class FloatToStringImpl { + LibDoubleConversion, + StdToChars, +}; + +#if defined(FOLLY_CONV_USE_TO_CHARS) && FOLLY_CONV_USE_TO_CHARS == 1 +constexpr FloatToStringImpl kConvFloatToStringImpl = + FloatToStringImpl::StdToChars; +constexpr int kConvMaxFixedDigitsAfterPoint = 100; +constexpr int kConvMaxPrecisionDigits = 120; +#else +constexpr FloatToStringImpl kConvFloatToStringImpl = + FloatToStringImpl::LibDoubleConversion; +constexpr int kConvMaxFixedDigitsAfterPoint = + double_conversion::DoubleToStringConverter::kMaxFixedDigitsAfterPoint; +constexpr int kConvMaxPrecisionDigits = + double_conversion::DoubleToStringConverter::kMaxPrecisionDigits; + +/// Converts `DtoaMode` to +/// `double_conversion::DoubleToStringConverter::DtoaMode`. +/// This is temporary until +/// `double_conversion::DoubleToStringConverter::DtoaMode` is removed. +constexpr double_conversion::DoubleToStringConverter::DtoaMode convert( + DtoaMode mode) { + switch (mode) { + case DtoaMode::SHORTEST: + return double_conversion::DoubleToStringConverter::SHORTEST; + case DtoaMode::SHORTEST_SINGLE: + return double_conversion::DoubleToStringConverter::SHORTEST_SINGLE; + case DtoaMode::FIXED: + return double_conversion::DoubleToStringConverter::FIXED; + case DtoaMode::PRECISION: + return double_conversion::DoubleToStringConverter::PRECISION; + } + + assert(false); + // Default to PRECISION per exising behavior. + return double_conversion::DoubleToStringConverter::PRECISION; +} + +/// Converts `DtoaFlags` to +/// `double_conversion::DoubleToStringConverter::DtoaFlags`. +/// This is temporary until +/// `double_conversion::DoubleToStringConverter::DtoaFlags` is removed. +constexpr double_conversion::DoubleToStringConverter::Flags convert( + DtoaFlags flags) { + return static_cast(flags); +} + +/** + * Wrapper around `double_conversion::DoubleToStringConverter`. + */ +template +typename std::enable_if< + std::is_floating_point::value && IsSomeString::value>::type +toAppendDoubleConversion( + Src value, + Tgt* result, + DtoaMode mode, + unsigned int numDigits, + DtoaFlags flags = DtoaFlags::NO_FLAGS) { + using namespace double_conversion; + DoubleToStringConverter::Flags dcFlags = detail::convert(flags); + DoubleToStringConverter conv( + dcFlags, + "Infinity", + "NaN", + 'E', + detail::kConvMaxDecimalInShortestLow, + detail::kConvMaxDecimalInShortestHigh, + 6, // max leading padding zeros + 1); // max trailing padding zeros + char buffer[256]; + StringBuilder builder(buffer, sizeof(buffer)); + DoubleToStringConverter::DtoaMode dcMode = detail::convert(mode); + FOLLY_PUSH_WARNING + FOLLY_CLANG_DISABLE_WARNING("-Wcovered-switch-default") + switch (dcMode) { + case DoubleToStringConverter::SHORTEST: + conv.ToShortest(value, &builder); + break; + case DoubleToStringConverter::SHORTEST_SINGLE: + conv.ToShortestSingle(static_cast(value), &builder); + break; + case DoubleToStringConverter::FIXED: + conv.ToFixed(value, int(numDigits), &builder); + break; + case DoubleToStringConverter::PRECISION: + default: + assert(dcMode == DoubleToStringConverter::PRECISION); + conv.ToPrecision(value, int(numDigits), &builder); + break; + } + FOLLY_POP_WARNING + const size_t length = size_t(builder.position()); + builder.Finalize(); + result->append(buffer, length); +} +#endif // FOLLY_CONV_USE_TO_CHARS + +#if defined(FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT) && \ + FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT == 1 +/// Holds a set of `DtoaFlags` as a bitwise OR of the flags. +/// It has convience member functions to check if a flag is set. +struct DtoaFlagsSet { + explicit DtoaFlagsSet(DtoaFlags flags); + + bool isSet(DtoaFlags flag) const; + + bool emitPositiveExponentSign() const; + bool emitTrailingDecimalPoint() const; + bool emitTrailingZeroAfterPoint() const; + bool uniqueZero() const; + bool noTrailingZero() const; + + private: + DtoaFlags flags_; +}; +/// This parses a decimal string into a structured format. +/// For example, given "123.456e+7", this will create pointers to the integer, +/// fractional, exponentional parts. +/// +/// The decimal string is passed in as a `char` buffer with begin and end +/// pointers. The parsing will create pointers to parts of the decimal string. +/// +/// e.g., +/// -123.456e+78 +/// ABCDEFGHIJK +/// negativeSign points to address A +/// integerBegin points to address B +/// integerEnd points to address E +/// and so on... +/// +/// The is used to format the output of `std::to_chars` so that it is consistent +/// with `double_conversion::DoubleToStringConverter`'s format. +/// +/// This also has helper member functions to identify parts needed to apply +/// `DtoaMode::PRECISION` formating. +class ParsedDecimal { + public: + char* negativeSign{}; + char* integerBegin{}; + char* integerEnd{}; + char* decimalPoint{}; + char* fractionalBegin{}; + char* fractionalEnd{}; + char* exponentSymbol{}; + char* exponentSign{}; + char* exponentBegin{}; + char* exponentEnd{}; + + ParsedDecimal(char* begin, char* end); + + /// Returns the number of figures that count in PRECISION/general mode. + /// This is needed to know how many more figures to add when NO_TRAILING_ZERO + /// is unset. + int numPrecisionFigures() const; + + /// first is the begin pointer of the fractional suffix. + /// second is the end pointer of the fractional suffix. + using FractionalSuffix = std::pair; + + /// Returns pointers to the suffix after the fraction. + /// e.g., for "12.34-56" this returns pointers to "e-56". + /// Returns nothing if there is no suffix (e.g., "7.89"). + std::optional fractionalSuffix() const; + + /// Shifts the pointers of the fractional suffix by the given amount. + /// This is used when inserting additional figures for `DtoaMode::PRECISION`. + /// The pointers need to be updated after the fractional suffix is `memmove`'d + /// to accommodate the additional figures. + void shiftFractionalSuffixPtrs(size_t amount); +}; + +/// Formats the output from `std::to_chars` as if it came from +/// `double_conversion::DoubleToStringConverter`. +/// +/// Specifically it adds support for: +/// - EMIT_POSITIVE_EXPONENT_SIGN +/// - EMIT_TRAILING_DECIMAL_POINT +/// - EMIT_TRAILING_ZERO_AFTER_POINT +/// - UNIQUE_ZERO +/// - NO_TRAILING_ZERO +/// - Captial E exponent sign (e.g., 1.23e4 -> 1.23E4) +/// - Removes leading zeros in exponent (e.g., 1.23e04 -> 1.23e4) +/// +/// This modifies the result buffer in place to match the output format of +/// `double_conversion::DoubleToStringConverter`. +/// `resultBegin` is the begin pointer of the result from `std::to_chars`. +/// `resultEnd` is the end pointer of the result from `std::to_chars`. +/// `bufferEnd` is the end pointer of the buffer space given to `std::to_chars`. +/// The extra buffer space is used to expand the result. +/// `resultBegin`, `resultEnd`, and `bufferEnd` must point to the same buffer. +/// +/// The first char* of the return type is the begin pointer of the newly +/// formatted output. The second char* of the return type is the begin pointer +/// of the newly formatted output. +std::pair formatAsDoubleConversion( + bool valueIsZero, + DtoaMode mode, + unsigned int numDigits, + DtoaFlags flags, + char* resultBegin, + char* resultEnd, + char* bufferEnd); + +template +typename std::enable_if< + std::is_floating_point::value && IsSomeString::value>::type +toAppendStdToChars( + Src value, + Tgt* result, + DtoaMode mode, + unsigned int numDigits, + DtoaFlags flags = DtoaFlags::NO_FLAGS) { + if (std::isnan(value)) { + // no signbit check because -nan outputs as NaN + result->append("NaN", 3); + return; + } + + if (std::isinf(value)) { + if (std::signbit(value)) { + result->append("-", 1); + } + // std::to_chars returns "inf", this needs "Infinity" + result->append("Infinity", 8); + return; + } + + if (mode == DtoaMode::PRECISION && + (numDigits == 0 || numDigits > detail::kConvMaxPrecisionDigits)) { + // double_conversion outputs the empty string in this scenario + return; + } + + if (mode == DtoaMode::FIXED && + numDigits > detail::kConvMaxFixedDigitsAfterPoint) { + // double_conversion outputs the empty string in this scenario + return; + } + + bool useShortestFixed{false}; + if (mode == DtoaMode::SHORTEST || mode == DtoaMode::SHORTEST_SINGLE) { + Src absValue = std::abs(value); + // use fixed decimal notation (i.e., not exponential notation) + // for values in this range to match double-conversion formatting. + useShortestFixed = kConvMaxDecimalInShortestLowValue <= absValue && + absValue < kConvMaxDecimalInShortestHighValue; + } + + std::to_chars_result conv_result; + char buffer[256]; + char* const bufferEnd = buffer + sizeof(buffer); + FOLLY_PUSH_WARNING + FOLLY_CLANG_DISABLE_WARNING("-Wcovered-switch-default") + switch (mode) { + case DtoaMode::SHORTEST: { + if (useShortestFixed) { + conv_result = + std::to_chars(buffer, bufferEnd, value, std::chars_format::fixed); + } else { + conv_result = std::to_chars(buffer, bufferEnd, value); + } + break; + } + case DtoaMode::SHORTEST_SINGLE: + if (useShortestFixed) { + conv_result = std::to_chars( + buffer, + bufferEnd, + static_cast(value), + std::chars_format::fixed); + } else { + conv_result = + std::to_chars(buffer, bufferEnd, static_cast(value)); + } + break; + case DtoaMode::FIXED: + conv_result = std::to_chars( + buffer, bufferEnd, value, std::chars_format::fixed, numDigits); + break; + case DtoaMode::PRECISION: + default: + assert(mode == DtoaMode::PRECISION); + conv_result = std::to_chars( + buffer, bufferEnd, value, std::chars_format::general, numDigits); + break; + } + FOLLY_POP_WARNING + + auto [resultEnd, ec] = conv_result; + if (ec != std::errc()) { + folly::throw_exception(std::make_error_code(ec)); + } + + char* resultBegin = buffer; + bool valueIsZero = value == 0.0; + auto [formattedBegin, formattedEnd] = detail::formatAsDoubleConversion( + valueIsZero, mode, numDigits, flags, resultBegin, resultEnd, bufferEnd); + + result->append(formattedBegin, formattedEnd - formattedBegin); +} +#endif // FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT +} // namespace detail + +/** + * `numDigits` is only used with `FIXED` && `PRECISION`. + */ +template +typename std::enable_if< + std::is_floating_point::value && IsSomeString::value>::type +toAppend( + Src value, + Tgt* result, + DtoaMode mode, + unsigned int numDigits, + DtoaFlags flags = DtoaFlags::NO_FLAGS) { +#if defined(FOLLY_CONV_USE_TO_CHARS) && FOLLY_CONV_USE_TO_CHARS == 1 + detail::toAppendStdToChars(value, result, mode, numDigits, flags); +#else + detail::toAppendDoubleConversion(value, result, mode, numDigits, flags); +#endif +} + +/** + * As above, but for floating point + */ +template +typename std::enable_if< + std::is_floating_point::value && IsSomeString::value>::type +toAppend(Src value, Tgt* result) { + toAppend(value, result, DtoaMode::SHORTEST, 0); +} + +/** + * Upper bound of the length of the output from + * DoubleToStringConverter::ToShortest(double, StringBuilder*), + * as used in toAppend(double, string*). + */ +template +typename std::enable_if::value, size_t>::type +estimateSpaceNeeded(Src value) { + // kBase10MaximalLength is 17. We add 1 for decimal point, + // e.g. 10.0/9 is 17 digits and 18 characters, including the decimal point. + constexpr int kMaxMantissaSpace = detail::kBase10MaximalLength + 1; + // strlen("E-") + digits10(numeric_limits::max_exponent10) + constexpr int kMaxExponentSpace = 2 + 3; + static const int kMaxPositiveSpace = std::max({ + // E.g. 1.1111111111111111E-100. + kMaxMantissaSpace + kMaxExponentSpace, + // E.g. 0.000001.1111111111111111, if kConvMaxDecimalInShortestLow is -6. + kMaxMantissaSpace - detail::kConvMaxDecimalInShortestLow, + // If kConvMaxDecimalInShortestHigh is 21, then 1e21 is the smallest + // number > 1 which ToShortest outputs in exponential notation, + // so 21 is the longest non-exponential number > 1. + detail::kConvMaxDecimalInShortestHigh, + }); + return size_t( + kMaxPositiveSpace + + (value < 0 ? 1 : 0)); // +1 for minus sign, if negative +} + +template +constexpr typename std::enable_if< + !std::is_fundamental::value && +#if FOLLY_HAVE_INT128_T + // On OSX 10.10, is_fundamental<__int128> is false :-O + !std::is_same<__int128, Src>::value && + !std::is_same::value && +#endif + !IsSomeString::value && + !std::is_convertible::value && + !std::is_convertible::value && + !std::is_enum::value, + size_t>::type +estimateSpaceNeeded(const Src&) { + return sizeof(Src) + 1; // dumbest best effort ever? +} + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +namespace detail { + +FOLLY_ERASE constexpr size_t estimateSpaceToReserveOne(std::false_type, void*) { + return 0; +} +template +FOLLY_ERASE constexpr size_t estimateSpaceToReserveOne( + std::true_type, const T& v) { + return estimateSpaceNeeded(v); +} + +template +struct EstimateSpaceToReserveAll; +template +struct EstimateSpaceToReserveAll> { + template + using tag = std::bool_constant; + template + static size_t call(const T&... v) { + const size_t sizes[] = {estimateSpaceToReserveOne(tag{}, v)...}; + size_t size = 0; + for (const auto s : sizes) { + size += s; + } + return size; + } +}; + +template +void reserveInTarget(const O& o) { + (void)o; +} +template +void reserveInTarget(const T& v, const O& o) { + o->reserve(estimateSpaceNeeded(v)); +} +template +void reserveInTarget(const T0& v0, const T1& v1, const Ts&... vs) { + using seq = std::index_sequence_for; + getLastElement(vs...)->reserve( + EstimateSpaceToReserveAll::call(v0, v1, vs...)); +} + +template +void reserveInTargetDelim(const Delimiter& d, const Ts&... vs) { + static_assert(sizeof...(vs) >= 2, "Needs at least 2 args"); + using seq = std::index_sequence_for; + size_t fordelim = (sizeof...(vs) - 2) * estimateSpaceNeeded(d); + getLastElement(vs...)->reserve( + fordelim + EstimateSpaceToReserveAll::call(vs...)); +} + +template +FOLLY_ERASE constexpr int toAppendStrImplOne( + std::false_type, const T& v, void*) { + (void)v; + return 0; +} +template +FOLLY_ERASE int toAppendStrImplOne(std::true_type, const T& v, Tgt result) { + return toAppend(v, result), 0; +} +template +struct ToAppendStrImplAll; +template +struct ToAppendStrImplAll> { + template + static void call(const T&... v) { + using _ = int[]; + auto r = getLastElement(v...); + void(_{toAppendStrImplOne( + std::bool_constant{}, v, r)...}); + } +}; + +template +FOLLY_ERASE constexpr int toAppendDelimStrImplOne( + index_constant<0>, const Delimiter& d, const T& v, void*) { + (void)d; + (void)v; + return 0; +} +template +FOLLY_ERASE int toAppendDelimStrImplOne( + index_constant<1>, const Delimiter& d, const T& v, Tgt result) { + (void)d; + toAppend(v, result); + return 0; +} +template +FOLLY_ERASE int toAppendDelimStrImplOne( + index_constant<2>, const Delimiter& d, const T& v, Tgt result) { + toAppend(v, result); + toAppend(d, result); + return 0; +} +template +struct ToAppendDelimStrImplAll; +template +struct ToAppendDelimStrImplAll> { + template + using tag = index_constant<(K < 2 ? K : 2)>; + template + static void call(const Delimiter& d, const T&... v) { + using _ = int[]; + auto r = detail::getLastElement(v...); + void(_{toAppendDelimStrImplOne(tag{}, d, v, r)...}); + } +}; +template < + class Delimiter, + class T, + class... Ts, + std::enable_if_t< + sizeof...(Ts) >= 2 && + IsSomeString>::type>::value, + int> = 0> +void toAppendDelimStrImpl(const Delimiter& delim, const T& v, const Ts&... vs) { + using seq = std::index_sequence_for; + ToAppendDelimStrImplAll::call(delim, v, vs...); +} +} // namespace detail +#endif + +/** + * Variadic conversion to string. Appends each element in turn. + * If we have two or more things to append, we will not reserve + * the space for them and will depend on strings exponential growth. + * If you just append once consider using toAppendFit which reserves + * the space needed (but does not have exponential as a result). + * + * Custom implementations of toAppend() can be provided in the same namespace as + * the type to customize printing. estimateSpaceNeed() may also be provided to + * avoid reallocations in toAppendFit(): + * + * namespace other_namespace { + * + * template + * void toAppend(const OtherType&, String* out); + * + * // optional + * size_t estimateSpaceNeeded(const OtherType&); + * + * } + */ +template < + class... Ts, + std::enable_if_t< + sizeof...(Ts) >= 3 && + IsSomeString>::type>::value, + int> = 0> +void toAppend(const Ts&... vs) { + using seq = std::index_sequence_for; + detail::ToAppendStrImplAll::call(vs...); +} + +/** + * @overloadbrief toAppend, but pre-allocate the exact amount of space required. + * + * Special version of the call that preallocates exactly as much memory + * as need for arguments to be stored in target. This means we are + * not doing exponential growth when we append. If you are using it + * in a loop you are aiming at your foot with a big perf-destroying + * bazooka. + * On the other hand if you are appending to a string once, this + * will probably save a few calls to malloc. + */ +template < + class... Ts, + std::enable_if_t< + IsSomeString>::type>::value, + int> = 0> +void toAppendFit(const Ts&... vs) { + ::folly::detail::reserveInTarget(vs...); + toAppend(vs...); +} + +template +void toAppendFit(const Ts&) {} + +/** + * Variadic base case: do nothing. + */ +template +typename std::enable_if::value>::type toAppend( + Tgt* /* result */) {} + +/** + * @overloadbrief Use a specified delimiter between appendees. + * + * Variadic base case: do nothing. + */ +template +typename std::enable_if::value>::type toAppendDelim( + const Delimiter& /* delim */, Tgt* /* result */) {} + +/** + * 1 element: same as toAppend. + */ +template +typename std::enable_if::value>::type toAppendDelim( + const Delimiter& /* delim */, const T& v, Tgt* tgt) { + toAppend(v, tgt); +} + +/** + * Append to string with a delimiter in between elements. Check out + * comments for toAppend for details about memory allocation. + */ +template < + class Delimiter, + class... Ts, + std::enable_if_t< + sizeof...(Ts) >= 3 && + IsSomeString>::type>::value, + int> = 0> +void toAppendDelim(const Delimiter& delim, const Ts&... vs) { + detail::toAppendDelimStrImpl(delim, vs...); +} + +/** + * @overloadbrief toAppend with custom delimiter and exact pre-allocation. + * + * Detail in comment for toAppendFit + */ +template < + class Delimiter, + class... Ts, + std::enable_if_t< + IsSomeString>::type>::value, + int> = 0> +void toAppendDelimFit(const Delimiter& delim, const Ts&... vs) { + detail::reserveInTargetDelim(delim, vs...); + toAppendDelim(delim, vs...); +} + +template +void toAppendDelimFit(const De&, const Ts&) {} + +/** + * to(v1, v2, ...) uses toAppend() (see below) as back-end + * for all types. + */ +template < + class Tgt, + class... Ts, + std::enable_if_t< + IsSomeString::value && + (sizeof...(Ts) != 1 || + !std::is_same>::value), + int> = 0> +Tgt to(const Ts&... vs) { + Tgt result; + toAppendFit(vs..., &result); + return result; +} + +/** + * Special version of to for floating point. When calling + * folly::to(double), generic implementation above will + * firstly reserve 24 (or 25 when negative value) bytes. This will + * introduce a malloc call for most mainstream string implementations. + * + * But for most cases, a floating point doesn't need 24 (or 25) bytes to + * be converted as a string. + * + * This special version will not do string reserve. + */ +template +typename std::enable_if< + IsSomeString::value && std::is_floating_point::value, + Tgt>::type +to(Src value) { + Tgt result; + toAppend(value, &result); + return result; +} + +/** + * @overloadbrief Like `to`, but uses a custom delimiter. + * + * toDelim(SomeString str) returns itself. + */ +template +typename std::enable_if< + IsSomeString::value && + std::is_same::type>::value, + Tgt>::type +toDelim(const Delim& /* delim */, Src&& value) { + return static_cast(value); +} + +/** + * toDelim(delim, v1, v2, ...) uses toAppendDelim() as + * back-end for all types. + */ +template < + class Tgt, + class Delim, + class... Ts, + std::enable_if_t< + IsSomeString::value && + (sizeof...(Ts) != 1 || + !std::is_same>::value), + int> = 0> +Tgt toDelim(const Delim& delim, const Ts&... vs) { + Tgt result; + toAppendDelimFit(delim, vs..., &result); + return result; +} + +/** + * Conversions from string types to integral types. + */ + +namespace detail { + +Expected str_to_bool(StringPiece* src) noexcept; + +template +Expected str_to_floating(StringPiece* src) noexcept; + +extern template Expected str_to_floating( + StringPiece* src) noexcept; +extern template Expected str_to_floating( + StringPiece* src) noexcept; + +template +Expected str_to_floating_fast_float_from_chars( + StringPiece* src) noexcept; + +extern template Expected +str_to_floating_fast_float_from_chars(StringPiece* src) noexcept; +extern template Expected +str_to_floating_fast_float_from_chars(StringPiece* src) noexcept; + +template +Expected digits_to(const char* b, const char* e) noexcept; + +extern template Expected digits_to( + const char*, const char*) noexcept; +extern template Expected digits_to( + const char*, const char*) noexcept; +extern template Expected +digits_to(const char*, const char*) noexcept; + +extern template Expected digits_to( + const char*, const char*) noexcept; +extern template Expected +digits_to(const char*, const char*) noexcept; + +extern template Expected digits_to( + const char*, const char*) noexcept; +extern template Expected digits_to( + const char*, const char*) noexcept; + +extern template Expected digits_to( + const char*, const char*) noexcept; +extern template Expected +digits_to(const char*, const char*) noexcept; + +extern template Expected digits_to( + const char*, const char*) noexcept; +extern template Expected +digits_to(const char*, const char*) noexcept; + +#if FOLLY_HAVE_INT128_T +extern template Expected<__int128, ConversionCode> digits_to<__int128>( + const char*, const char*) noexcept; +extern template Expected +digits_to(const char*, const char*) noexcept; +#endif + +template +Expected str_to_integral(StringPiece* src) noexcept; + +extern template Expected str_to_integral( + StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; + +extern template Expected str_to_integral( + StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; + +extern template Expected str_to_integral( + StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; + +extern template Expected str_to_integral( + StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; + +extern template Expected str_to_integral( + StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; + +#if FOLLY_HAVE_INT128_T +extern template Expected<__int128, ConversionCode> str_to_integral<__int128>( + StringPiece* src) noexcept; +extern template Expected +str_to_integral(StringPiece* src) noexcept; +#endif + +template +typename std:: + enable_if::value, Expected>::type + convertTo(StringPiece* src) noexcept { + return str_to_bool(src); +} + +template +typename std::enable_if< + std::is_floating_point::value, + Expected>::type +convertTo(StringPiece* src) noexcept { + return str_to_floating(src); +} + +template +typename std::enable_if< + is_integral_v && !std::is_same::value, + Expected>::type +convertTo(StringPiece* src) noexcept { + return str_to_integral(src); +} + +} // namespace detail + +/** + * String represented as a pair of pointers to char to unsigned + * integrals. Assumes NO whitespace before or after. + */ +template +typename std::enable_if< + is_integral_v && !std::is_same::value, + Expected>::type +tryTo(const char* b, const char* e) noexcept { + return detail::digits_to(b, e); +} + +template +typename std::enable_if< // + is_integral_v && !std::is_same::value, + Tgt>::type +to(const char* b, const char* e) { + return tryTo(b, e).thenOrThrow(identity, [=](ConversionCode code) { + return makeConversionError(code, StringPiece(b, e)); + }); +} + +/** + * Conversions from string types to arithmetic types. + */ + +/** + * Parsing strings to numeric types. + */ +template +FOLLY_NODISCARD inline typename std::enable_if< // + is_arithmetic_v, + Expected>::type +parseTo(StringPiece src, Tgt& out) { + return detail::convertTo(&src).then( + [&](Tgt res) { return void(out = res), src; }); +} + +/** + * Integral / Floating Point to integral / Floating Point + */ + +namespace detail { + +/** + * Bool to integral/float doesn't need any special checks, and this + * overload means we aren't trying to see if a bool is less than + * an integer. + */ +template +typename std::enable_if< + !std::is_same::value && + (is_integral_v || std::is_floating_point::value), + Expected>::type +convertTo(const bool& value) noexcept { + return static_cast(value ? 1 : 0); +} + +/** + * Checked conversion from integral to integral. The checks are only + * performed when meaningful, e.g. conversion from int to long goes + * unchecked. + */ +template +typename std::enable_if< + is_integral_v && !std::is_same::value && + !std::is_same::value && is_integral_v, + Expected>::type +convertTo(const Src& value) noexcept { + if /* constexpr */ ( + make_unsigned_t(std::numeric_limits::max()) < + make_unsigned_t(std::numeric_limits::max())) { + if (greater_than::max()>(value)) { + return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW); + } + } + if /* constexpr */ ( + is_signed_v && (!is_signed_v || sizeof(Src) > sizeof(Tgt))) { + if (less_than::min()>(value)) { + return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW); + } + } + return static_cast(value); +} + +/** + * Checked conversion from floating to floating. The checks are only + * performed when meaningful, e.g. conversion from float to double goes + * unchecked. + */ +template +typename std::enable_if< + std::is_floating_point::value && std::is_floating_point::value && + !std::is_same::value, + Expected>::type +convertTo(const Src& value) noexcept { + if (FOLLY_UNLIKELY(std::isinf(value))) { + return static_cast(value); + } + if /* constexpr */ ( + std::numeric_limits::max() < std::numeric_limits::max()) { + if (value > std::numeric_limits::max()) { + return makeUnexpected(ConversionCode::ARITH_POSITIVE_OVERFLOW); + } + if (value < std::numeric_limits::lowest()) { + return makeUnexpected(ConversionCode::ARITH_NEGATIVE_OVERFLOW); + } + } + return static_cast(value); +} + +/** + * Check if a floating point value can safely be converted to an + * integer value without triggering undefined behaviour. + */ +template +inline typename std::enable_if< + std::is_floating_point::value && is_integral_v && + !std::is_same::value, + bool>::type +checkConversion(const Src& value) { + constexpr Src tgtMaxAsSrc = static_cast(std::numeric_limits::max()); + constexpr Src tgtMinAsSrc = static_cast(std::numeric_limits::min()); + // NOTE: The following two comparisons also handle the case where value is + // NaN, as all comparisons with NaN are false. + if (!(value < tgtMaxAsSrc)) { + if (!(value <= tgtMaxAsSrc)) { + return false; + } + const Src mmax = folly::nextafter(tgtMaxAsSrc, Src()); + if (static_cast(value - mmax) > + std::numeric_limits::max() - static_cast(mmax)) { + return false; + } + } else if (value <= tgtMinAsSrc) { + if (value < tgtMinAsSrc) { + return false; + } + const Src mmin = folly::nextafter(tgtMinAsSrc, Src()); + if (static_cast(value - mmin) < + std::numeric_limits::min() - static_cast(mmin)) { + return false; + } + } + return true; +} + +// Integers can always safely be converted to floating point values +template +constexpr typename std::enable_if< + is_integral_v && std::is_floating_point::value, + bool>::type +checkConversion(const Src&) { + return true; +} + +// Also, floating point values can always be safely converted to bool +// Per the standard, any floating point value that is not zero will yield true +template +constexpr typename std::enable_if< + std::is_floating_point::value && std::is_same::value, + bool>::type +checkConversion(const Src&) { + return true; +} + +/** + * Checked conversion from integral to floating point and back. The + * result must be convertible back to the source type without loss of + * precision. This seems Draconian but sometimes is what's needed, and + * complements existing routines nicely. For various rounding + * routines, see . + */ +template +typename std::enable_if< + (is_integral_v && std::is_floating_point::value) || + (std::is_floating_point::value && is_integral_v), + Expected>::type +convertTo(const Src& value) noexcept { + if (FOLLY_LIKELY(checkConversion(value))) { + Tgt result = static_cast(value); + if (FOLLY_LIKELY(checkConversion(result))) { + Src witness = static_cast(result); + if (FOLLY_LIKELY(value == witness)) { + return result; + } + } + } + return makeUnexpected(ConversionCode::ARITH_LOSS_OF_PRECISION); +} + +template +inline std::string errorValue(const Src& value) { + return to("(", pretty_name(), ") ", value); +} + +template +using IsArithToArith = std::bool_constant< + !std::is_same::value && !std::is_same::value && + is_arithmetic_v && is_arithmetic_v>; + +} // namespace detail + +template +typename std::enable_if< + detail::IsArithToArith::value, + Expected>::type +tryTo(const Src& value) noexcept { + return detail::convertTo(value); +} + +template +typename std::enable_if::value, Tgt>::type to( + const Src& value) { + return tryTo(value).thenOrThrow(identity, [&](ConversionCode e) { + return makeConversionError(e, detail::errorValue(value)); + }); +} + +/** + * Custom Conversions + * + * Any type can be used with folly::to by implementing parseTo. The + * implementation should be provided in the namespace of the type to facilitate + * argument-dependent lookup: + * + * namespace other_namespace { + * ::folly::Expected<::folly::StringPiece, SomeErrorCode> + * parseTo(::folly::StringPiece, OtherType&) noexcept; + * } + */ +template +FOLLY_NODISCARD typename std::enable_if< + std::is_enum::value, + Expected>::type +parseTo(StringPiece in, T& out) noexcept { + typename std::underlying_type::type tmp{}; + auto restOrError = parseTo(in, tmp); + out = static_cast(tmp); // Harmless if parseTo fails + return restOrError; +} + +FOLLY_NODISCARD +inline Expected parseTo( + StringPiece in, StringPiece& out) noexcept { + out = in; + return StringPiece{in.end(), in.end()}; +} + +namespace detail { + +template +FOLLY_ERASE Expected parseToStr( + StringPiece in, Str& out) { + out.clear(); + out.append(in.data(), in.size()); // TODO try/catch? + return StringPiece{in.end(), in.end()}; +} + +} // namespace detail + +FOLLY_NODISCARD +inline Expected parseTo( + StringPiece in, std::string& out) { + return detail::parseToStr(in, out); +} + +FOLLY_NODISCARD +inline Expected parseTo( + StringPiece in, std::string_view& out) { + out = std::string_view(in.data(), in.size()); + return StringPiece{in.end(), in.end()}; +} + +FOLLY_NODISCARD +inline Expected parseTo( + StringPiece in, fbstring& out) { + return detail::parseToStr(in, out); +} + +template +FOLLY_NODISCARD inline typename std::enable_if< + IsSomeString::value, + Expected>::type +parseTo(StringPiece in, Str& out) { + return detail::parseToStr(in, out); +} + +namespace detail { +template +using ParseToResult = decltype(parseTo(StringPiece{}, std::declval())); + +struct CheckTrailingSpace { + Expected operator()(StringPiece sp) const { + auto e = enforceWhitespaceErr(sp); + if (FOLLY_UNLIKELY(e != ConversionCode::SUCCESS)) { + return makeUnexpected(e); + } + return unit; + } +}; + +template +struct ReturnUnit { + template + constexpr Expected operator()(T&&) const { + return unit; + } +}; + +// Older versions of the parseTo customization point threw on error and +// returned void. Handle that. +template +inline typename std::enable_if< + std::is_void>::value, + Expected>::type +parseToWrap(StringPiece sp, Tgt& out) { + parseTo(sp, out); + return StringPiece(sp.end(), sp.end()); +} + +template +inline typename std::enable_if< + !std::is_void>::value, + ParseToResult>::type +parseToWrap(StringPiece sp, Tgt& out) { + return parseTo(sp, out); +} + +template +using ParseToError = ExpectedErrorType()))>; + +} // namespace detail + +/** + * String or StringPiece to target conversion. Accepts leading and trailing + * whitespace, but no non-space trailing characters. + */ + +template +inline typename std::enable_if< + !std::is_same::value, + Expected>>::type +tryTo(StringPiece src) noexcept { + Tgt result{}; + using Error = detail::ParseToError; + using Check = typename std::conditional< + is_arithmetic_v, + detail::CheckTrailingSpace, + detail::ReturnUnit>::type; + return parseTo(src, result).then(Check(), [&](Unit) { + return std::move(result); + }); +} + +template +inline typename std::enable_if< + IsSomeString::value && !std::is_same::value, + Tgt>::type +to(Src const& src) { + return to(StringPiece(src.data(), src.size())); +} + +template +inline + typename std::enable_if::value, Tgt>::type + to(StringPiece src) { + Tgt result{}; + using Error = detail::ParseToError; + using Check = typename std::conditional< + is_arithmetic_v, + detail::CheckTrailingSpace, + detail::ReturnUnit>::type; + auto tmp = detail::parseToWrap(src, result); + return tmp + .thenOrThrow( + Check(), + [&](Error e) { throw_exception(makeConversionError(e, src)); }) + .thenOrThrow( + [&](Unit) { return std::move(result); }, + [&](Error e) { + throw_exception(makeConversionError(e, tmp.value())); + }); +} + +/** + * tryTo/to that take the strings by pointer so the caller gets information + * about how much of the string was consumed by the conversion. These do not + * check for trailing whitespace. + */ +template +Expected> tryTo(StringPiece* src) noexcept { + Tgt result; + return parseTo(*src, result).then([&, src](StringPiece sp) -> Tgt { + *src = sp; + return std::move(result); + }); +} + +template +Tgt to(StringPiece* src) { + Tgt result{}; + using Error = detail::ParseToError; + return parseTo(*src, result) + .thenOrThrow( + [&, src](StringPiece sp) -> Tgt { + *src = sp; + return std::move(result); + }, + [=](Error e) { return makeConversionError(e, *src); }); +} + +/** + * Enum to anything and back + */ + +template +typename std::enable_if< + std::is_enum::value && !std::is_same::value && + !std::is_convertible::value, + Expected>::type +tryTo(const Src& value) noexcept { + return tryTo(to_underlying(value)); +} + +template +typename std::enable_if< + !std::is_convertible::value && std::is_enum::value && + !std::is_same::value, + Expected>::type +tryTo(const Src& value) noexcept { + using I = typename std::underlying_type::type; + return tryTo(value).then([](I i) { return static_cast(i); }); +} + +template +typename std::enable_if< + std::is_enum::value && !std::is_same::value && + !std::is_convertible::value, + Tgt>::type +to(const Src& value) { + return to(to_underlying(value)); +} + +template +typename std::enable_if< + !std::is_convertible::value && std::is_enum::value && + !std::is_same::value, + Tgt>::type +to(const Src& value) { + return static_cast(to::type>(value)); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/CppAttributes.h b/vnext/external/folly/folly/CppAttributes.h new file mode 100644 index 00000000000..3400f859322 --- /dev/null +++ b/vnext/external/folly/folly/CppAttributes.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * GCC compatible wrappers around clang attributes. + */ + +#pragma once + +#include + +#ifndef __has_attribute +#define FOLLY_HAS_ATTRIBUTE(x) 0 +#else +#define FOLLY_HAS_ATTRIBUTE(x) __has_attribute(x) +#endif + +#ifndef __has_cpp_attribute +#define FOLLY_HAS_CPP_ATTRIBUTE(x) 0 +#else +#define FOLLY_HAS_CPP_ATTRIBUTE(x) __has_cpp_attribute(x) +#endif + +#ifndef __has_extension +#define FOLLY_HAS_EXTENSION(x) 0 +#else +#define FOLLY_HAS_EXTENSION(x) __has_extension(x) +#endif + +/** + * Nullable indicates that a return value or a parameter may be a `nullptr`, + * e.g. + * + * int* FOLLY_NULLABLE foo(int* a, int* FOLLY_NULLABLE b) { + * if (*a > 0) { // safe dereference + * return nullptr; + * } + * if (*b < 0) { // unsafe dereference + * return *a; + * } + * if (b != nullptr && *b == 1) { // safe checked dereference + * return new int(1); + * } + * return nullptr; + * } + * + * Ignores Clang's -Wnullability-extension since it correctly handles the case + * where the extension is not present. + */ +#if FOLLY_HAS_EXTENSION(nullability) +#define FOLLY_NULLABLE \ + FOLLY_PUSH_WARNING \ + FOLLY_CLANG_DISABLE_WARNING("-Wnullability-extension") \ + _Nullable FOLLY_POP_WARNING +#define FOLLY_NONNULL \ + FOLLY_PUSH_WARNING \ + FOLLY_CLANG_DISABLE_WARNING("-Wnullability-extension") \ + _Nonnull FOLLY_POP_WARNING +#else +#define FOLLY_NULLABLE +#define FOLLY_NONNULL +#endif + +/** + * "Cold" indicates to the compiler that a function is only expected to be + * called from unlikely code paths. It can affect decisions made by the + * optimizer both when processing the function body and when analyzing + * call-sites. + */ +#if FOLLY_HAS_CPP_ATTRIBUTE(gnu::cold) +#define FOLLY_ATTR_GNU_COLD gnu::cold +#else +#define FOLLY_ATTR_GNU_COLD +#endif + +/// FOLLY_ATTR_MAYBE_UNUSED_IF_NDEBUG +/// +/// When defined(NDEBUG), expands to maybe_unused; otherwise, expands to empty. +/// Useful for marking variables that are used, in the sense checked for by the +/// attribute maybe_unused, only in debug builds. +#if defined(NDEBUG) +#define FOLLY_ATTR_MAYBE_UNUSED_IF_NDEBUG maybe_unused +#else +#define FOLLY_ATTR_MAYBE_UNUSED_IF_NDEBUG +#endif + +/** + * no_unique_address indicates that a member variable can be optimized to + * occupy no space, rather than the minimum 1-byte used by default. + * + * class Empty {}; + * + * class NonEmpty1 { + * [[FOLLY_ATTR_NO_UNIQUE_ADDRESS]] Empty e; + * int f; + * }; + * + * class NonEmpty2 { + * Empty e; + * int f; + * }; + * + * sizeof(NonEmpty1); // may be == sizeof(int) + * sizeof(NonEmpty2); // must be > sizeof(int) + */ +#if FOLLY_HAS_CPP_ATTRIBUTE(no_unique_address) +#define FOLLY_ATTR_NO_UNIQUE_ADDRESS no_unique_address +#else +#define FOLLY_ATTR_NO_UNIQUE_ADDRESS +#endif + +#if FOLLY_HAS_CPP_ATTRIBUTE(clang::no_destroy) +#define FOLLY_ATTR_CLANG_NO_DESTROY clang::no_destroy +#else +#define FOLLY_ATTR_CLANG_NO_DESTROY +#endif + +#if FOLLY_HAS_CPP_ATTRIBUTE(clang::uninitialized) +#define FOLLY_ATTR_CLANG_UNINITIALIZED clang::uninitialized +#else +#define FOLLY_ATTR_CLANG_UNINITIALIZED +#endif + +/** + * Accesses to objects with types with this attribute are not subjected to + * type-based alias analysis, but are instead assumed to be able to alias any + * other type of objects, just like the char type. + */ +#if FOLLY_HAS_CPP_ATTRIBUTE(gnu::may_alias) +#define FOLLY_ATTR_GNU_MAY_ALIAS gnu::may_alias +#else +#define FOLLY_ATTR_GNU_MAY_ALIAS +#endif + +#if FOLLY_HAS_CPP_ATTRIBUTE(gnu::pure) +#define FOLLY_ATTR_GNU_PURE gnu::pure +#else +#define FOLLY_ATTR_GNU_PURE +#endif + +#if FOLLY_HAS_CPP_ATTRIBUTE(clang::preserve_most) +#define FOLLY_ATTR_CLANG_PRESERVE_MOST clang::preserve_most +#else +#define FOLLY_ATTR_CLANG_PRESERVE_MOST +#endif + +#if FOLLY_HAS_CPP_ATTRIBUTE(clang::preserve_all) +#define FOLLY_ATTR_CLANG_PRESERVE_ALL clang::preserve_all +#else +#define FOLLY_ATTR_CLANG_PRESERVE_ALL +#endif + +#if FOLLY_HAS_CPP_ATTRIBUTE(gnu::used) +#define FOLLY_ATTR_GNU_USED gnu::used +#else +#define FOLLY_ATTR_GNU_USED +#endif diff --git a/vnext/external/folly/folly/CpuId.h b/vnext/external/folly/folly/CpuId.h new file mode 100644 index 00000000000..1ddbe688126 --- /dev/null +++ b/vnext/external/folly/folly/CpuId.h @@ -0,0 +1,297 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#ifdef _MSC_VER +#include +#endif + +namespace folly { + +/** + * Identification of an Intel CPU. + * Supports CPUID feature flags (EAX=1) and extended features (EAX=7, ECX=0). + * Values from + * http://www.intel.com/content/www/us/en/processors/processor-identification-cpuid-instruction-note.html + */ +class CpuId { + public: + // Always inline in order for this to be usable from a __ifunc__. + // In shared library mode, a __ifunc__ runs at relocation time, while the + // PLT hasn't been fully populated yet; thus, ifuncs cannot use symbols + // with potentially external linkage. (This issue is less likely in opt + // mode since inlining happens more likely, and it doesn't happen for + // statically linked binaries which don't depend on the PLT) + FOLLY_ALWAYS_INLINE CpuId() { +#if defined(_MSC_VER) && (FOLLY_X64 || defined(_M_IX86)) +#if !defined(__clang__) + int reg[4]; + __cpuid(static_cast(reg), 0); + vendor_[0] = (uint32_t)reg[1]; + vendor_[1] = (uint32_t)reg[3]; + vendor_[2] = (uint32_t)reg[2]; + const int n = reg[0]; + if (n >= 1) { + __cpuid(static_cast(reg), 1); + f1c_ = uint32_t(reg[2]); + f1d_ = uint32_t(reg[3]); + } + if (n >= 7) { + __cpuidex(static_cast(reg), 7, 0); + f7b_ = uint32_t(reg[1]); + f7c_ = uint32_t(reg[2]); + f7d_ = uint32_t(reg[3]); + } +#else + // Clang compiler has a bug (fixed in https://reviews.llvm.org/D101338) in + // which the `__cpuid` intrinsic does not save and restore `rbx` as it needs + // to due to being a reserved register. So in that case, do the `cpuid` + // ourselves. Clang supports inline assembly anyway. + uint32_t n; + uint32_t v0b, v0d, v0c; + __asm__( + "pushq %%rbx\n\t" + "cpuid\n\t" + "movl %%ebx, %1\n\t" + "popq %%rbx\n\t" + : "=a"(n), "=r"(v0b), "=d"(v0d), "=c"(v0c) + : "a"(0)); + vendor_[0] = v0b; + vendor_[1] = v0d; + vendor_[2] = v0c; + if (n >= 1) { + uint32_t f1a; + __asm__( + "pushq %%rbx\n\t" + "cpuid\n\t" + "popq %%rbx\n\t" + : "=a"(f1a), "=c"(f1c_), "=d"(f1d_) + : "a"(1) + :); + } + if (n >= 7) { + __asm__( + "pushq %%rbx\n\t" + "cpuid\n\t" + "movq %%rbx, %%rax\n\t" + "popq %%rbx" + : "=a"(f7b_), "=c"(f7c_), "=d"(f7d_) + : "a"(7), "c"(0)); + } +#endif +#elif defined(__i386__) && defined(__PIC__) && !defined(__clang__) && \ + defined(__GNUC__) + // The following block like the normal cpuid branch below, but gcc + // reserves ebx for use of its pic register so we must specially + // handle the save and restore to avoid clobbering the register + uint32_t n; + uint32_t v0b, v0d, v0c; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %1\n\t" + "popl %%ebx\n\t" + : "=a"(n), "=r"(v0b), "=d"(v0d), "=c"(v0c) + : "a"(0)); + vendor_[0] = v0b; + vendor_[1] = v0d; + vendor_[2] = v0c; + if (n >= 1) { + uint32_t f1a; + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "popl %%ebx\n\t" + : "=a"(f1a), "=c"(f1c_), "=d"(f1d_) + : "a"(1) + :); + } + if (n >= 7) { + __asm__( + "pushl %%ebx\n\t" + "cpuid\n\t" + "movl %%ebx, %%eax\n\t" + "popl %%ebx" + : "=a"(f7b_), "=c"(f7c_), "=d"(f7d_) + : "a"(7), "c"(0)); + } +#elif FOLLY_X64 || defined(__i386__) + uint32_t n; + uint32_t v0b, v0d, v0c; + __asm__("cpuid" : "=a"(n), "=b"(v0b), "=d"(v0d), "=c"(v0c) : "a"(0)); + vendor_[0] = v0b; + vendor_[1] = v0d; + vendor_[2] = v0c; + if (n >= 1) { + uint32_t f1a; + __asm__("cpuid" : "=a"(f1a), "=c"(f1c_), "=d"(f1d_) : "a"(1) : "ebx"); + } + if (n >= 7) { + uint32_t f7a; + __asm__("cpuid" + : "=a"(f7a), "=b"(f7b_), "=c"(f7c_), "=d"(f7d_) + : "a"(7), "c"(0)); + } +#endif + } + +#define FOLLY_DETAIL_CPUID_X(name, r, bit) \ + FOLLY_ALWAYS_INLINE bool name() const { return ((r) & (1U << bit)) != 0; } + +// cpuid(1): Processor Info and Feature Bits. +#define FOLLY_DETAIL_CPUID_C(name, bit) FOLLY_DETAIL_CPUID_X(name, f1c_, bit) + FOLLY_DETAIL_CPUID_C(sse3, 0) + FOLLY_DETAIL_CPUID_C(pclmuldq, 1) + FOLLY_DETAIL_CPUID_C(dtes64, 2) + FOLLY_DETAIL_CPUID_C(monitor, 3) + FOLLY_DETAIL_CPUID_C(dscpl, 4) + FOLLY_DETAIL_CPUID_C(vmx, 5) + FOLLY_DETAIL_CPUID_C(smx, 6) + FOLLY_DETAIL_CPUID_C(eist, 7) + FOLLY_DETAIL_CPUID_C(tm2, 8) + FOLLY_DETAIL_CPUID_C(ssse3, 9) + FOLLY_DETAIL_CPUID_C(cnxtid, 10) + FOLLY_DETAIL_CPUID_C(fma, 12) + FOLLY_DETAIL_CPUID_C(cx16, 13) + FOLLY_DETAIL_CPUID_C(xtpr, 14) + FOLLY_DETAIL_CPUID_C(pdcm, 15) + FOLLY_DETAIL_CPUID_C(pcid, 17) + FOLLY_DETAIL_CPUID_C(dca, 18) + FOLLY_DETAIL_CPUID_C(sse41, 19) + FOLLY_DETAIL_CPUID_C(sse42, 20) + FOLLY_DETAIL_CPUID_C(x2apic, 21) + FOLLY_DETAIL_CPUID_C(movbe, 22) + FOLLY_DETAIL_CPUID_C(popcnt, 23) + FOLLY_DETAIL_CPUID_C(tscdeadline, 24) + FOLLY_DETAIL_CPUID_C(aes, 25) + FOLLY_DETAIL_CPUID_C(xsave, 26) + FOLLY_DETAIL_CPUID_C(osxsave, 27) + FOLLY_DETAIL_CPUID_C(avx, 28) + FOLLY_DETAIL_CPUID_C(f16c, 29) + FOLLY_DETAIL_CPUID_C(rdrand, 30) +#undef FOLLY_DETAIL_CPUID_C +#define FOLLY_DETAIL_CPUID_D(name, bit) FOLLY_DETAIL_CPUID_X(name, f1d_, bit) + FOLLY_DETAIL_CPUID_D(fpu, 0) + FOLLY_DETAIL_CPUID_D(vme, 1) + FOLLY_DETAIL_CPUID_D(de, 2) + FOLLY_DETAIL_CPUID_D(pse, 3) + FOLLY_DETAIL_CPUID_D(tsc, 4) + FOLLY_DETAIL_CPUID_D(msr, 5) + FOLLY_DETAIL_CPUID_D(pae, 6) + FOLLY_DETAIL_CPUID_D(mce, 7) + FOLLY_DETAIL_CPUID_D(cx8, 8) + FOLLY_DETAIL_CPUID_D(apic, 9) + FOLLY_DETAIL_CPUID_D(sep, 11) + FOLLY_DETAIL_CPUID_D(mtrr, 12) + FOLLY_DETAIL_CPUID_D(pge, 13) + FOLLY_DETAIL_CPUID_D(mca, 14) + FOLLY_DETAIL_CPUID_D(cmov, 15) + FOLLY_DETAIL_CPUID_D(pat, 16) + FOLLY_DETAIL_CPUID_D(pse36, 17) + FOLLY_DETAIL_CPUID_D(psn, 18) + FOLLY_DETAIL_CPUID_D(clfsh, 19) + FOLLY_DETAIL_CPUID_D(ds, 21) + FOLLY_DETAIL_CPUID_D(acpi, 22) + FOLLY_DETAIL_CPUID_D(mmx, 23) + FOLLY_DETAIL_CPUID_D(fxsr, 24) + FOLLY_DETAIL_CPUID_D(sse, 25) + FOLLY_DETAIL_CPUID_D(sse2, 26) + FOLLY_DETAIL_CPUID_D(ss, 27) + FOLLY_DETAIL_CPUID_D(htt, 28) + FOLLY_DETAIL_CPUID_D(tm, 29) + FOLLY_DETAIL_CPUID_D(pbe, 31) +#undef FOLLY_DETAIL_CPUID_D + + // cpuid(7): Extended Features. +#define FOLLY_DETAIL_CPUID_B(name, bit) FOLLY_DETAIL_CPUID_X(name, f7b_, bit) + FOLLY_DETAIL_CPUID_B(bmi1, 3) + FOLLY_DETAIL_CPUID_B(hle, 4) + FOLLY_DETAIL_CPUID_B(avx2, 5) + FOLLY_DETAIL_CPUID_B(smep, 7) + FOLLY_DETAIL_CPUID_B(bmi2, 8) + FOLLY_DETAIL_CPUID_B(erms, 9) + FOLLY_DETAIL_CPUID_B(invpcid, 10) + FOLLY_DETAIL_CPUID_B(rtm, 11) + FOLLY_DETAIL_CPUID_B(mpx, 14) + FOLLY_DETAIL_CPUID_B(avx512f, 16) + FOLLY_DETAIL_CPUID_B(avx512dq, 17) + FOLLY_DETAIL_CPUID_B(rdseed, 18) + FOLLY_DETAIL_CPUID_B(adx, 19) + FOLLY_DETAIL_CPUID_B(smap, 20) + FOLLY_DETAIL_CPUID_B(avx512ifma, 21) + FOLLY_DETAIL_CPUID_B(pcommit, 22) + FOLLY_DETAIL_CPUID_B(clflushopt, 23) + FOLLY_DETAIL_CPUID_B(clwb, 24) + FOLLY_DETAIL_CPUID_B(avx512pf, 26) + FOLLY_DETAIL_CPUID_B(avx512er, 27) + FOLLY_DETAIL_CPUID_B(avx512cd, 28) + FOLLY_DETAIL_CPUID_B(sha, 29) + FOLLY_DETAIL_CPUID_B(avx512bw, 30) + FOLLY_DETAIL_CPUID_B(avx512vl, 31) +#undef FOLLY_DETAIL_CPUID_B +#define FOLLY_DETAIL_CPUID_C(name, bit) FOLLY_DETAIL_CPUID_X(name, f7c_, bit) + FOLLY_DETAIL_CPUID_C(prefetchwt1, 0) + FOLLY_DETAIL_CPUID_C(avx512vbmi, 1) + FOLLY_DETAIL_CPUID_C(avx512vbmi2, 6) + FOLLY_DETAIL_CPUID_C(vaes, 9) + FOLLY_DETAIL_CPUID_C(vpclmulqdq, 10) + FOLLY_DETAIL_CPUID_C(avx512vnni, 11) + FOLLY_DETAIL_CPUID_C(avx512bitalg, 12) + FOLLY_DETAIL_CPUID_C(avx512vpopcntdq, 14) + FOLLY_DETAIL_CPUID_C(rdpid, 22) +#undef FOLLY_DETAIL_CPUID_C +#define FOLLY_DETAIL_CPUID_D(name, bit) FOLLY_DETAIL_CPUID_X(name, f7d_, bit) + FOLLY_DETAIL_CPUID_D(avx5124vnniw, 2) + FOLLY_DETAIL_CPUID_D(avx5124fmaps, 3) + FOLLY_DETAIL_CPUID_D(avx512vp2intersect, 8) + FOLLY_DETAIL_CPUID_D(amxbf16, 22) + FOLLY_DETAIL_CPUID_D(avx512fp16, 23) + FOLLY_DETAIL_CPUID_D(amxtile, 24) + FOLLY_DETAIL_CPUID_D(amxint8, 25) +#undef FOLLY_DETAIL_CPUID_D + +#undef FOLLY_DETAIL_CPUID_X + +#define FOLLY_DETAIL_VENDOR(name, str) \ + FOLLY_ALWAYS_INLINE bool vendor_##name() const { \ + /* Size of str should be 12 + NUL terminator. */ \ + static_assert(sizeof(str) == 13, "Bad CPU Vendor string"); \ + /* Just as with the main CpuId call above, this can also \ + still be in an __ifunc__, so no function calls :( */ \ + return memcmp(&vendor_[0], &str[0], 12) == 0; \ + } + + FOLLY_DETAIL_VENDOR(intel, "GenuineIntel") + FOLLY_DETAIL_VENDOR(amd, "AuthenticAMD") + +#undef FOLLY_DETAIL_VENDOR + + private: + uint32_t vendor_[3] = {0}; + uint32_t f1c_ = 0; + uint32_t f1d_ = 0; + uint32_t f7b_ = 0; + uint32_t f7c_ = 0; + uint32_t f7d_ = 0; +}; + +} // namespace folly diff --git a/vnext/external/folly/folly/DefaultKeepAliveExecutor.h b/vnext/external/folly/folly/DefaultKeepAliveExecutor.h new file mode 100644 index 00000000000..2073a6b7a1c --- /dev/null +++ b/vnext/external/folly/folly/DefaultKeepAliveExecutor.h @@ -0,0 +1,172 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include +#include +#include + +namespace folly { + +/// An Executor accepts units of work with add(), which should be +/// threadsafe. +class DefaultKeepAliveExecutor : public virtual Executor { + public: + virtual ~DefaultKeepAliveExecutor() override { DCHECK(!keepAlive_); } + + template + static auto getWeakRef(ExecutorT& executor) { + static_assert( + std::is_base_of::value, + "getWeakRef only works for folly::DefaultKeepAliveExecutor implementations."); + using WeakRefExecutorType = std::conditional_t< + std::is_base_of::value, + SequencedExecutor, + Executor>; + return WeakRef::create( + executor.controlBlock_, &executor); + } + + folly::Executor::KeepAlive<> weakRef() { return getWeakRef(*this); } + + protected: + void joinKeepAlive() { + DCHECK(keepAlive_); + keepAlive_.reset(); + keepAliveReleaseBaton_.wait(); + } + + void joinAndResetKeepAlive() { + joinKeepAlive(); + auto keepAliveCount = + controlBlock_->keepAliveCount_.exchange(1, std::memory_order_relaxed); + DCHECK_EQ(keepAliveCount, 0); + keepAliveReleaseBaton_.reset(); + keepAlive_ = makeKeepAlive(this); + } + + private: + struct ControlBlock { + std::atomic keepAliveCount_{1}; + }; + + template + class WeakRef : public ExecutorT { + public: + static folly::Executor::KeepAlive create( + std::shared_ptr controlBlock, ExecutorT* executor) { + return makeKeepAlive(new WeakRef(std::move(controlBlock), executor)); + } + + void add(Func f) override { + if (auto executor = lock()) { + executor->add(std::move(f)); + } + } + + void addWithPriority(Func f, int8_t priority) override { + if (auto executor = lock()) { + executor->addWithPriority(std::move(f), priority); + } + } + + virtual uint8_t getNumPriorities() const override { return numPriorities_; } + + private: + WeakRef(std::shared_ptr controlBlock, ExecutorT* executor) + : controlBlock_(std::move(controlBlock)), + executor_(executor), + numPriorities_(executor->getNumPriorities()) {} + + bool keepAliveAcquire() noexcept override { + auto keepAliveCount = + keepAliveCount_.fetch_add(1, std::memory_order_relaxed); + // We should never increment from 0 + DCHECK(keepAliveCount > 0); + return true; + } + + void keepAliveRelease() noexcept override { + auto keepAliveCount = + keepAliveCount_.fetch_sub(1, std::memory_order_acq_rel); + DCHECK(keepAliveCount >= 1); + + if (keepAliveCount == 1) { + delete this; + } + } + + folly::Executor::KeepAlive lock() { + auto controlBlock = + controlBlock_->keepAliveCount_.load(std::memory_order_relaxed); + do { + if (controlBlock == 0) { + return {}; + } + } while (!controlBlock_->keepAliveCount_.compare_exchange_weak( + controlBlock, + controlBlock + 1, + std::memory_order_release, + std::memory_order_relaxed)); + + return makeKeepAlive(executor_); + } + + std::atomic keepAliveCount_{1}; + + std::shared_ptr controlBlock_; + ExecutorT* executor_; + + uint8_t numPriorities_; + }; + + bool keepAliveAcquire() noexcept override { + auto keepAliveCount = + controlBlock_->keepAliveCount_.fetch_add(1, std::memory_order_relaxed); + // We should never increment from 0 + DCHECK(keepAliveCount > 0); + return true; + } + + void keepAliveRelease() noexcept override { + auto keepAliveCount = + controlBlock_->keepAliveCount_.fetch_sub(1, std::memory_order_acq_rel); + DCHECK(keepAliveCount >= 1); + + if (keepAliveCount == 1) { + keepAliveReleaseBaton_.post(); // std::memory_order_release + } + } + + std::shared_ptr controlBlock_{std::make_shared()}; + Baton<> keepAliveReleaseBaton_; + KeepAlive keepAlive_{makeKeepAlive(this)}; +}; + +template +auto getWeakRef(ExecutorT& executor) { + static_assert( + std::is_base_of::value, + "getWeakRef only works for folly::DefaultKeepAliveExecutor implementations."); + return DefaultKeepAliveExecutor::getWeakRef(executor); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/Demangle.cpp b/vnext/external/folly/folly/Demangle.cpp new file mode 100644 index 00000000000..d7234e0db06 --- /dev/null +++ b/vnext/external/folly/folly/Demangle.cpp @@ -0,0 +1,255 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include + +#if __has_include() +#include +#endif + +// The headers (binutils) and (glibc) both declare the +// symbol basename. Unfortunately, the declarations are different. So including +// both headers in the same translation unit fails due to the two conflicting +// declarations. Since includes we must be careful. +#if __has_include() +#pragma push_macro("HAVE_DECL_BASENAME") +#define HAVE_DECL_BASENAME 1 +#include // @manual +#pragma pop_macro("HAVE_DECL_BASENAME") +#endif + +// try to find cxxabi demangle +// +// prefer using a weakref + +#if __has_include() + +[[gnu::weakref("__cxa_demangle")]] static char* cxxabi_demangle( + char const*, char*, size_t*, int*); + +#else // __has_include() + +static constexpr auto cxxabi_demangle = static_cast(nullptr); + +#endif // __has_include() + +// try to find liberty demangle +// +// cannot use a weak symbol since it may be the only referenced symbol in +// liberty +// +// in contrast with cxxabi, where there are certainly other referenced symbols +// +// for rust_demangle_callback, detect its declaration in the header + +#if __has_include() + +namespace { +struct poison {}; + +[[maybe_unused]] FOLLY_ERASE void rust_demangle_callback(poison); + +[[maybe_unused]] FOLLY_ERASE int rust_demangle_callback_fallback( + const char*, int, demangle_callbackref, void*) { + return 0; +} + +FOLLY_CREATE_QUAL_INVOKER( + invoke_rust_demangle_primary, ::rust_demangle_callback); +FOLLY_CREATE_QUAL_INVOKER( + invoke_rust_demangle_fallback, rust_demangle_callback_fallback); + +using invoke_rust_demangle_fn = folly::invoke_first_match< + invoke_rust_demangle_primary, + invoke_rust_demangle_fallback>; +constexpr invoke_rust_demangle_fn invoke_rust_demangle; + +int call_rust_demangle_callback( + const char* mangled, int options, demangle_callbackref cb, void* opaque) { + return invoke_rust_demangle(mangled, options, cb, opaque); +} + +} // namespace + +using liberty_demangle_t = int(const char*, int, demangle_callbackref, void*); + +static constexpr liberty_demangle_t* liberty_cplus_demangle = + cplus_demangle_v3_callback; +static constexpr liberty_demangle_t* liberty_rust_demangle = + call_rust_demangle_callback; + +#if defined(DMGL_NO_RECURSE_LIMIT) +static constexpr auto liberty_demangle_options_no_recurse_limit = + DMGL_NO_RECURSE_LIMIT; +#else +static constexpr auto liberty_demangle_options_no_recurse_limit = 0; +#endif + +static constexpr auto liberty_demangle_options = // + DMGL_PARAMS | DMGL_ANSI | DMGL_TYPES | // + liberty_demangle_options_no_recurse_limit; + +#else // __has_include() + +using liberty_demangle_t = int(...); + +static constexpr liberty_demangle_t* liberty_cplus_demangle = nullptr; +static constexpr liberty_demangle_t* liberty_rust_demangle = nullptr; +static constexpr auto liberty_demangle_options = 0; + +#endif // __has_include() + +// implementations + +namespace folly { + +bool const demangle_build_has_cxxabi = cxxabi_demangle; +bool const demangle_build_has_liberty = // + to_bool(liberty_cplus_demangle) && // + to_bool(liberty_rust_demangle); + +namespace { +void demangleStringCallback(const char* str, size_t size, void* p) { + fbstring* demangle = static_cast(p); + + demangle->append(str, size); +} +} // namespace + +fbstring demangle(const char* name) { + if (!name) { + return fbstring(); + } + + if (demangle_max_symbol_size) { + // GCC's __cxa_demangle() uses on-stack data structures for the + // parser state which are linear in the number of components of the + // symbol. For extremely long symbols, this can cause a stack + // overflow. We set an arbitrary symbol length limit above which we + // just return the mangled name. + size_t mangledLen = strlen(name); + if (mangledLen > demangle_max_symbol_size) { + return fbstring(name, mangledLen); + } + } + + if (folly::demangle_build_has_liberty) { + liberty_demangle_t* funcs[] = { + liberty_rust_demangle, + liberty_cplus_demangle, + }; + + for (auto func : funcs) { + fbstring demangled; + + // Unlike most library functions, this returns 1 on success and 0 on + // failure + int success = func( + name, liberty_demangle_options, demangleStringCallback, &demangled); + if (success && !demangled.empty()) { + return demangled; + } + } + } + + if (cxxabi_demangle) { + int status; + size_t len = 0; + // malloc() memory for the demangled type name + char* demangled = cxxabi_demangle(name, nullptr, &len, &status); + if (status != 0) { + return name; + } + // len is the length of the buffer (including NUL terminator and maybe + // other junk) + return fbstring( + demangled, strlen(demangled), len, AcquireMallocatedString()); + } else { + return fbstring(name); + } +} + +namespace { + +struct DemangleBuf { + char* dest; + size_t remaining; + size_t total; +}; + +void demangleBufCallback(const char* str, size_t size, void* p) { + DemangleBuf* buf = static_cast(p); + size_t n = std::min(buf->remaining, size); + memcpy(buf->dest, str, n); + buf->dest += n; + buf->remaining -= n; + buf->total += size; +} + +} // namespace + +size_t demangle(const char* name, char* out, size_t outSize) { + if (demangle_max_symbol_size) { + size_t mangledLen = strlen(name); + if (mangledLen > demangle_max_symbol_size) { + if (outSize) { + size_t n = std::min(mangledLen, outSize - 1); + memcpy(out, name, n); + out[n] = '\0'; + } + return mangledLen; + } + } + + if (folly::demangle_build_has_liberty) { + liberty_demangle_t* funcs[] = { + liberty_rust_demangle, + liberty_cplus_demangle, + }; + + for (auto func : funcs) { + DemangleBuf dbuf; + dbuf.dest = out; + dbuf.remaining = outSize ? outSize - 1 : 0; // leave room for null term + dbuf.total = 0; + + // Unlike most library functions, this returns 1 on success and 0 on + // failure + int success = + func(name, liberty_demangle_options, demangleBufCallback, &dbuf); + if (success) { + if (outSize != 0) { + *dbuf.dest = '\0'; + } + return dbuf.total; + } + } + } + + // fallback - just return original + return folly::strlcpy(out, name, outSize); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/Demangle.h b/vnext/external/folly/folly/Demangle.h new file mode 100644 index 00000000000..1cace13f472 --- /dev/null +++ b/vnext/external/folly/folly/Demangle.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace folly { + +inline constexpr size_t demangle_max_symbol_size = +#if defined(FOLLY_DEMANGLE_MAX_SYMBOL_SIZE) + FOLLY_DEMANGLE_MAX_SYMBOL_SIZE; +#else + 0; +#endif + +extern bool const demangle_build_has_cxxabi; +extern bool const demangle_build_has_liberty; + +/** + * Return the demangled (prettified) version of a C++ type. + * + * This function tries to produce a human-readable type, but the type name will + * be returned unchanged in case of error or if demangling isn't supported on + * your system. + * + * Use for debugging -- do not rely on demangle() returning anything useful. + * + * This function may allocate memory (and therefore throw std::bad_alloc). + */ +fbstring demangle(const char* name); +inline fbstring demangle(const std::type_info& type) { + return demangle(type.name()); +} + +/** + * Return the demangled (prettified) version of a C++ type in a user-provided + * buffer. + * + * The semantics are the same as for snprintf or strlcpy: bufSize is the size + * of the buffer, the string is always null-terminated, and the return value is + * the number of characters (not including the null terminator) that would have + * been written if the buffer was big enough. (So a return value >= bufSize + * indicates that the output was truncated) + * + * This function does not allocate memory and is async-signal-safe. + * + * Note that the underlying function for the fbstring-returning demangle is + * somewhat standard (abi::__cxa_demangle, which uses malloc), the underlying + * function for this version is less so (cplus_demangle_v3_callback from + * libiberty), so it is possible for the fbstring version to work, while this + * version returns the original, mangled name. + */ +size_t demangle(const char* name, char* out, size_t outSize); +inline size_t demangle(const std::type_info& type, char* buf, size_t bufSize) { + return demangle(type.name(), buf, bufSize); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/DiscriminatedPtr.h b/vnext/external/folly/folly/DiscriminatedPtr.h new file mode 100644 index 00000000000..be8a9d52346 --- /dev/null +++ b/vnext/external/folly/folly/DiscriminatedPtr.h @@ -0,0 +1,236 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Discriminated pointer: Type-safe pointer to one of several types. + * + * Similar to std::variant, but has no space overhead over a raw pointer, as + * it relies on the fact that (on x86_64) there are 16 unused bits in a + * pointer. + */ + +#pragma once + +#include +#include + +#include + +#include +#include +#include + +#if !FOLLY_X64 && !FOLLY_AARCH64 && !FOLLY_PPC64 && !FOLLY_RISCV64 +#error "DiscriminatedPtr is x64, arm64, ppc64 and riscv64 specific code." +#endif + +namespace folly { + +/** + * Discriminated pointer. + * + * Given a list of types, a DiscriminatedPtr may point to an object + * of one of the given types, or may be empty. DiscriminatedPtr is type-safe: + * you may only get a pointer to the type that you put in, otherwise get + * throws an exception (and get_nothrow returns nullptr) + * + * This pointer does not do any kind of lifetime management -- it's not a + * "smart" pointer. You are responsible for deallocating any memory used + * to hold pointees, if necessary. + */ +template +class DiscriminatedPtr { + // <, not <=, as our indexes are 1-based (0 means "empty") + static_assert( + sizeof...(Types) < std::numeric_limits::max(), + "too many types"); + + public: + /** + * Create an empty DiscriminatedPtr. + */ + DiscriminatedPtr() : data_(0) {} + + /** + * Create a DiscriminatedPtr that points to an object of type T. + * Fails at compile time if T is not a valid type (listed in Types) + */ + template + explicit DiscriminatedPtr(T* ptr) { + set(ptr, typeIndex()); + } + + /** + * Set this DiscriminatedPtr to point to an object of type T. + * Fails at compile time if T is not a valid type (listed in Types) + */ + template + void set(T* ptr) { + set(ptr, typeIndex()); + } + + /** + * Get a pointer to the object that this DiscriminatedPtr points to, if it is + * of type T. Fails at compile time if T is not a valid type (listed in + * Types), and returns nullptr if this DiscriminatedPtr is empty or points to + * an object of a different type. + */ + template + T* get_nothrow() noexcept { + void* p = FOLLY_LIKELY(hasType()) ? ptr() : nullptr; + return static_cast(p); + } + + template + const T* get_nothrow() const noexcept { + const void* p = FOLLY_LIKELY(hasType()) ? ptr() : nullptr; + return static_cast(p); + } + + /** + * Get a pointer to the object that this DiscriminatedPtr points to, if it is + * of type T. Fails at compile time if T is not a valid type (listed in + * Types), and throws std::invalid_argument if this DiscriminatedPtr is empty + * or points to an object of a different type. + */ + template + T* get() { + if (FOLLY_UNLIKELY(!hasType())) { + throw std::invalid_argument("Invalid type"); + } + return static_cast(ptr()); + } + + template + const T* get() const { + if (FOLLY_UNLIKELY(!hasType())) { + throw std::invalid_argument("Invalid type"); + } + return static_cast(ptr()); + } + + /** + * Return true iff this DiscriminatedPtr is empty. + */ + bool empty() const { return index() == 0; } + + /** + * Return true iff the object pointed by this DiscriminatedPtr has type T, + * false otherwise. Fails at compile time if T is not a valid type (listed + * in Types...) + */ + template + bool hasType() const { + return index() == typeIndex(); + } + + /** + * Clear this DiscriminatedPtr, making it empty. + */ + void clear() { data_ = 0; } + + /** + * Assignment operator from a pointer of type T. + */ + template + DiscriminatedPtr& operator=(T* ptr) { + set(ptr); + return *this; + } + + /** + * Apply a visitor to this object, calling the appropriate overload for + * the type currently stored in DiscriminatedPtr. Throws invalid_argument + * if the DiscriminatedPtr is empty. + * + * The visitor must meet the following requirements: + * + * - The visitor must allow invocation as a function by overloading + * operator(), unambiguously accepting all values of type T* (or const T*) + * for all T in Types... + * - All operations of the function object on T* (or const T*) must + * return the same type (or a static_assert will fire). + */ + template + typename dptr_detail::VisitorResult::type apply(V&& visitor) { + size_t n = index(); + if (n == 0) { + throw std::invalid_argument("Empty DiscriminatedPtr"); + } + return dptr_detail::ApplyVisitor()( + n, std::forward(visitor), ptr()); + } + + template + typename dptr_detail::ConstVisitorResult::type apply( + V&& visitor) const { + size_t n = index(); + if (n == 0) { + throw std::invalid_argument("Empty DiscriminatedPtr"); + } + return dptr_detail::ApplyConstVisitor()( + n, std::forward(visitor), ptr()); + } + + private: + /** + * Get the 1-based type index of T in Types. + */ + template + uint16_t typeIndex() const { + return uint16_t(dptr_detail::GetTypeIndex::value); + } + + uint16_t index() const { return data_ >> 48; } + void* ptr() const { + return reinterpret_cast(data_ & ((1ULL << 48) - 1)); + } + + void set(void* p, uint16_t v) { + uintptr_t ip = reinterpret_cast(p); + CHECK(!(ip >> 48)); + ip |= static_cast(v) << 48; + data_ = ip; + } + + /** + * We store a pointer in the least significant 48 bits of data_, and a type + * index (0 = empty, or 1-based index in Types) in the most significant 16 + * bits. We rely on the fact that pointers have their most significant 16 + * bits clear on x86_64. + */ + uintptr_t data_; +}; + +template +decltype(auto) apply_visitor( + Visitor&& visitor, const DiscriminatedPtr& variant) { + return variant.apply(std::forward(visitor)); +} + +template +decltype(auto) apply_visitor( + Visitor&& visitor, DiscriminatedPtr& variant) { + return variant.apply(std::forward(visitor)); +} + +template +decltype(auto) apply_visitor( + Visitor&& visitor, DiscriminatedPtr&& variant) { + return variant.apply(std::forward(visitor)); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/DynamicConverter.h b/vnext/external/folly/folly/DynamicConverter.h new file mode 100644 index 00000000000..7bbf20dad5f --- /dev/null +++ b/vnext/external/folly/folly/DynamicConverter.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include diff --git a/vnext/external/folly/folly/Exception.h b/vnext/external/folly/folly/Exception.h new file mode 100644 index 00000000000..1cf79e3516e --- /dev/null +++ b/vnext/external/folly/folly/Exception.h @@ -0,0 +1,150 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace folly { + +// Various helpers to throw appropriate std::system_error exceptions from C +// library errors (returned in errno, as positive return values (many POSIX +// functions), or as negative return values (Linux syscalls)) +// +// The *Explicit functions take an explicit value for errno. + +// On linux and similar platforms the value of `errno` is a mixture of +// POSIX-`errno`-domain error codes and per-OS extended error codes. So the +// most appropriate category to use is `system_category`. +// +// On Windows `system_category` means codes that can be returned by Win32 API +// `GetLastError` and codes from the `errno`-domain must be reported as +// `generic_category`. +inline const std::error_category& errorCategoryForErrnoDomain() noexcept { + if (kIsWindows) { + return std::generic_category(); + } + return std::system_category(); +} + +inline std::system_error makeSystemErrorExplicit(int err, const char* msg) { + return std::system_error(err, errorCategoryForErrnoDomain(), msg); +} + +template +std::system_error makeSystemErrorExplicit(int err, Args&&... args) { + return makeSystemErrorExplicit( + err, to(std::forward(args)...).c_str()); +} + +inline std::system_error makeSystemError(const char* msg) { + return makeSystemErrorExplicit(errno, msg); +} + +template +std::system_error makeSystemError(Args&&... args) { + return makeSystemErrorExplicit(errno, std::forward(args)...); +} + +// Helper to throw std::system_error +[[noreturn]] inline void throwSystemErrorExplicit(int err, const char* msg) { + throw_exception(makeSystemErrorExplicit(err, msg)); +} + +template +[[noreturn]] void throwSystemErrorExplicit(int err, Args&&... args) { + throw_exception(makeSystemErrorExplicit(err, std::forward(args)...)); +} + +// Helper to throw std::system_error from errno and components of a string +template +[[noreturn]] void throwSystemError(Args&&... args) { + throwSystemErrorExplicit(errno, std::forward(args)...); +} + +// Check a Posix return code (0 on success, error number on error), throw +// on error. +template +void checkPosixError(int err, Args&&... args) { + if (FOLLY_UNLIKELY(err != 0)) { + throwSystemErrorExplicit(err, std::forward(args)...); + } +} + +// Check a Linux kernel-style return code (>= 0 on success, negative error +// number on error), throw on error. +template +void checkKernelError(ssize_t ret, Args&&... args) { + if (FOLLY_UNLIKELY(ret < 0)) { + throwSystemErrorExplicit(int(-ret), std::forward(args)...); + } +} + +// Check a traditional Unix return code (-1 and sets errno on error), throw +// on error. +template +void checkUnixError(ssize_t ret, Args&&... args) { + if (FOLLY_UNLIKELY(ret == -1)) { + throwSystemError(std::forward(args)...); + } +} + +template +void checkUnixErrorExplicit(ssize_t ret, int savedErrno, Args&&... args) { + if (FOLLY_UNLIKELY(ret == -1)) { + throwSystemErrorExplicit(savedErrno, std::forward(args)...); + } +} + +// Check the return code from a fopen-style function (returns a non-nullptr +// FILE* on success, nullptr on error, sets errno). Works with fopen, fdopen, +// freopen, tmpfile, etc. +template +void checkFopenError(FILE* fp, Args&&... args) { + if (FOLLY_UNLIKELY(!fp)) { + throwSystemError(std::forward(args)...); + } +} + +template +void checkFopenErrorExplicit(FILE* fp, int savedErrno, Args&&... args) { + if (FOLLY_UNLIKELY(!fp)) { + throwSystemErrorExplicit(savedErrno, std::forward(args)...); + } +} + +/** + * If cond is not true, raise an exception of type E. E must have a ctor that + * works with const char* (a description of the failure). + */ +#define CHECK_THROW(cond, E) \ + do { \ + if (!(cond)) { \ + folly::throw_exception("Check failed: " #cond); \ + } \ + } while (0) + +} // namespace folly diff --git a/vnext/external/folly/folly/ExceptionString.cpp b/vnext/external/folly/folly/ExceptionString.cpp new file mode 100644 index 00000000000..75696f23f8f --- /dev/null +++ b/vnext/external/folly/folly/ExceptionString.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include +#include +#include + +namespace folly { + +namespace { + +fbstring exception_string_type(std::type_info const* ti) { + return ti ? demangle(*ti) : ""; +} + +} // namespace + +/** + * Debug string for an exception: include type and what(), if + * defined. + */ +fbstring exceptionStr(std::exception const& e) { + auto prefix = exception_string_type(folly::type_info_of(e)); + return std::move(prefix) + ": " + e.what(); +} + +fbstring exceptionStr(std::exception_ptr const& ep) { + if (auto ex = exception_ptr_get_object(ep)) { + return exceptionStr(*ex); + } + return exception_string_type(exception_ptr_get_type(ep)); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/ExceptionString.h b/vnext/external/folly/folly/ExceptionString.h new file mode 100644 index 00000000000..56fcbe7e70a --- /dev/null +++ b/vnext/external/folly/folly/ExceptionString.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +namespace folly { + +/** + * Debug string for an exception: include type and what(), if + * defined. + */ +fbstring exceptionStr(std::exception const& e); + +fbstring exceptionStr(std::exception_ptr const& ep); + +} // namespace folly diff --git a/vnext/external/folly/folly/ExceptionWrapper-inl.h b/vnext/external/folly/folly/ExceptionWrapper-inl.h new file mode 100644 index 00000000000..f73cbfa5c98 --- /dev/null +++ b/vnext/external/folly/folly/ExceptionWrapper-inl.h @@ -0,0 +1,264 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace folly { + +struct exception_wrapper::with_exception_from_fn_ { + struct impl_var_ { + template + using apply = void; + }; + struct impl_arg_ { + template + using apply = typename function_traits::template argument<0>; + }; + struct impl_bye_; + template < + typename Sig, + typename Traits = function_traits, + std::size_t NArgs = Traits::template arguments::value> + using impl_ = conditional_t< + Traits::is_variadic, + impl_var_, + conditional_t>; + + template + using member_ = typename member_pointer_traits::member_type; + + template + struct arg_type_; + template + struct arg_type_::value>, Sig> { + using type = typename impl_::template apply; + }; + template + struct arg_type_::value>, Ptr> + : arg_type_> {}; + template + struct arg_type_, Obj> + : arg_type_> {}; + + // void if Fn is a variadic callable; otherwise the first arg type + template + using apply = _t>; +}; + +struct exception_wrapper::with_exception_from_ex_ { + template + using apply = Ex; +}; + +// The libc++ and cpplib implementations do not have a move constructor or a +// move-assignment operator. To avoid refcount operations, we must improvise. +// The libstdc++ implementation has a move constructor and a move-assignment +// operator but having this does no harm. +inline std::exception_ptr exception_wrapper::extract_( + std::exception_ptr&& ptr) noexcept { + constexpr auto sz = sizeof(std::exception_ptr); + // assume relocatability on all platforms + // assume nrvo for performance + std::exception_ptr ret; + std::memcpy(static_cast(&ret), &ptr, sz); + std::memset(static_cast(&ptr), 0, sz); + return ret; +} + +inline exception_wrapper::exception_wrapper(exception_wrapper&& that) noexcept + : ptr_{extract_(std::move(that.ptr_))} {} + +inline exception_wrapper::exception_wrapper( + std::exception_ptr const& ptr) noexcept + : ptr_{ptr} {} + +inline exception_wrapper::exception_wrapper(std::exception_ptr&& ptr) noexcept + : ptr_{extract_(std::move(ptr))} {} + +template < + class Ex, + class Ex_, + FOLLY_REQUIRES_DEF(Conjunction< + exception_wrapper::IsStdException, + exception_wrapper::IsRegularExceptionType>::value)> +inline exception_wrapper::exception_wrapper(Ex&& ex) + : ptr_{make_exception_ptr_with(std::in_place, std::forward(ex))} {} + +template < + class Ex, + class Ex_, + FOLLY_REQUIRES_DEF(exception_wrapper::IsRegularExceptionType::value)> +inline exception_wrapper::exception_wrapper(std::in_place_t, Ex&& ex) + : ptr_{make_exception_ptr_with(std::in_place, std::forward(ex))} {} + +template < + class Ex, + typename... As, + FOLLY_REQUIRES_DEF(exception_wrapper::IsRegularExceptionType::value)> +inline exception_wrapper::exception_wrapper( + std::in_place_type_t, As&&... as) + : ptr_{make_exception_ptr_with( + std::in_place_type, std::forward(as)...)} {} + +inline exception_wrapper& exception_wrapper::operator=( + exception_wrapper&& that) noexcept { + // assume relocatability on all platforms + constexpr auto sz = sizeof(std::exception_ptr); + std::exception_ptr tmp; + std::memcpy(static_cast(&tmp), &ptr_, sz); + std::memcpy(static_cast(&ptr_), &that.ptr_, sz); + std::memset(static_cast(&that.ptr_), 0, sz); + return *this; +} + +inline void exception_wrapper::swap(exception_wrapper& that) noexcept { + // assume relocatability on all platforms + constexpr auto sz = sizeof(std::exception_ptr); + aligned_storage_for_t storage; + std::memcpy(&storage, &ptr_, sz); + std::memcpy(static_cast(&ptr_), &that.ptr_, sz); + std::memcpy(static_cast(&that.ptr_), &storage, sz); +} + +inline exception_wrapper::operator bool() const noexcept { + return !!ptr_; +} + +inline bool exception_wrapper::operator!() const noexcept { + return !ptr_; +} + +inline void exception_wrapper::reset() { + ptr_ = {}; +} + +inline bool exception_wrapper::has_exception_ptr() const noexcept { + return !!ptr_; +} + +inline std::exception* exception_wrapper::get_exception() noexcept { + return exception_ptr_get_object(ptr_); +} +inline std::exception const* exception_wrapper::get_exception() const noexcept { + return exception_ptr_get_object(ptr_); +} + +template +inline Ex* exception_wrapper::get_exception() noexcept { + return exception_ptr_get_object_hint(ptr_, tag); +} + +template +inline Ex const* exception_wrapper::get_exception() const noexcept { + return exception_ptr_get_object_hint(ptr_, tag); +} + +inline std::exception_ptr exception_wrapper::to_exception_ptr() const noexcept { + return ptr_; +} + +inline std::exception_ptr const& exception_wrapper::exception_ptr_ref() + const noexcept { + return ptr_; +} + +inline std::type_info const* exception_wrapper::type() const noexcept { + return exception_ptr_get_type(ptr_); +} + +inline folly::fbstring exception_wrapper::what() const { + if (auto e = get_exception()) { + return class_name() + ": " + e->what(); + } + return class_name(); +} + +inline folly::fbstring exception_wrapper::class_name() const { + auto const* const ti = type(); + return !*this ? "" : !ti ? "" : folly::demangle(*ti); +} + +template +inline bool exception_wrapper::is_compatible_with() const noexcept { + return exception_ptr_get_object(ptr_); +} + +[[noreturn]] inline void exception_wrapper::throw_exception() const { + ptr_ ? std::rethrow_exception(ptr_) : onNoExceptionError(__func__); +} + +template +[[noreturn]] inline void exception_wrapper::throw_with_nested(Ex&& ex) const { + try { + throw_exception(); + } catch (...) { + std::throw_with_nested(std::forward(ex)); + } +} + +template +inline bool exception_wrapper::with_exception_(This&, Fn fn_, tag_t) { + return void(fn_()), true; +} + +template +inline bool exception_wrapper::with_exception_(This& this_, Fn fn_, tag_t) { + auto ptr = this_.template get_exception>(); + return ptr && (void(fn_(static_cast(*ptr))), true); +} + +template +inline bool exception_wrapper::with_exception_(This& this_, Fn fn_) { + using from_fn = with_exception_from_fn_; + using from_ex = with_exception_from_ex_; + using from = conditional_t::value, from_fn, from_ex>; + using type = typename from::template apply; + return with_exception_(this_, std::move(fn_), tag); +} + +template +inline void exception_wrapper::handle_( + This& this_, char const* name, CatchFns&... fns) { + using _ = bool[]; + if (!this_) { + onNoExceptionError(name); + } + bool handled = false; + void(_{false, (handled = handled || with_exception_(this_, fns))...}); + if (!handled) { + this_.throw_exception(); + } +} + +template +inline bool exception_wrapper::with_exception(Fn fn) { + return with_exception_(*this, std::move(fn)); +} +template +inline bool exception_wrapper::with_exception(Fn fn) const { + return with_exception_(*this, std::move(fn)); +} + +template +inline void exception_wrapper::handle(CatchFns... fns) { + handle_(*this, __func__, fns...); +} +template +inline void exception_wrapper::handle(CatchFns... fns) const { + handle_(*this, __func__, fns...); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/ExceptionWrapper.cpp b/vnext/external/folly/folly/ExceptionWrapper.cpp new file mode 100644 index 00000000000..df1e49fb423 --- /dev/null +++ b/vnext/external/folly/folly/ExceptionWrapper.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +namespace folly { + +[[noreturn]] void exception_wrapper::onNoExceptionError( + char const* const name) { + std::ios_base::Init ioinit_; // ensure std::cerr is alive + std::cerr << "Cannot use `" << name + << "` with an empty folly::exception_wrapper" << std::endl; + std::terminate(); +} + +fbstring exceptionStr(exception_wrapper const& ew) { + return ew.what(); +} + +} // namespace folly diff --git a/vnext/external/folly/folly/ExceptionWrapper.h b/vnext/external/folly/folly/ExceptionWrapper.h new file mode 100644 index 00000000000..56e37b919b8 --- /dev/null +++ b/vnext/external/folly/folly/ExceptionWrapper.h @@ -0,0 +1,377 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace folly { + +#define FOLLY_REQUIRES_DEF(...) \ + std::enable_if_t(__VA_ARGS__), long> + +#define FOLLY_REQUIRES(...) FOLLY_REQUIRES_DEF(__VA_ARGS__) = __LINE__ + +//! Throwing exceptions can be a convenient way to handle errors. Storing +//! exceptions in an `exception_ptr` makes it easy to handle exceptions in a +//! different thread or at a later time. `exception_ptr` can also be used in a +//! very generic result/exception wrapper. +//! +//! However, inspecting exceptions through the `exception_ptr` interface, namely +//! through `rethrow_exception`, is expensive. This is a wrapper interface which +//! offers faster inspection. +//! +//! \par Example usage: +//! \code +//! exception_wrapper globalExceptionWrapper; +//! +//! // Thread1 +//! void doSomethingCrazy() { +//! int rc = doSomethingCrazyWithLameReturnCodes(); +//! if (rc == NAILED_IT) { +//! globalExceptionWrapper = exception_wrapper(); +//! } else if (rc == FACE_PLANT) { +//! globalExceptionWrapper = make_exception_wrapper(); +//! } else if (rc == FAIL_WHALE) { +//! globalExceptionWrapper = make_exception_wrapper(); +//! } +//! } +//! +//! // Thread2: Exceptions are ok! +//! void processResult() { +//! try { +//! globalExceptionWrapper.throw_exception(); +//! } catch (const FacePlantException& e) { +//! LOG(ERROR) << "FACEPLANT!"; +//! } catch (const FailWhaleException& e) { +//! LOG(ERROR) << "FAILWHALE!"; +//! } +//! } +//! +//! // Thread2: Exceptions are bad! +//! void processResult() { +//! globalExceptionWrapper.handle( +//! [&](FacePlantException& faceplant) { +//! LOG(ERROR) << "FACEPLANT"; +//! }, +//! [&](FailWhaleException& failwhale) { +//! LOG(ERROR) << "FAILWHALE!"; +//! }, +//! [](...) { +//! LOG(FATAL) << "Unrecognized exception"; +//! }); +//! } +//! \endcode +class exception_wrapper final { + private: + struct with_exception_from_fn_; + struct with_exception_from_ex_; + + [[noreturn]] static void onNoExceptionError(char const* name); + + template + using IsStdException = std::is_base_of>; + + std::exception_ptr ptr_; + + template + struct IsRegularExceptionType + : StrictConjunction< + std::is_copy_constructible, + Negation>, + Negation>> {}; + + template + static bool with_exception_(This& this_, Fn fn_, tag_t); + + template + static bool with_exception_(This& this_, Fn fn_, tag_t); + + template + static bool with_exception_(This& this_, Fn fn_); + + template + static void handle_(This& this_, char const* name, CatchFns&... fns); + + static std::exception_ptr extract_(std::exception_ptr&&) noexcept; + + public: + //! Default-constructs an empty `exception_wrapper` + //! \post `type() == nullptr` + exception_wrapper() noexcept {} + + //! Move-constructs an `exception_wrapper` + //! \post `*this` contains the value of `that` prior to the move + //! \post `that.type() == nullptr` + exception_wrapper(exception_wrapper&& that) noexcept; + + //! Copy-constructs an `exception_wrapper` + //! \post `*this` contains a copy of `that`, and `that` is unmodified + //! \post `type() == that.type()` + exception_wrapper(exception_wrapper const& that) = default; + + //! Move-assigns an `exception_wrapper` + //! \pre `this != &that` + //! \post `*this` contains the value of `that` prior to the move + //! \post `that.type() == nullptr` + exception_wrapper& operator=(exception_wrapper&& that) noexcept; + + //! Copy-assigns an `exception_wrapper` + //! \post `*this` contains a copy of `that`, and `that` is unmodified + //! \post `type() == that.type()` + exception_wrapper& operator=(exception_wrapper const& that) = default; + + //! \post `!ptr || bool(*this)` + explicit exception_wrapper(std::exception_ptr const& ptr) noexcept; + explicit exception_wrapper(std::exception_ptr&& ptr) noexcept; + + //! \pre `typeid(ex) == typeid(typename decay::type)` + //! \post `bool(*this)` + //! \post `type() == &typeid(ex)` + //! \note Exceptions of types derived from `std::exception` can be implicitly + //! converted to an `exception_wrapper`. + template < + class Ex, + class Ex_ = std::decay_t, + FOLLY_REQUIRES( + Conjunction, IsRegularExceptionType>::value)> + /* implicit */ exception_wrapper(Ex&& ex); + + //! \pre `typeid(ex) == typeid(typename decay::type)` + //! \post `bool(*this)` + //! \post `type() == &typeid(ex)` + //! \note Exceptions of types not derived from `std::exception` can still be + //! used to construct an `exception_wrapper`, but you must specify + //! `std::in_place` as the first parameter. + template < + class Ex, + class Ex_ = std::decay_t, + FOLLY_REQUIRES(IsRegularExceptionType::value)> + exception_wrapper(std::in_place_t, Ex&& ex); + + template < + class Ex, + typename... As, + FOLLY_REQUIRES(IsRegularExceptionType::value)> + exception_wrapper(std::in_place_type_t, As&&... as); + + //! Swaps the value of `*this` with the value of `that` + void swap(exception_wrapper& that) noexcept; + + //! \return `true` if `*this` is holding an exception. + explicit operator bool() const noexcept; + + //! \return `!bool(*this)` + bool operator!() const noexcept; + + //! Make this `exception_wrapper` empty + //! \post `!*this` + void reset(); + + //! \return `true` if this `exception_wrapper` holds an exception. + bool has_exception_ptr() const noexcept; + + //! \return a pointer to the `std::exception` held by `*this`, if it holds + //! one; otherwise, returns `nullptr`. + std::exception* get_exception() noexcept; + //! \overload + std::exception const* get_exception() const noexcept; + + //! \returns a pointer to the `Ex` held by `*this`, if it holds an object + //! whose type `From` permits `std::is_convertible`; + //! otherwise, returns `nullptr`. + template + Ex* get_exception() noexcept; + //! \overload + template + Ex const* get_exception() const noexcept; + + //! \return A `std::exception_ptr` that references the exception held by + //! `*this`. + std::exception_ptr to_exception_ptr() const noexcept; + std::exception_ptr const& exception_ptr_ref() const noexcept; + + //! Returns the `typeid` of the wrapped exception object. If there is no + //! wrapped exception object, returns `nullptr`. + std::type_info const* type() const noexcept; + + //! \return If `get_exception() != nullptr`, `class_name() + ": " + + //! get_exception()->what()`; otherwise, `class_name()`. + folly::fbstring what() const; + + //! \return If `!*this`, the empty string; otherwise, if `!type()`, text that + //! is not a class name; otherwise, the demangling of `type()->name()`. + folly::fbstring class_name() const; + + //! \tparam Ex The expression type to check for compatibility with. + //! \return `true` if and only if `*this` wraps an exception that would be + //! caught with a `catch(Ex const&)` clause. + //! \note If `*this` is empty, this function returns `false`. + template + bool is_compatible_with() const noexcept; + + //! Throws the wrapped expression. + //! \pre `bool(*this)` + [[noreturn]] void throw_exception() const; + + //! Terminates the process with the wrapped expression. + [[noreturn]] void terminate_with() const noexcept { throw_exception(); } + + //! Throws the wrapped expression nested into another exception. + //! \pre `bool(*this)` + //! \param ex Exception in *this will be thrown nested into ex; + // see std::throw_with_nested() for details on this semantic. + template + [[noreturn]] void throw_with_nested(Ex&& ex) const; + + //! Call `fn` with the wrapped exception (if any), if `fn` can accept it. + //! \par Example + //! \code + //! exception_wrapper ew{std::runtime_error("goodbye cruel world")}; + //! + //! assert( ew.with_exception([](std::runtime_error& e){/*...*/}) ); + //! + //! assert( !ew.with_exception([](int& e){/*...*/}) ); + //! + //! assert( !exception_wrapper{}.with_exception([](int& e){/*...*/}) ); + //! \endcode + //! \tparam Ex Optionally, the type of the exception that `fn` accepts. + //! \tparam Fn The type of a monomophic function object. + //! \param fn A function object to call with the wrapped exception + //! \return `true` if and only if `fn` was called. + //! \note Optionally, you may explicitly specify the type of the exception + //! that `fn` expects, as in + //! \code + //! ew.with_exception([](auto&& e) { /*...*/; }); + //! \endcode + //! \note The handler is not invoked with an active exception. + //! **Do not try to rethrow the exception with `throw;` from within your + //! handler -- that is, a throw expression with no operand.** This may + //! cause your process to terminate. (It is perfectly ok to throw from + //! a handler so long as you specify the exception to throw, as in + //! `throw e;`.) + template + bool with_exception(Fn fn); + //! \overload + template + bool with_exception(Fn fn) const; + + //! Handle the wrapped expression as if with a series of `catch` clauses, + //! propagating the exception if no handler matches. + //! \par Example + //! \code + //! exception_wrapper ew{std::runtime_error("goodbye cruel world")}; + //! + //! ew.handle( + //! [&](std::logic_error const& e) { + //! LOG(DFATAL) << "ruh roh"; + //! ew.throw_exception(); // rethrow the active exception without + //! // slicing it. Will not be caught by other + //! // handlers in this call. + //! }, + //! [&](std::exception const& e) { + //! LOG(ERROR) << ew.what(); + //! }); + //! \endcode + //! In the above example, any exception _not_ derived from `std::exception` + //! will be propagated. To specify a catch-all clause, pass a lambda that + //! takes a C-style ellipses, as in: + //! \code + //! ew.handle(/*...* /, [](...) { /* handle unknown exception */ } ) + //! \endcode + //! \pre `!*this` + //! \tparam CatchFns A pack of unary monomorphic function object types. + //! \param fns A pack of unary monomorphic function objects to be treated as + //! an ordered list of potential exception handlers. + //! \note The handlers are not invoked with an active exception. + //! **Do not try to rethrow the exception with `throw;` from within your + //! handler -- that is, a throw expression with no operand.** This may + //! cause your process to terminate. (It is perfectly ok to throw from + //! a handler so long as you specify the exception to throw, as in + //! `throw e;`.) + template + void handle(CatchFns... fns); + //! \overload + template + void handle(CatchFns... fns) const; +}; + +/** + * \return An `exception_wrapper` that wraps an instance of type `Ex` + * that has been constructed with arguments `std::forward(as)...`. + */ +template +exception_wrapper make_exception_wrapper(As&&... as) { + return exception_wrapper{std::in_place_type, std::forward(as)...}; +} + +/** + * Inserts `ew.what()` into the ostream `sout`. + * \return `sout` + */ +template +std::basic_ostream& operator<<( + std::basic_ostream& sout, exception_wrapper const& ew) { + sout << ew.class_name(); + if (auto e = ew.get_exception()) { + sout << ": " << e->what(); + } + return sout; +} + +/** + * Swaps the value of `a` with the value of `b`. + */ +inline void swap(exception_wrapper& a, exception_wrapper& b) noexcept { + a.swap(b); +} + +// For consistency with exceptionStr() functions in ExceptionString.h +fbstring exceptionStr(exception_wrapper const& ew); + +//! `try_and_catch` is a convenience for `try {} catch(...) {}`` that returns an +//! `exception_wrapper` with the thrown exception, if any. +template +exception_wrapper try_and_catch(F&& fn) noexcept { + auto x = [&] { return void(static_cast(fn)()), std::exception_ptr{}; }; + return exception_wrapper{catch_exception(x, current_exception)}; +} +} // namespace folly + +#include + +#undef FOLLY_REQUIRES +#undef FOLLY_REQUIRES_DEF diff --git a/vnext/external/folly/folly/Executor.cpp b/vnext/external/folly/folly/Executor.cpp new file mode 100644 index 00000000000..4b40d29bc22 --- /dev/null +++ b/vnext/external/folly/folly/Executor.cpp @@ -0,0 +1,111 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include + +#include + +#include +#include +#include + +namespace folly { + +void Executor::invokeCatchingExnsLog(char const* const prefix) noexcept { + auto ep = current_exception(); + LOG(ERROR) << prefix << " threw unhandled " << exceptionStr(ep); +} + +void Executor::addWithPriority(Func, int8_t /* priority */) { + throw std::runtime_error( + "addWithPriority() is not implemented for this Executor"); +} + +bool Executor::keepAliveAcquire() noexcept { + return false; +} + +void Executor::keepAliveRelease() noexcept { + LOG(FATAL) << __func__ << "() should not be called for folly::Executor types " + << "which do not override keepAliveAcquire()"; +} + +// Base case of permitting with no termination to avoid nullptr tests +static ExecutorBlockingList emptyList{nullptr, {false, false, nullptr, {}}}; + +thread_local ExecutorBlockingList* executor_blocking_list = &emptyList; + +Optional getExecutorBlockingContext() noexcept { + return // + kIsMobile || !executor_blocking_list->curr.forbid ? none : // + make_optional(executor_blocking_list->curr); +} + +ExecutorBlockingGuard::ExecutorBlockingGuard(PermitTag) noexcept { + if (!kIsMobile) { + list_ = *executor_blocking_list; + list_.prev = executor_blocking_list; + list_.curr.forbid = false; + // Do not overwrite tag or executor pointer + executor_blocking_list = &list_; + } +} + +ExecutorBlockingGuard::ExecutorBlockingGuard( + TrackTag, Executor* ex, StringPiece tag) noexcept { + if (!kIsMobile) { + list_ = *executor_blocking_list; + list_.prev = executor_blocking_list; + list_.curr.forbid = true; + list_.curr.ex = ex; + // If no string was provided, maintain the parent string to keep some + // information + if (!tag.empty()) { + list_.curr.tag = tag; + } + executor_blocking_list = &list_; + } +} + +ExecutorBlockingGuard::ExecutorBlockingGuard( + ProhibitTag, Executor* ex, StringPiece tag) noexcept { + if (!kIsMobile) { + list_ = *executor_blocking_list; + list_.prev = executor_blocking_list; + list_.curr.forbid = true; + list_.curr.ex = ex; + list_.curr.allowTerminationOnBlocking = true; + // If no string was provided, maintain the parent string to keep some + // information + if (!tag.empty()) { + list_.curr.tag = tag; + } + executor_blocking_list = &list_; + } +} + +ExecutorBlockingGuard::~ExecutorBlockingGuard() { + if (!kIsMobile) { + if (executor_blocking_list != &list_) { + terminate_with("dtor mismatch"); + } + executor_blocking_list = list_.prev; + } +} + +} // namespace folly diff --git a/vnext/external/folly/folly/Executor.h b/vnext/external/folly/folly/Executor.h new file mode 100644 index 00000000000..f5410f6f369 --- /dev/null +++ b/vnext/external/folly/folly/Executor.h @@ -0,0 +1,351 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include + +#include +#include +#include +#include +#include + +namespace folly { + +using Func = Function; + +namespace detail { + +class ExecutorKeepAliveBase { + public: + // A dummy keep-alive is a keep-alive to an executor which does not support + // the keep-alive mechanism. + static constexpr uintptr_t kDummyFlag = uintptr_t(1) << 0; + + // An alias keep-alive is a keep-alive to an executor to which there is + // known to be another keep-alive whose lifetime surrounds the lifetime of + // the alias. + static constexpr uintptr_t kAliasFlag = uintptr_t(1) << 1; + + static constexpr uintptr_t kFlagMask = kDummyFlag | kAliasFlag; + static constexpr uintptr_t kExecutorMask = ~kFlagMask; +}; + +} // namespace detail + +/// An Executor accepts units of work with add(), which should be +/// threadsafe. +class Executor { + public: + virtual ~Executor() = default; + + /// Enqueue a function to be executed by this executor. This and all + /// variants must be threadsafe. + virtual void add(Func) = 0; + + /// Enqueue a function with a given priority, where 0 is the medium priority + /// This is up to the implementation to enforce + virtual void addWithPriority(Func, int8_t priority); + + virtual uint8_t getNumPriorities() const { return 1; } + + static constexpr int8_t LO_PRI = SCHAR_MIN; + static constexpr int8_t MID_PRI = 0; + static constexpr int8_t HI_PRI = SCHAR_MAX; + + /** + * Executor::KeepAlive is a safe pointer to an Executor. + * For any Executor that supports KeepAlive functionality, Executor's + * destructor will block until all the KeepAlive objects associated with that + * Executor are destroyed. + * For Executors that don't support the KeepAlive functionality, KeepAlive + * doesn't provide such protection. + * + * KeepAlive should *always* be used instead of Executor*. KeepAlive can be + * implicitly constructed from Executor*. getKeepAliveToken() helper method + * can be used to construct a KeepAlive in templated code if you need to + * preserve the original Executor type. + */ + template + class KeepAlive : private detail::ExecutorKeepAliveBase { + public: + using KeepAliveFunc = Function; + + KeepAlive() = default; + + ~KeepAlive() { + static_assert( + std::is_standard_layout::value, "standard-layout"); + static_assert(sizeof(KeepAlive) == sizeof(void*), "pointer size"); + static_assert(alignof(KeepAlive) == alignof(void*), "pointer align"); + + reset(); + } + + KeepAlive(KeepAlive&& other) noexcept + : storage_(std::exchange(other.storage_, 0)) {} + + KeepAlive(const KeepAlive& other) noexcept + : KeepAlive(getKeepAliveToken(other.get())) {} + + template < + typename OtherExecutor, + typename = typename std::enable_if< + std::is_convertible::value>::type> + /* implicit */ KeepAlive(KeepAlive&& other) noexcept + : KeepAlive(other.get(), other.storage_ & kFlagMask) { + other.storage_ = 0; + } + + template < + typename OtherExecutor, + typename = typename std::enable_if< + std::is_convertible::value>::type> + /* implicit */ KeepAlive(const KeepAlive& other) noexcept + : KeepAlive(getKeepAliveToken(other.get())) {} + + /* implicit */ KeepAlive(ExecutorT* executor) { + *this = getKeepAliveToken(executor); + } + + KeepAlive& operator=(KeepAlive&& other) noexcept { + reset(); + storage_ = std::exchange(other.storage_, 0); + return *this; + } + + KeepAlive& operator=(KeepAlive const& other) { + return operator=(folly::copy(other)); + } + + template < + typename OtherExecutor, + typename = typename std::enable_if< + std::is_convertible::value>::type> + KeepAlive& operator=(KeepAlive&& other) noexcept { + return *this = KeepAlive(std::move(other)); + } + + template < + typename OtherExecutor, + typename = typename std::enable_if< + std::is_convertible::value>::type> + KeepAlive& operator=(const KeepAlive& other) { + return *this = KeepAlive(other); + } + + void reset() noexcept { + if (Executor* executor = get()) { + auto const flags = std::exchange(storage_, 0) & kFlagMask; + if (!(flags & (kDummyFlag | kAliasFlag))) { + executor->keepAliveRelease(); + } + } + } + + explicit operator bool() const { return storage_; } + + ExecutorT* get() const { + return reinterpret_cast(storage_ & kExecutorMask); + } + + ExecutorT& operator*() const { return *get(); } + + ExecutorT* operator->() const { return get(); } + + KeepAlive copy() const { + return isKeepAliveDummy(*this) // + ? makeKeepAliveDummy(get()) + : getKeepAliveToken(get()); + } + + KeepAlive get_alias() const { return KeepAlive(storage_ | kAliasFlag); } + + template + void add(KAF&& f) && { + static_assert( + is_invocable::value, + "Parameter to add must be void(KeepAlive&&)>"); + auto ex = get(); + ex->add([ka = std::move(*this), f_2 = std::forward(f)]() mutable { + f_2(std::move(ka)); + }); + } + + private: + friend class Executor; + template + friend class KeepAlive; + + KeepAlive(ExecutorT* executor, uintptr_t flags) noexcept + : storage_(reinterpret_cast(executor) | flags) { + assert(executor); + assert(!(reinterpret_cast(executor) & ~kExecutorMask)); + assert(!(flags & kExecutorMask)); + } + + explicit KeepAlive(uintptr_t storage) noexcept : storage_(storage) {} + + // Combined storage for the executor pointer and for all flags. + uintptr_t storage_{reinterpret_cast(nullptr)}; + }; + + template + static KeepAlive getKeepAliveToken(ExecutorT* executor) { + static_assert( + std::is_base_of::value, + "getKeepAliveToken only works for folly::Executor implementations."); + if (!executor) { + return {}; + } + folly::Executor* executorPtr = executor; + if (executorPtr->keepAliveAcquire()) { + return makeKeepAlive(executor); + } + return makeKeepAliveDummy(executor); + } + + template + static KeepAlive getKeepAliveToken(ExecutorT& executor) { + static_assert( + std::is_base_of::value, + "getKeepAliveToken only works for folly::Executor implementations."); + return getKeepAliveToken(&executor); + } + + template + FOLLY_ERASE static void invokeCatchingExns(char const* p, F f) noexcept { + catch_exception(f, invokeCatchingExnsLog, p); + } + + protected: + /** + * Returns true if the KeepAlive is constructed from an executor that does + * not support the keep alive ref-counting functionality + */ + template + static bool isKeepAliveDummy(const KeepAlive& keepAlive) { + return keepAlive.storage_ & KeepAlive::kDummyFlag; + } + + static bool keepAliveAcquire(Executor* executor) { + return executor->keepAliveAcquire(); + } + static void keepAliveRelease(Executor* executor) { + return executor->keepAliveRelease(); + } + + // Acquire a keep alive token. Should return false if keep-alive mechanism + // is not supported. + virtual bool keepAliveAcquire() noexcept; + // Release a keep alive token previously acquired by keepAliveAcquire(). + // Will never be called if keepAliveAcquire() returns false. + virtual void keepAliveRelease() noexcept; + + template + static KeepAlive makeKeepAlive(ExecutorT* executor) { + static_assert( + std::is_base_of::value, + "makeKeepAlive only works for folly::Executor implementations."); + return KeepAlive{executor, uintptr_t(0)}; + } + + private: + static void invokeCatchingExnsLog(char const* prefix) noexcept; + + template + static KeepAlive makeKeepAliveDummy(ExecutorT* executor) { + static_assert( + std::is_base_of::value, + "makeKeepAliveDummy only works for folly::Executor implementations."); + return KeepAlive{executor, KeepAlive::kDummyFlag}; + } +}; + +/// Returns a keep-alive token which guarantees that Executor will keep +/// processing tasks until the token is released (if supported by Executor). +/// KeepAlive always contains a valid pointer to an Executor. +template +Executor::KeepAlive getKeepAliveToken(ExecutorT* executor) { + static_assert( + std::is_base_of::value, + "getKeepAliveToken only works for folly::Executor implementations."); + return Executor::getKeepAliveToken(executor); +} + +template +Executor::KeepAlive getKeepAliveToken(ExecutorT& executor) { + static_assert( + std::is_base_of::value, + "getKeepAliveToken only works for folly::Executor implementations."); + return getKeepAliveToken(&executor); +} + +template +Executor::KeepAlive getKeepAliveToken( + Executor::KeepAlive& ka) { + return ka.copy(); +} + +struct ExecutorBlockingContext { + bool forbid; + bool allowTerminationOnBlocking; + Executor* ex = nullptr; + StringPiece tag; +}; +static_assert( + std::is_standard_layout::value, + "non-standard layout"); + +struct ExecutorBlockingList { + ExecutorBlockingList* prev; + ExecutorBlockingContext curr; +}; +static_assert( + std::is_standard_layout::value, + "non-standard layout"); + +class ExecutorBlockingGuard { + public: + struct PermitTag {}; + struct TrackTag {}; + struct ProhibitTag {}; + + ~ExecutorBlockingGuard(); + ExecutorBlockingGuard() = delete; + + explicit ExecutorBlockingGuard(PermitTag) noexcept; + explicit ExecutorBlockingGuard( + TrackTag, Executor* ex, StringPiece tag) noexcept; + explicit ExecutorBlockingGuard( + ProhibitTag, Executor* ex, StringPiece tag) noexcept; + + ExecutorBlockingGuard(ExecutorBlockingGuard&&) = delete; + ExecutorBlockingGuard(ExecutorBlockingGuard const&) = delete; + + ExecutorBlockingGuard& operator=(ExecutorBlockingGuard const&) = delete; + ExecutorBlockingGuard& operator=(ExecutorBlockingGuard&&) = delete; + + private: + ExecutorBlockingList list_; +}; + +Optional getExecutorBlockingContext() noexcept; + +} // namespace folly diff --git a/vnext/external/folly/folly/Expected.h b/vnext/external/folly/folly/Expected.h new file mode 100644 index 00000000000..2d3c2d13cde --- /dev/null +++ b/vnext/external/folly/folly/Expected.h @@ -0,0 +1,1725 @@ +/* + * Copyright (c) Meta Platforms, Inc. and affiliates. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * Like folly::Optional, but can store a value *or* an error. + */ + +#pragma once + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define FOLLY_EXPECTED_ID(X) FB_CONCATENATE(FB_CONCATENATE(Folly, X), __LINE__) + +#define FOLLY_REQUIRES_IMPL(...) \ + bool FOLLY_EXPECTED_ID(Requires) = false, \ + typename std::enable_if< \ + (FOLLY_EXPECTED_ID(Requires) || static_cast(__VA_ARGS__)), \ + int>::type = 0 + +#define FOLLY_REQUIRES_TRAILING(...) , FOLLY_REQUIRES_IMPL(__VA_ARGS__) + +#define FOLLY_REQUIRES(...) template + +namespace folly { + +namespace expected_detail { +namespace expected_detail_ExpectedHelper { +struct ExpectedHelper; +} +/* using override */ using expected_detail_ExpectedHelper::ExpectedHelper; +} // namespace expected_detail + +/** + * Unexpected - a helper type used to disambiguate the construction of + * Expected objects in the error state. + */ +template +class FOLLY_NODISCARD Unexpected final { + template + friend class Unexpected; + template + friend class Expected; + friend struct expected_detail::ExpectedHelper; + + public: + /** + * Constructors + */ + Unexpected() = default; + Unexpected(const Unexpected&) = default; + Unexpected(Unexpected&&) = default; + Unexpected& operator=(const Unexpected&) = default; + Unexpected& operator=(Unexpected&&) = default; + [[FOLLY_ATTR_GNU_COLD]] constexpr /* implicit */ Unexpected(const Error& err) + : error_(err) {} + [[FOLLY_ATTR_GNU_COLD]] constexpr /* implicit */ Unexpected(Error&& err) + : error_(std::move(err)) {} + + template ::value)> + constexpr /* implicit */ Unexpected(Unexpected that) + : error_(std::move(that.error())) {} + + /** + * Assignment + */ + template ::value)> + Unexpected& operator=(Unexpected that) { + error_ = std::move(that.error()); + } + + /** + * Observers + */ + Error& error() & { return error_; } + const Error& error() const& { return error_; } + Error&& error() && { return std::move(error_); } + const Error&& error() const&& { return std::move(error_); } + + private: + Error error_; +}; + +template < + class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable::value)> +inline bool operator==( + const Unexpected& lhs, const Unexpected& rhs) { + return lhs.error() == rhs.error(); +} + +template < + class Error FOLLY_REQUIRES_TRAILING(IsEqualityComparable::value)> +inline bool operator!=( + const Unexpected& lhs, const Unexpected& rhs) { + return !(lhs == rhs); +} + +/** + * For constructing an Unexpected object from an error code. Unexpected objects + * are implicitly convertible to Expected object in the error state. Usage is + * as follows: + * + * enum class MyErrorCode { BAD_ERROR, WORSE_ERROR }; + * Expected myAPI() { + * int i = // ...; + * return i ? makeExpected(i) + * : makeUnexpected(MyErrorCode::BAD_ERROR); + * } + */ +template +constexpr Unexpected::type> makeUnexpected( + Error&& err) { + return Unexpected::type>{ + static_cast(err)}; +} + +template +class FOLLY_EXPORT BadExpectedAccess; + +/** + * A common base type for exceptions thrown by Expected when the caller + * erroneously requests a value. + */ +template <> +class FOLLY_EXPORT BadExpectedAccess : public std::exception { + public: + explicit BadExpectedAccess() noexcept = default; + BadExpectedAccess(BadExpectedAccess const&) {} + BadExpectedAccess& operator=(BadExpectedAccess const&) { return *this; } + + char const* what() const noexcept override { return "bad expected access"; } +}; + +/** + * An exception type thrown by Expected on catastrophic logic errors, i.e., when + * the caller tries to access the value within an Expected but when the Expected + * instead contains an error. + */ +template +class FOLLY_EXPORT BadExpectedAccess : public BadExpectedAccess { + public: + explicit BadExpectedAccess(Error error) + : error_{static_cast(error)} {} + + /** + * The error code that was held by the Expected object when the caller + * erroneously requested the value. + */ + Error& error() & { return error_; } + Error const& error() const& { return error_; } + Error&& error() && { return static_cast(error_); } + Error const&& error() const&& { return static_cast(error_); } + + private: + Error error_; +}; + +/** + * Forward declarations + */ +template +class Expected; + +template +FOLLY_NODISCARD constexpr Expected::type, Error> +makeExpected(Value&&); + +/** + * Alias for an Expected type's associated value_type + */ +template +using ExpectedValueType = + typename std::remove_reference::type::value_type; + +/** + * Alias for an Expected type's associated error_type + */ +template +using ExpectedErrorType = + typename std::remove_reference::type::error_type; + +// Details... +namespace expected_detail { + +template +struct Promise; +template +struct PromiseReturn; + +template