react-native-windows 0.78.4 → 0.78.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (191) hide show
  1. package/Directory.Build.props +6 -4
  2. package/Folly/Folly.vcxproj +46 -6
  3. package/Folly/Folly.vcxproj.filters +16 -4
  4. package/Folly/TEMP_UntilFollyUpdate/ConstexprMath.h +26 -18
  5. package/Folly/TEMP_UntilFollyUpdate/Conv.cpp +1205 -0
  6. package/Folly/TEMP_UntilFollyUpdate/chrono/Hardware.h +155 -0
  7. package/Folly/TEMP_UntilFollyUpdate/concurrency/CacheLocality.cpp +633 -0
  8. package/Folly/TEMP_UntilFollyUpdate/{dynamic-inl.h → json/dynamic-inl.h} +3 -4
  9. package/Folly/TEMP_UntilFollyUpdate/{json.cpp → json/json.cpp} +14 -10
  10. package/Folly/TEMP_UntilFollyUpdate/lang/SafeAssert.h +7 -14
  11. package/Folly/TEMP_UntilFollyUpdate/lang/ToAscii.h +6 -6
  12. package/Folly/ThreadNameStub.cpp +10 -0
  13. package/Folly/cgmanifest.json +11 -1
  14. package/Libraries/Components/View/View.windows.js +107 -56
  15. package/Libraries/Components/View/ViewAccessibility.d.ts +60 -1
  16. package/Libraries/Image/Image.windows.js +42 -21
  17. package/Libraries/Modal/Modal.d.ts +7 -0
  18. package/Libraries/Modal/Modal.windows.js +7 -1
  19. package/Libraries/NativeComponent/BaseViewConfig.windows.js +3 -0
  20. package/Libraries/Text/Text.d.ts +18 -0
  21. package/Microsoft.ReactNative/AsynchronousEventBeat.cpp +4 -25
  22. package/Microsoft.ReactNative/AsynchronousEventBeat.h +0 -3
  23. package/Microsoft.ReactNative/Base/FollyIncludes.h +1 -0
  24. package/Microsoft.ReactNative/CallInvoker.cpp +42 -0
  25. package/Microsoft.ReactNative/CallInvoker.h +34 -0
  26. package/Microsoft.ReactNative/{JSDispatcherWriter.cpp → CallInvokerWriter.cpp} +35 -47
  27. package/Microsoft.ReactNative/CallInvokerWriter.h +74 -0
  28. package/Microsoft.ReactNative/CompositionComponentView.idl +0 -5
  29. package/Microsoft.ReactNative/CompositionSwitcher.idl +7 -0
  30. package/Microsoft.ReactNative/Fabric/AbiViewProps.cpp +8 -10
  31. package/Microsoft.ReactNative/Fabric/ComponentView.cpp +4 -1
  32. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.cpp +12 -2
  33. package/Microsoft.ReactNative/Fabric/Composition/ActivityIndicatorComponentView.h +2 -0
  34. package/Microsoft.ReactNative/Fabric/Composition/CompositionAnnotationProvider.cpp +100 -0
  35. package/Microsoft.ReactNative/Fabric/Composition/CompositionAnnotationProvider.h +31 -0
  36. package/Microsoft.ReactNative/Fabric/Composition/CompositionContextHelper.cpp +77 -11
  37. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.cpp +43 -1
  38. package/Microsoft.ReactNative/Fabric/Composition/CompositionDynamicAutomationProvider.h +7 -0
  39. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.cpp +86 -56
  40. package/Microsoft.ReactNative/Fabric/Composition/CompositionEventHandler.h +5 -1
  41. package/Microsoft.ReactNative/Fabric/Composition/CompositionRootAutomationProvider.cpp +0 -4
  42. package/Microsoft.ReactNative/Fabric/Composition/CompositionUIService.cpp +0 -2
  43. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.cpp +118 -63
  44. package/Microsoft.ReactNative/Fabric/Composition/CompositionViewComponentView.h +2 -0
  45. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.cpp +133 -8
  46. package/Microsoft.ReactNative/Fabric/Composition/ContentIslandComponentView.h +16 -2
  47. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.cpp +4 -2
  48. package/Microsoft.ReactNative/Fabric/Composition/FocusManager.h +9 -1
  49. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.cpp +34 -11
  50. package/Microsoft.ReactNative/Fabric/Composition/ImageComponentView.h +3 -0
  51. package/Microsoft.ReactNative/Fabric/Composition/Modal/WindowsModalHostViewComponentView.cpp +133 -135
  52. package/Microsoft.ReactNative/Fabric/Composition/ParagraphComponentView.cpp +9 -6
  53. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.cpp +46 -49
  54. package/Microsoft.ReactNative/Fabric/Composition/ReactNativeIsland.h +6 -1
  55. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.cpp +13 -8
  56. package/Microsoft.ReactNative/Fabric/Composition/RootComponentView.h +5 -2
  57. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.cpp +146 -25
  58. package/Microsoft.ReactNative/Fabric/Composition/ScrollViewComponentView.h +14 -0
  59. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.cpp +160 -12
  60. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputComponentView.h +6 -0
  61. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.cpp +47 -0
  62. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputEventEmitter.h +15 -1
  63. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.cpp +6 -2
  64. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputProps.h +4 -1
  65. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.cpp +7 -9
  66. package/Microsoft.ReactNative/Fabric/Composition/TextInput/WindowsTextInputShadowNode.h +4 -1
  67. package/Microsoft.ReactNative/Fabric/Composition/Theme.cpp +5 -0
  68. package/Microsoft.ReactNative/Fabric/Composition/TooltipService.cpp +40 -36
  69. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.cpp +68 -0
  70. package/Microsoft.ReactNative/Fabric/Composition/UiaHelpers.h +11 -0
  71. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.cpp +70 -13
  72. package/Microsoft.ReactNative/Fabric/FabricUIManagerModule.h +10 -2
  73. package/Microsoft.ReactNative/Fabric/ImageManager.cpp +5 -5
  74. package/Microsoft.ReactNative/Fabric/ImageRequestParams.cpp +26 -0
  75. package/Microsoft.ReactNative/Fabric/WindowsImageManager.cpp +47 -8
  76. package/Microsoft.ReactNative/Fabric/WindowsImageManager.h +10 -1
  77. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/CompositionAccessibilityProps.h +67 -0
  78. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.cpp +22 -4
  79. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewEventEmitter.h +15 -2
  80. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.cpp +20 -0
  81. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/HostPlatformViewProps.h +5 -0
  82. package/Microsoft.ReactNative/Fabric/platform/react/renderer/components/view/MouseEvent.h +20 -0
  83. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/HostPlatformColor.h +5 -8
  84. package/Microsoft.ReactNative/Fabric/platform/react/renderer/graphics/PlatformColorParser.h +1 -2
  85. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.cpp +247 -45
  86. package/Microsoft.ReactNative/Fabric/platform/react/renderer/textlayoutmanager/TextLayoutManager.h +15 -0
  87. package/Microsoft.ReactNative/Fabric/platform/react/threading/MessageQueueThreadImpl.cpp +39 -0
  88. package/Microsoft.ReactNative/Fabric/platform/react/threading/MessageQueueThreadImpl.h +54 -0
  89. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.cpp +126 -0
  90. package/Microsoft.ReactNative/Fabric/platform/react/threading/TaskDispatchThread.h +73 -0
  91. package/Microsoft.ReactNative/IReactContext.cpp +17 -0
  92. package/Microsoft.ReactNative/IReactContext.h +1 -0
  93. package/Microsoft.ReactNative/IReactContext.idl +18 -1
  94. package/Microsoft.ReactNative/IReactDispatcher.idl +1 -0
  95. package/Microsoft.ReactNative/IReactModuleBuilder.cpp +12 -0
  96. package/Microsoft.ReactNative/IReactModuleBuilder.h +2 -0
  97. package/Microsoft.ReactNative/IReactModuleBuilder.idl +8 -0
  98. package/Microsoft.ReactNative/JsiApi.cpp +10 -2
  99. package/Microsoft.ReactNative/JsiApi.h +1 -0
  100. package/Microsoft.ReactNative/JsiApi.idl +1 -0
  101. package/Microsoft.ReactNative/Microsoft.ReactNative.vcxproj +0 -3
  102. package/Microsoft.ReactNative/Modules/AccessibilityInfoModule.cpp +2 -3
  103. package/Microsoft.ReactNative/Modules/AlertModule.cpp +7 -12
  104. package/Microsoft.ReactNative/Modules/Animated/AnimationDriver.cpp +2 -1
  105. package/Microsoft.ReactNative/Modules/Animated/NativeAnimatedModule.cpp +4 -8
  106. package/Microsoft.ReactNative/Modules/AppStateModule.cpp +2 -2
  107. package/Microsoft.ReactNative/Modules/ClipboardModule.cpp +6 -8
  108. package/Microsoft.ReactNative/Modules/ClipboardModule.h +1 -1
  109. package/Microsoft.ReactNative/Modules/ImageViewManagerModule.cpp +6 -15
  110. package/Microsoft.ReactNative/Modules/NativeUIManager.cpp +13 -24
  111. package/Microsoft.ReactNative/QuirkSettings.cpp +0 -16
  112. package/Microsoft.ReactNative/QuirkSettings.h +0 -3
  113. package/Microsoft.ReactNative/ReactHost/ReactHost.cpp +11 -1
  114. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.cpp +78 -68
  115. package/Microsoft.ReactNative/ReactHost/ReactInstanceWin.h +1 -2
  116. package/Microsoft.ReactNative/ReactInstanceSettings.cpp +12 -0
  117. package/Microsoft.ReactNative/ReactInstanceSettings.h +2 -0
  118. package/Microsoft.ReactNative/ReactInstanceSettings.idl +6 -0
  119. package/Microsoft.ReactNative/ReactNativeIsland.idl +3 -0
  120. package/Microsoft.ReactNative/ReactSupport.cpp +44 -11
  121. package/Microsoft.ReactNative/RedBox.cpp +30 -1
  122. package/Microsoft.ReactNative/SchedulerSettings.cpp +4 -4
  123. package/Microsoft.ReactNative/SchedulerSettings.h +1 -1
  124. package/Microsoft.ReactNative/TurboModulesProvider.cpp +30 -12
  125. package/Microsoft.ReactNative/Utils/ImageUtils.h +1 -0
  126. package/Microsoft.ReactNative/Utils/LocalBundleReader.cpp +37 -31
  127. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.cpp +1 -0
  128. package/Microsoft.ReactNative.Cxx/ApiLoaders/JSRuntimeApi.inc +2 -0
  129. package/Microsoft.ReactNative.Cxx/ApiLoaders/NodeApi_posix.cpp +1 -1
  130. package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.cpp +94 -27
  131. package/Microsoft.ReactNative.Cxx/JSI/JsiAbiApi.h +27 -6
  132. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.cpp +45 -11
  133. package/Microsoft.ReactNative.Cxx/JSI/JsiApiContext.h +6 -0
  134. package/Microsoft.ReactNative.Cxx/JSI/decorator.h +220 -0
  135. package/Microsoft.ReactNative.Cxx/JSI/instrumentation.h +28 -0
  136. package/Microsoft.ReactNative.Cxx/JSI/jsi-inl.h +6 -0
  137. package/Microsoft.ReactNative.Cxx/JSI/jsi.cpp +241 -4
  138. package/Microsoft.ReactNative.Cxx/JSI/jsi.h +207 -19
  139. package/Microsoft.ReactNative.Cxx/JSValue.cpp +19 -3
  140. package/Microsoft.ReactNative.Cxx/JSValue.h +15 -7
  141. package/Microsoft.ReactNative.Cxx/Microsoft.ReactNative.Cxx.vcxitems +2 -2
  142. package/Microsoft.ReactNative.Cxx/NativeModules.h +60 -2
  143. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.cpp +1267 -614
  144. package/Microsoft.ReactNative.Cxx/NodeApiJsiRuntime.h +4 -2
  145. package/Microsoft.ReactNative.Cxx/ReactContext.h +7 -0
  146. package/Microsoft.ReactNative.Cxx/TurboModuleProvider.cpp +11 -13
  147. package/Microsoft.ReactNative.Cxx/TurboModuleProvider.h +2 -3
  148. package/Microsoft.ReactNative.Cxx/node-api/js_native_api.h +81 -20
  149. package/Microsoft.ReactNative.Cxx/node-api/js_native_api_types.h +47 -2
  150. package/Microsoft.ReactNative.Cxx/node-api/js_runtime_api.h +13 -0
  151. package/Microsoft.ReactNative.Cxx/stubs/glog/logging.h +1 -1
  152. package/Microsoft.ReactNative.Managed/ReactContext.cs +3 -1
  153. package/PropertySheets/Generated/PackageVersion.g.props +3 -3
  154. package/PropertySheets/JSEngine.props +1 -1
  155. package/PropertySheets/React.Cpp.props +2 -1
  156. package/PropertySheets/WebView2.props +1 -1
  157. package/PropertySheets/WinUI.props +2 -2
  158. package/ReactCommon/TEMP_UntilReactCommonUpdate/jserrorhandler/JsErrorHandler.cpp +429 -0
  159. package/ReactCommon/cgmanifest.json +1 -1
  160. package/Shared/HermesRuntimeHolder.cpp +6 -0
  161. package/Shared/JSI/ChakraRuntime.cpp +4 -0
  162. package/Shared/JSI/ChakraRuntime.h +2 -0
  163. package/Shared/Modules/BlobModule.cpp +14 -16
  164. package/Shared/Modules/BlobModule.h +3 -1
  165. package/Shared/Networking/WinRTWebSocketResource.cpp +82 -101
  166. package/Shared/Networking/WinRTWebSocketResource.h +91 -7
  167. package/Shared/Shared.vcxitems +11 -7
  168. package/Shared/Shared.vcxitems.filters +6 -1
  169. package/Shared/TurboModuleManager.cpp +0 -15
  170. package/codegen/react/components/rnwcore/ActivityIndicatorView.g.h +6 -6
  171. package/codegen/react/components/rnwcore/AndroidDrawerLayout.g.h +6 -6
  172. package/codegen/react/components/rnwcore/AndroidHorizontalScrollContentView.g.h +6 -6
  173. package/codegen/react/components/rnwcore/AndroidProgressBar.g.h +6 -6
  174. package/codegen/react/components/rnwcore/AndroidSwipeRefreshLayout.g.h +6 -6
  175. package/codegen/react/components/rnwcore/AndroidSwitch.g.h +6 -6
  176. package/codegen/react/components/rnwcore/DebuggingOverlay.g.h +6 -6
  177. package/codegen/react/components/rnwcore/InputAccessory.g.h +6 -6
  178. package/codegen/react/components/rnwcore/ModalHostView.g.h +11 -7
  179. package/codegen/react/components/rnwcore/Props.cpp +2 -1
  180. package/codegen/react/components/rnwcore/Props.h +1 -0
  181. package/codegen/react/components/rnwcore/PullToRefreshView.g.h +6 -6
  182. package/codegen/react/components/rnwcore/SafeAreaView.g.h +6 -6
  183. package/codegen/react/components/rnwcore/Switch.g.h +6 -6
  184. package/codegen/react/components/rnwcore/UnimplementedNativeView.g.h +6 -6
  185. package/index.windows.js +4 -2
  186. package/package.json +3 -4
  187. package/src/private/specs/components/RCTModalHostViewNativeComponent.js +8 -0
  188. package/stubs/glog/logging.h +1 -1
  189. package/Microsoft.ReactNative/JSDispatcherWriter.h +0 -47
  190. package/Microsoft.ReactNative/SynchronousEventBeat.cpp +0 -51
  191. package/Microsoft.ReactNative/SynchronousEventBeat.h +0 -31
@@ -0,0 +1,1205 @@
1
+ /*
2
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
3
+ *
4
+ * Licensed under the Apache License, Version 2.0 (the "License");
5
+ * you may not use this file except in compliance with the License.
6
+ * You may obtain a copy of the License at
7
+ *
8
+ * http://www.apache.org/licenses/LICENSE-2.0
9
+ *
10
+ * Unless required by applicable law or agreed to in writing, software
11
+ * distributed under the License is distributed on an "AS IS" BASIS,
12
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ * See the License for the specific language governing permissions and
14
+ * limitations under the License.
15
+ */
16
+
17
+ #include <folly/Conv.h>
18
+
19
+ #include <array>
20
+ #include <istream>
21
+
22
+ #include <folly/lang/SafeAssert.h>
23
+
24
+ #include <fast_float/fast_float.h> // @manual=fbsource//third-party/fast_float:fast_float
25
+
26
+ namespace folly {
27
+ namespace detail {
28
+
29
+ namespace {
30
+
31
+ /**
32
+ * Finds the first non-digit in a string. The number of digits
33
+ * searched depends on the precision of the Tgt integral. Assumes the
34
+ * string starts with NO whitespace and NO sign.
35
+ *
36
+ * The semantics of the routine is:
37
+ * for (;; ++b) {
38
+ * if (b >= e || !isdigit(*b)) return b;
39
+ * }
40
+ *
41
+ * Complete unrolling marks bottom-line (i.e. entire conversion)
42
+ * improvements of 20%.
43
+ */
44
+ inline const char* findFirstNonDigit(const char* b, const char* e) {
45
+ for (; b < e; ++b) {
46
+ auto const c = static_cast<unsigned>(*b) - '0';
47
+ if (c >= 10) {
48
+ break;
49
+ }
50
+ }
51
+ return b;
52
+ }
53
+
54
+ // Maximum value of number when represented as a string
55
+ template <class T>
56
+ struct MaxString {
57
+ static const char* const value;
58
+ };
59
+
60
+ template <>
61
+ const char* const MaxString<uint8_t>::value = "255";
62
+ template <>
63
+ const char* const MaxString<uint16_t>::value = "65535";
64
+ template <>
65
+ const char* const MaxString<uint32_t>::value = "4294967295";
66
+ #if __SIZEOF_LONG__ == 4
67
+ template <>
68
+ const char* const MaxString<unsigned long>::value = "4294967295";
69
+ #else
70
+ template <>
71
+ const char* const MaxString<unsigned long>::value = "18446744073709551615";
72
+ #endif
73
+ static_assert(
74
+ sizeof(unsigned long) >= 4,
75
+ "Wrong value for MaxString<unsigned long>::value,"
76
+ " please update.");
77
+ template <>
78
+ const char* const MaxString<unsigned long long>::value = "18446744073709551615";
79
+ static_assert(
80
+ sizeof(unsigned long long) >= 8,
81
+ "Wrong value for MaxString<unsigned long long>::value"
82
+ ", please update.");
83
+
84
+ #if FOLLY_HAVE_INT128_T
85
+ template <>
86
+ const char* const MaxString<__uint128_t>::value =
87
+ "340282366920938463463374607431768211455";
88
+ #endif
89
+
90
+ /*
91
+ * Lookup tables that converts from a decimal character value to an integral
92
+ * binary value, shifted by a decimal "shift" multiplier.
93
+ * For all character values in the range '0'..'9', the table at those
94
+ * index locations returns the actual decimal value shifted by the multiplier.
95
+ * For all other values, the lookup table returns an invalid OOR value.
96
+ */
97
+ // Out-of-range flag value, larger than the largest value that can fit in
98
+ // four decimal bytes (9999), but four of these added up together should
99
+ // still not overflow uint16_t.
100
+ constexpr int32_t OOR = 10000;
101
+
102
+ alignas(16) constexpr uint16_t shift1[] = {
103
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 0-9
104
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 10
105
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 20
106
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 30
107
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, 0, 1, // 40
108
+ 2, 3, 4, 5, 6, 7, 8, 9, OOR, OOR,
109
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 60
110
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 70
111
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 80
112
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 90
113
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 100
114
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 110
115
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 120
116
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 130
117
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 140
118
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 150
119
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 160
120
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 170
121
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 180
122
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 190
123
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 200
124
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 210
125
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 220
126
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 230
127
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 240
128
+ OOR, OOR, OOR, OOR, OOR, OOR // 250
129
+ };
130
+
131
+ alignas(16) constexpr uint16_t shift10[] = {
132
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 0-9
133
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 10
134
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 20
135
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 30
136
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, 0, 10, // 40
137
+ 20, 30, 40, 50, 60, 70, 80, 90, OOR, OOR,
138
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 60
139
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 70
140
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 80
141
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 90
142
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 100
143
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 110
144
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 120
145
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 130
146
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 140
147
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 150
148
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 160
149
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 170
150
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 180
151
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 190
152
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 200
153
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 210
154
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 220
155
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 230
156
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 240
157
+ OOR, OOR, OOR, OOR, OOR, OOR // 250
158
+ };
159
+
160
+ alignas(16) constexpr uint16_t shift100[] = {
161
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 0-9
162
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 10
163
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 20
164
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 30
165
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, 0, 100, // 40
166
+ 200, 300, 400, 500, 600, 700, 800, 900, OOR, OOR,
167
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 60
168
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 70
169
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 80
170
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 90
171
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 100
172
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 110
173
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 120
174
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 130
175
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 140
176
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 150
177
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 160
178
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 170
179
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 180
180
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 190
181
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 200
182
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 210
183
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 220
184
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 230
185
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 240
186
+ OOR, OOR, OOR, OOR, OOR, OOR // 250
187
+ };
188
+
189
+ alignas(16) constexpr uint16_t shift1000[] = {
190
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 0-9
191
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 10
192
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 20
193
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 30
194
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, 0, 1000, // 40
195
+ 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, OOR, OOR,
196
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 60
197
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 70
198
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 80
199
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 90
200
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 100
201
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 110
202
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 120
203
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 130
204
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 140
205
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 150
206
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 160
207
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 170
208
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 180
209
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 190
210
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 200
211
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 210
212
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 220
213
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 230
214
+ OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, OOR, // 240
215
+ OOR, OOR, OOR, OOR, OOR, OOR // 250
216
+ };
217
+
218
+ struct ErrorString {
219
+ const char* string;
220
+ bool quote;
221
+ };
222
+
223
+ // Keep this in sync with ConversionCode in Conv.h
224
+ constexpr const std::array<
225
+ ErrorString,
226
+ static_cast<std::size_t>(ConversionCode::NUM_ERROR_CODES)>
227
+ kErrorStrings{{
228
+ {"Success", true},
229
+ {"Empty input string", true},
230
+ {"No digits found in input string", true},
231
+ {"Integer overflow when parsing bool (must be 0 or 1)", true},
232
+ {"Invalid value for bool", true},
233
+ {"Non-digit character found", true},
234
+ {"Invalid leading character", true},
235
+ {"Overflow during conversion", true},
236
+ {"Negative overflow during conversion", true},
237
+ {"Unable to convert string to floating point value", true},
238
+ {"Non-whitespace character found after end of conversion", true},
239
+ {"Overflow during arithmetic conversion", false},
240
+ {"Negative overflow during arithmetic conversion", false},
241
+ {"Loss of precision during arithmetic conversion", false},
242
+ }};
243
+
244
+ // Check if ASCII is really ASCII
245
+ using IsAscii =
246
+ std::bool_constant<'A' == 65 && 'Z' == 90 && 'a' == 97 && 'z' == 122>;
247
+
248
+ // The code in this file that uses tolower() really only cares about
249
+ // 7-bit ASCII characters, so we can take a nice shortcut here.
250
+ inline char tolower_ascii(char in) {
251
+ return IsAscii::value ? in | 0x20 : char(std::tolower(in));
252
+ }
253
+
254
+ inline bool bool_str_cmp(const char** b, size_t len, const char* value) {
255
+ // Can't use strncasecmp, since we want to ensure that the full value matches
256
+ const char* p = *b;
257
+ const char* e = *b + len;
258
+ const char* v = value;
259
+ while (*v != '\0') {
260
+ if (p == e || tolower_ascii(*p) != *v) { // value is already lowercase
261
+ return false;
262
+ }
263
+ ++p;
264
+ ++v;
265
+ }
266
+
267
+ *b = p;
268
+ return true;
269
+ }
270
+
271
+ } // namespace
272
+
273
+ Expected<bool, ConversionCode> str_to_bool(StringPiece* src) noexcept {
274
+ auto b = src->begin(), e = src->end();
275
+ for (;; ++b) {
276
+ if (b >= e) {
277
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
278
+ }
279
+ if ((*b < '\t' || *b > '\r') && *b != ' ') {
280
+ break;
281
+ }
282
+ }
283
+
284
+ bool result;
285
+ auto len = size_t(e - b);
286
+ switch (*b) {
287
+ case '0':
288
+ case '1': {
289
+ result = false;
290
+ for (; b < e && isdigit(*b); ++b) {
291
+ if (result || (*b != '0' && *b != '1')) {
292
+ return makeUnexpected(ConversionCode::BOOL_OVERFLOW);
293
+ }
294
+ result = (*b == '1');
295
+ }
296
+ break;
297
+ }
298
+ case 'y':
299
+ case 'Y':
300
+ result = true;
301
+ if (!bool_str_cmp(&b, len, "yes")) {
302
+ ++b; // accept the single 'y' character
303
+ }
304
+ break;
305
+ case 'n':
306
+ case 'N':
307
+ result = false;
308
+ if (!bool_str_cmp(&b, len, "no")) {
309
+ ++b;
310
+ }
311
+ break;
312
+ case 't':
313
+ case 'T':
314
+ result = true;
315
+ if (!bool_str_cmp(&b, len, "true")) {
316
+ ++b;
317
+ }
318
+ break;
319
+ case 'f':
320
+ case 'F':
321
+ result = false;
322
+ if (!bool_str_cmp(&b, len, "false")) {
323
+ ++b;
324
+ }
325
+ break;
326
+ case 'o':
327
+ case 'O':
328
+ if (bool_str_cmp(&b, len, "on")) {
329
+ result = true;
330
+ } else if (bool_str_cmp(&b, len, "off")) {
331
+ result = false;
332
+ } else {
333
+ return makeUnexpected(ConversionCode::BOOL_INVALID_VALUE);
334
+ }
335
+ break;
336
+ default:
337
+ return makeUnexpected(ConversionCode::BOOL_INVALID_VALUE);
338
+ }
339
+
340
+ src->assign(b, e);
341
+
342
+ return result;
343
+ }
344
+
345
+ /// Uses `double_conversion` library to convert from string to a floating
346
+ /// point.
347
+ template <class Tgt>
348
+ Expected<Tgt, ConversionCode> str_to_floating_double_conversion(
349
+ StringPiece* src) noexcept {
350
+ using namespace double_conversion;
351
+ static StringToDoubleConverter conv(
352
+ StringToDoubleConverter::ALLOW_TRAILING_JUNK |
353
+ StringToDoubleConverter::ALLOW_LEADING_SPACES,
354
+ 0.0,
355
+ // return this for junk input string
356
+ std::numeric_limits<Tgt>::quiet_NaN(),
357
+ nullptr,
358
+ nullptr);
359
+
360
+ if (src->empty()) {
361
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
362
+ }
363
+
364
+ int length; // processed char count
365
+ auto result = std::is_same<Tgt, float>::value
366
+ ? conv.StringToFloat(src->data(), static_cast<int>(src->size()), &length)
367
+ : static_cast<Tgt>(conv.StringToDouble(
368
+ src->data(), static_cast<int>(src->size()), &length));
369
+
370
+ if (!std::isnan(result)) {
371
+ // If we get here with length = 0, the input string is empty.
372
+ // If we get here with result = 0.0, it's either because the string
373
+ // contained only whitespace, or because we had an actual zero value
374
+ // (with potential trailing junk). If it was only whitespace, we
375
+ // want to raise an error; length will point past the last character
376
+ // that was processed, so we need to check if that character was
377
+ // whitespace or not.
378
+ if (length == 0 ||
379
+ (result == 0.0 && std::isspace((*src)[size_t(length) - 1]))) {
380
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
381
+ }
382
+ if (length >= 2) {
383
+ const char* suffix = src->data() + length - 1;
384
+ // double_conversion doesn't update length correctly when there is an
385
+ // incomplete exponent specifier. Converting "12e-f-g" shouldn't consume
386
+ // any more than "12", but it will consume "12e-".
387
+
388
+ // "123-" should only parse "123"
389
+ if (*suffix == '-' || *suffix == '+') {
390
+ --suffix;
391
+ --length;
392
+ }
393
+ // "12e-f-g" or "12euro" should only parse "12"
394
+ if (*suffix == 'e' || *suffix == 'E') {
395
+ --length;
396
+ }
397
+ }
398
+ src->advance(size_t(length));
399
+ return Tgt(result);
400
+ }
401
+
402
+ auto* e = src->end();
403
+ auto* b = std::find_if_not(src->begin(), e, [](char c) {
404
+ return (c >= '\t' && c <= '\r') || c == ' ';
405
+ });
406
+ if (b == e) {
407
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
408
+ }
409
+ auto size = size_t(e - b);
410
+
411
+ bool negative = false;
412
+ if (*b == '-') {
413
+ negative = true;
414
+ ++b;
415
+ --size;
416
+ if (size == 0) {
417
+ return makeUnexpected(ConversionCode::STRING_TO_FLOAT_ERROR);
418
+ }
419
+ }
420
+ assert(size > 0);
421
+
422
+ result = 0.0;
423
+
424
+ switch (tolower_ascii(*b)) {
425
+ case 'i':
426
+ if (size >= 3 && tolower_ascii(b[1]) == 'n' &&
427
+ tolower_ascii(b[2]) == 'f') {
428
+ if (size >= 8 && tolower_ascii(b[3]) == 'i' &&
429
+ tolower_ascii(b[4]) == 'n' && tolower_ascii(b[5]) == 'i' &&
430
+ tolower_ascii(b[6]) == 't' && tolower_ascii(b[7]) == 'y') {
431
+ b += 8;
432
+ } else {
433
+ b += 3;
434
+ }
435
+ result = std::numeric_limits<Tgt>::infinity();
436
+ }
437
+ break;
438
+
439
+ case 'n':
440
+ if (size >= 3 && tolower_ascii(b[1]) == 'a' &&
441
+ tolower_ascii(b[2]) == 'n') {
442
+ b += 3;
443
+ result = std::numeric_limits<Tgt>::quiet_NaN();
444
+ }
445
+ break;
446
+
447
+ default:
448
+ break;
449
+ }
450
+
451
+ if (result == 0.0) {
452
+ // All bets are off
453
+ return makeUnexpected(ConversionCode::STRING_TO_FLOAT_ERROR);
454
+ }
455
+
456
+ if (negative) {
457
+ result = -result;
458
+ }
459
+
460
+ src->assign(b, e);
461
+
462
+ return Tgt(result);
463
+ }
464
+
465
+ /// Uses `fast_float::from_chars` to convert from string to an integer.
466
+ template <class Tgt>
467
+ Expected<Tgt, ConversionCode> str_to_floating_fast_float_from_chars(
468
+ StringPiece* src) noexcept {
469
+ if (src->empty()) {
470
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
471
+ }
472
+
473
+ // move through leading whitespace characters
474
+ auto* e = src->end();
475
+ auto* b = std::find_if_not(src->begin(), e, [](char c) {
476
+ return (c >= '\t' && c <= '\r') || c == ' ';
477
+ });
478
+ if (b == e) {
479
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
480
+ }
481
+
482
+ Tgt result;
483
+ auto [ptr, ec] = fast_float::from_chars(b, e, result);
484
+ bool isOutOfRange{ec == std::errc::result_out_of_range};
485
+ bool isOk{ec == std::errc()};
486
+ if (!isOk && !isOutOfRange) {
487
+ return makeUnexpected(ConversionCode::STRING_TO_FLOAT_ERROR);
488
+ }
489
+
490
+ auto numMatchedChars = ptr - src->data();
491
+ src->advance(numMatchedChars);
492
+
493
+ if (isOutOfRange) {
494
+ if (*b == '-') {
495
+ return -std::numeric_limits<Tgt>::infinity();
496
+ } else {
497
+ return std::numeric_limits<Tgt>::infinity();
498
+ }
499
+ }
500
+
501
+ return result;
502
+ }
503
+
504
+ template Expected<float, ConversionCode>
505
+ str_to_floating_fast_float_from_chars<float>(StringPiece* src) noexcept;
506
+ template Expected<double, ConversionCode>
507
+ str_to_floating_fast_float_from_chars<double>(StringPiece* src) noexcept;
508
+
509
+ /**
510
+ * StringPiece to double, with progress information. Alters the
511
+ * StringPiece parameter to munch the already-parsed characters.
512
+ */
513
+ template <class Tgt>
514
+ Expected<Tgt, ConversionCode> str_to_floating(StringPiece* src) noexcept {
515
+ #if defined(FOLLY_CONV_ATOD_MODE) && FOLLY_CONV_ATOD_MODE == 1
516
+ return detail::str_to_floating_fast_float_from_chars<Tgt>(src);
517
+ #else
518
+ return detail::str_to_floating_double_conversion<Tgt>(src);
519
+ #endif
520
+ }
521
+
522
+ template Expected<float, ConversionCode> str_to_floating<float>(
523
+ StringPiece* src) noexcept;
524
+ template Expected<double, ConversionCode> str_to_floating<double>(
525
+ StringPiece* src) noexcept;
526
+
527
+ namespace {
528
+
529
+ /**
530
+ * This class takes care of additional processing needed for signed values,
531
+ * like leading sign character and overflow checks.
532
+ */
533
+ template <typename T, bool IsSigned = is_signed_v<T>>
534
+ class SignedValueHandler;
535
+
536
+ template <typename T>
537
+ class SignedValueHandler<T, true> {
538
+ public:
539
+ ConversionCode init(const char*& b) {
540
+ negative_ = false;
541
+ if (!std::isdigit(*b)) {
542
+ if (*b == '-') {
543
+ negative_ = true;
544
+ } else if (FOLLY_UNLIKELY(*b != '+')) {
545
+ return ConversionCode::INVALID_LEADING_CHAR;
546
+ }
547
+ ++b;
548
+ }
549
+ return ConversionCode::SUCCESS;
550
+ }
551
+
552
+ ConversionCode overflow() {
553
+ return negative_ ? ConversionCode::NEGATIVE_OVERFLOW
554
+ : ConversionCode::POSITIVE_OVERFLOW;
555
+ }
556
+
557
+ template <typename U>
558
+ Expected<T, ConversionCode> finalize(U value) {
559
+ T rv;
560
+ if (negative_) {
561
+ FOLLY_PUSH_WARNING
562
+ FOLLY_MSVC_DISABLE_WARNING(4146)
563
+
564
+ // unary minus operator applied to unsigned type, result still unsigned
565
+ rv = T(-value);
566
+
567
+ FOLLY_POP_WARNING
568
+
569
+ if (FOLLY_UNLIKELY(rv > 0)) {
570
+ return makeUnexpected(ConversionCode::NEGATIVE_OVERFLOW);
571
+ }
572
+ } else {
573
+ rv = T(value);
574
+ if (FOLLY_UNLIKELY(rv < 0)) {
575
+ return makeUnexpected(ConversionCode::POSITIVE_OVERFLOW);
576
+ }
577
+ }
578
+ return rv;
579
+ }
580
+
581
+ private:
582
+ bool negative_;
583
+ };
584
+
585
+ // For unsigned types, we don't need any extra processing
586
+ template <typename T>
587
+ class SignedValueHandler<T, false> {
588
+ public:
589
+ ConversionCode init(const char*&) { return ConversionCode::SUCCESS; }
590
+
591
+ ConversionCode overflow() { return ConversionCode::POSITIVE_OVERFLOW; }
592
+
593
+ Expected<T, ConversionCode> finalize(T value) { return value; }
594
+ };
595
+
596
+ } // namespace
597
+
598
+ /**
599
+ * String represented as a pair of pointers to char to signed/unsigned
600
+ * integrals. Assumes NO whitespace before or after, and also that the
601
+ * string is composed entirely of digits (and an optional sign only for
602
+ * signed types). String may be empty, in which case digits_to returns
603
+ * an appropriate error.
604
+ */
605
+ template <class Tgt>
606
+ inline Expected<Tgt, ConversionCode> digits_to(
607
+ const char* b, const char* const e) noexcept {
608
+ using UT = make_unsigned_t<Tgt>;
609
+ assert(b <= e);
610
+
611
+ SignedValueHandler<Tgt> sgn;
612
+
613
+ auto err = sgn.init(b);
614
+ if (FOLLY_UNLIKELY(err != ConversionCode::SUCCESS)) {
615
+ return makeUnexpected(err);
616
+ }
617
+
618
+ auto size = size_t(e - b);
619
+
620
+ /* Although the string is entirely made of digits, we still need to
621
+ * check for overflow.
622
+ */
623
+ if (size > std::numeric_limits<UT>::digits10) {
624
+ // Leading zeros?
625
+ if (b < e && *b == '0') {
626
+ for (++b;; ++b) {
627
+ if (b == e) {
628
+ return Tgt(0); // just zeros, e.g. "0000"
629
+ }
630
+ if (*b != '0') {
631
+ size = size_t(e - b);
632
+ break;
633
+ }
634
+ }
635
+ }
636
+ if (size > std::numeric_limits<UT>::digits10 &&
637
+ (size != std::numeric_limits<UT>::digits10 + 1 ||
638
+ strncmp(b, MaxString<UT>::value, size) > 0)) {
639
+ return makeUnexpected(sgn.overflow());
640
+ }
641
+ }
642
+
643
+ // Here we know that the number won't overflow when
644
+ // converted. Proceed without checks.
645
+
646
+ UT result = 0;
647
+
648
+ for (; e - b >= 4; b += 4) {
649
+ result *= UT(10000);
650
+ const int32_t r0 = shift1000[static_cast<size_t>(b[0])];
651
+ const int32_t r1 = shift100[static_cast<size_t>(b[1])];
652
+ const int32_t r2 = shift10[static_cast<size_t>(b[2])];
653
+ const int32_t r3 = shift1[static_cast<size_t>(b[3])];
654
+ const auto sum = r0 + r1 + r2 + r3;
655
+ if (sum >= OOR) {
656
+ goto outOfRange;
657
+ }
658
+ result += UT(sum);
659
+ }
660
+
661
+ switch (e - b) {
662
+ case 3: {
663
+ const int32_t r0 = shift100[static_cast<size_t>(b[0])];
664
+ const int32_t r1 = shift10[static_cast<size_t>(b[1])];
665
+ const int32_t r2 = shift1[static_cast<size_t>(b[2])];
666
+ const auto sum = r0 + r1 + r2;
667
+ if (sum >= OOR) {
668
+ goto outOfRange;
669
+ }
670
+ result = UT(1000 * result + sum);
671
+ break;
672
+ }
673
+ case 2: {
674
+ const int32_t r0 = shift10[static_cast<size_t>(b[0])];
675
+ const int32_t r1 = shift1[static_cast<size_t>(b[1])];
676
+ const auto sum = r0 + r1;
677
+ if (sum >= OOR) {
678
+ goto outOfRange;
679
+ }
680
+ result = UT(100 * result + sum);
681
+ break;
682
+ }
683
+ case 1: {
684
+ const int32_t sum = shift1[static_cast<size_t>(b[0])];
685
+ if (sum >= OOR) {
686
+ goto outOfRange;
687
+ }
688
+ result = UT(10 * result + sum);
689
+ break;
690
+ }
691
+ default:
692
+ assert(b == e);
693
+ if (size == 0) {
694
+ return makeUnexpected(ConversionCode::NO_DIGITS);
695
+ }
696
+ break;
697
+ }
698
+
699
+ return sgn.finalize(result);
700
+
701
+ outOfRange:
702
+ return makeUnexpected(ConversionCode::NON_DIGIT_CHAR);
703
+ }
704
+
705
+ template Expected<char, ConversionCode> digits_to<char>(
706
+ const char*, const char*) noexcept;
707
+ template Expected<signed char, ConversionCode> digits_to<signed char>(
708
+ const char*, const char*) noexcept;
709
+ template Expected<unsigned char, ConversionCode> digits_to<unsigned char>(
710
+ const char*, const char*) noexcept;
711
+
712
+ template Expected<short, ConversionCode> digits_to<short>(
713
+ const char*, const char*) noexcept;
714
+ template Expected<unsigned short, ConversionCode> digits_to<unsigned short>(
715
+ const char*, const char*) noexcept;
716
+
717
+ template Expected<int, ConversionCode> digits_to<int>(
718
+ const char*, const char*) noexcept;
719
+ template Expected<unsigned int, ConversionCode> digits_to<unsigned int>(
720
+ const char*, const char*) noexcept;
721
+
722
+ template Expected<long, ConversionCode> digits_to<long>(
723
+ const char*, const char*) noexcept;
724
+ template Expected<unsigned long, ConversionCode> digits_to<unsigned long>(
725
+ const char*, const char*) noexcept;
726
+
727
+ template Expected<long long, ConversionCode> digits_to<long long>(
728
+ const char*, const char*) noexcept;
729
+ template Expected<unsigned long long, ConversionCode>
730
+ digits_to<unsigned long long>(const char*, const char*) noexcept;
731
+
732
+ #if FOLLY_HAVE_INT128_T
733
+ template Expected<__int128, ConversionCode> digits_to<__int128>(
734
+ const char*, const char*) noexcept;
735
+ template Expected<unsigned __int128, ConversionCode>
736
+ digits_to<unsigned __int128>(const char*, const char*) noexcept;
737
+ #endif
738
+
739
+ /**
740
+ * StringPiece to integrals, with progress information. Alters the
741
+ * StringPiece parameter to munch the already-parsed characters.
742
+ */
743
+ template <class Tgt>
744
+ Expected<Tgt, ConversionCode> str_to_integral(StringPiece* src) noexcept {
745
+ using UT = make_unsigned_t<Tgt>;
746
+
747
+ auto b = src->data(), past = src->data() + src->size();
748
+
749
+ for (;; ++b) {
750
+ if (FOLLY_UNLIKELY(b >= past)) {
751
+ return makeUnexpected(ConversionCode::EMPTY_INPUT_STRING);
752
+ }
753
+ if ((*b < '\t' || *b > '\r') && *b != ' ') {
754
+ break;
755
+ }
756
+ }
757
+
758
+ SignedValueHandler<Tgt> sgn;
759
+ auto err = sgn.init(b);
760
+
761
+ if (FOLLY_UNLIKELY(err != ConversionCode::SUCCESS)) {
762
+ return makeUnexpected(err);
763
+ }
764
+ if (is_signed_v<Tgt> && FOLLY_UNLIKELY(b >= past)) {
765
+ return makeUnexpected(ConversionCode::NO_DIGITS);
766
+ }
767
+ if (FOLLY_UNLIKELY(!isdigit(*b))) {
768
+ return makeUnexpected(ConversionCode::NON_DIGIT_CHAR);
769
+ }
770
+
771
+ auto m = findFirstNonDigit(b + 1, past);
772
+
773
+ auto tmp = digits_to<UT>(b, m);
774
+
775
+ if (FOLLY_UNLIKELY(!tmp.hasValue())) {
776
+ return makeUnexpected(
777
+ tmp.error() == ConversionCode::POSITIVE_OVERFLOW ? sgn.overflow()
778
+ : tmp.error());
779
+ }
780
+
781
+ auto res = sgn.finalize(tmp.value());
782
+
783
+ if (res.hasValue()) {
784
+ src->advance(size_t(m - src->data()));
785
+ }
786
+
787
+ return res;
788
+ }
789
+
790
+ template Expected<char, ConversionCode> str_to_integral<char>(
791
+ StringPiece* src) noexcept;
792
+ template Expected<signed char, ConversionCode> str_to_integral<signed char>(
793
+ StringPiece* src) noexcept;
794
+ template Expected<unsigned char, ConversionCode> str_to_integral<unsigned char>(
795
+ StringPiece* src) noexcept;
796
+
797
+ template Expected<short, ConversionCode> str_to_integral<short>(
798
+ StringPiece* src) noexcept;
799
+ template Expected<unsigned short, ConversionCode>
800
+ str_to_integral<unsigned short>(StringPiece* src) noexcept;
801
+
802
+ template Expected<int, ConversionCode> str_to_integral<int>(
803
+ StringPiece* src) noexcept;
804
+ template Expected<unsigned int, ConversionCode> str_to_integral<unsigned int>(
805
+ StringPiece* src) noexcept;
806
+
807
+ template Expected<long, ConversionCode> str_to_integral<long>(
808
+ StringPiece* src) noexcept;
809
+ template Expected<unsigned long, ConversionCode> str_to_integral<unsigned long>(
810
+ StringPiece* src) noexcept;
811
+
812
+ template Expected<long long, ConversionCode> str_to_integral<long long>(
813
+ StringPiece* src) noexcept;
814
+ template Expected<unsigned long long, ConversionCode>
815
+ str_to_integral<unsigned long long>(StringPiece* src) noexcept;
816
+
817
+ #if FOLLY_HAVE_INT128_T
818
+ template Expected<__int128, ConversionCode> str_to_integral<__int128>(
819
+ StringPiece* src) noexcept;
820
+ template Expected<unsigned __int128, ConversionCode>
821
+ str_to_integral<unsigned __int128>(StringPiece* src) noexcept;
822
+ #endif
823
+
824
+ #if defined(FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT) && \
825
+ FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT == 1
826
+ DtoaFlagsSet::DtoaFlagsSet(DtoaFlags flags) : flags_(flags) {}
827
+
828
+ bool DtoaFlagsSet::isSet(DtoaFlags flag) const {
829
+ return (flags_ & flag) == flag;
830
+ }
831
+
832
+ bool DtoaFlagsSet::emitPositiveExponentSign() const {
833
+ return isSet(DtoaFlags::EMIT_POSITIVE_EXPONENT_SIGN);
834
+ }
835
+
836
+ bool DtoaFlagsSet::emitTrailingDecimalPoint() const {
837
+ return isSet(DtoaFlags::EMIT_TRAILING_DECIMAL_POINT);
838
+ }
839
+
840
+ bool DtoaFlagsSet::emitTrailingZeroAfterPoint() const {
841
+ return isSet(DtoaFlags::EMIT_TRAILING_ZERO_AFTER_POINT);
842
+ }
843
+
844
+ bool DtoaFlagsSet::uniqueZero() const {
845
+ return isSet(DtoaFlags::UNIQUE_ZERO);
846
+ }
847
+
848
+ bool DtoaFlagsSet::noTrailingZero() const {
849
+ return isSet(DtoaFlags::NO_TRAILING_ZERO);
850
+ }
851
+
852
+ int ParsedDecimal::numPrecisionFigures() const {
853
+ int numInts = 0;
854
+
855
+ bool intIsZero = true;
856
+ int numLeadingIntZeros = 0;
857
+ bool isLeadingIntZero = true;
858
+ for (char* p = integerBegin; p && p != integerEnd; p++) {
859
+ if (*p == '0') {
860
+ if (isLeadingIntZero) {
861
+ numLeadingIntZeros += 1;
862
+ } else {
863
+ numInts += 1;
864
+ }
865
+ } else if (std::isdigit(*p)) {
866
+ intIsZero = false;
867
+ isLeadingIntZero = false;
868
+ numInts += 1;
869
+ } else {
870
+ folly::throw_exception<std::runtime_error>("non-numeric int");
871
+ }
872
+ }
873
+
874
+ bool fractionalIsZero = true;
875
+ int numFractional = 0;
876
+ int numLeadingFractionalZeros = 0;
877
+ bool isLeadingFractionalZero = true;
878
+ for (char* p = fractionalBegin; p && p != fractionalEnd; p++) {
879
+ if (*p == '0') {
880
+ if (isLeadingFractionalZero) {
881
+ numLeadingFractionalZeros += 1;
882
+ } else {
883
+ numFractional += 1;
884
+ }
885
+ } else if (std::isdigit(*p)) {
886
+ fractionalIsZero = false;
887
+ isLeadingFractionalZero = false;
888
+ numFractional += 1;
889
+ } else {
890
+ folly::throw_exception<std::runtime_error>("non-numeric frac");
891
+ }
892
+ }
893
+
894
+ if (intIsZero && fractionalIsZero) {
895
+ return numLeadingIntZeros + numLeadingFractionalZeros;
896
+ } else if (intIsZero) {
897
+ return numLeadingFractionalZeros + numFractional;
898
+ } else if (fractionalIsZero) {
899
+ return numInts + numLeadingFractionalZeros + numFractional;
900
+ } else {
901
+ return numInts + numLeadingFractionalZeros + numFractional;
902
+ }
903
+ }
904
+
905
+ std::optional<detail::ParsedDecimal::FractionalSuffix>
906
+ ParsedDecimal::fractionalSuffix() const {
907
+ if (exponentSymbol) {
908
+ if (exponentEnd) {
909
+ return std::make_pair(exponentSymbol, exponentEnd);
910
+ } else if (exponentSign) {
911
+ return std::make_pair(exponentSymbol, exponentSign);
912
+ } else {
913
+ return std::make_pair(exponentSymbol, exponentSymbol + 1);
914
+ }
915
+ } else if (exponentSign) {
916
+ if (exponentEnd) {
917
+ return std::make_pair(exponentSign, exponentEnd);
918
+ } else {
919
+ return std::make_pair(exponentSign, exponentSign + 1);
920
+ }
921
+ } else if (exponentBegin) {
922
+ if (exponentEnd) {
923
+ return std::make_pair(exponentEnd, exponentEnd);
924
+ } else {
925
+ return std::make_pair(exponentBegin, exponentSign + 1);
926
+ }
927
+ } else {
928
+ return std::nullopt;
929
+ }
930
+ }
931
+
932
+ void ParsedDecimal::shiftFractionalSuffixPtrs(size_t amount) {
933
+ if (exponentSymbol) {
934
+ exponentSymbol += amount;
935
+ }
936
+ if (exponentSign) {
937
+ exponentSign += amount;
938
+ }
939
+ if (exponentBegin) {
940
+ exponentBegin += amount;
941
+ }
942
+ if (exponentEnd) {
943
+ exponentEnd += amount;
944
+ }
945
+ }
946
+
947
+ namespace {
948
+
949
+ struct Stream : std::istream {
950
+ struct CharBuf : std::streambuf {
951
+ CharBuf(char* begin, char* end) { setg(begin, begin, end); }
952
+
953
+ char* pos() const { return gptr(); }
954
+ };
955
+ CharBuf& buf_;
956
+
957
+ explicit Stream(CharBuf& buf) : std::istream(&buf), buf_(buf) {}
958
+
959
+ char* pos() { return buf_.pos(); }
960
+
961
+ void advance() { get(); }
962
+ };
963
+
964
+ } // namespace
965
+
966
+ ParsedDecimal::ParsedDecimal(char* begin, char* end) {
967
+ if (!begin || !end || begin >= end) {
968
+ folly::throw_exception<std::invalid_argument>("invalid args");
969
+ }
970
+
971
+ Stream::CharBuf buf(begin, end);
972
+ Stream stream(buf);
973
+ if (stream.peek() == '-') {
974
+ negativeSign = stream.pos();
975
+ stream.advance();
976
+ }
977
+
978
+ if (char c = static_cast<unsigned char>(stream.peek()); std::isdigit(c)) { // [Windows - fix conversion from 'int' to 'char']
979
+ integerBegin = stream.pos();
980
+
981
+ while (!stream.eof() && std::isdigit(stream.peek())) {
982
+ stream.advance();
983
+ }
984
+
985
+ integerEnd = stream.pos();
986
+ }
987
+
988
+ if (stream.eof()) {
989
+ if (!integerBegin) {
990
+ folly::throw_exception<std::invalid_argument>("no int part");
991
+ }
992
+
993
+ return;
994
+ }
995
+
996
+ if (stream.peek() == '.') {
997
+ decimalPoint = stream.pos();
998
+ stream.advance();
999
+ }
1000
+
1001
+ if (stream.eof()) {
1002
+ if (!integerBegin) {
1003
+ folly::throw_exception<std::invalid_argument>("no int part");
1004
+ }
1005
+ return;
1006
+ }
1007
+
1008
+ if (char c = static_cast<unsigned char>(stream.peek()); std::isdigit(c)) { // [Windows - fix conversion from 'int' to 'char']
1009
+ fractionalBegin = stream.pos();
1010
+
1011
+ while (!stream.eof() && std::isdigit(stream.peek())) {
1012
+ stream.advance();
1013
+ }
1014
+
1015
+ fractionalEnd = stream.pos();
1016
+ }
1017
+
1018
+ if (!integerBegin && !fractionalBegin) {
1019
+ // there was no integer or fractional part.
1020
+ folly::throw_exception<std::invalid_argument>("no int or frac part");
1021
+ }
1022
+
1023
+ if (stream.eof()) {
1024
+ return;
1025
+ }
1026
+
1027
+ if (stream.peek() == 'e') {
1028
+ exponentSymbol = stream.pos();
1029
+ stream.advance();
1030
+
1031
+ if (stream.eof()) {
1032
+ return;
1033
+ }
1034
+
1035
+ if (char c = static_cast<unsigned char>(stream.peek()); c == '-' || c == '+') { // [Windows - fix conversion from 'int' to 'char']
1036
+ exponentSign = stream.pos();
1037
+ stream.advance();
1038
+ }
1039
+
1040
+ if (char c = static_cast<unsigned char>(stream.peek()); std::isdigit(c)) { // [Windows - fix conversion from 'int' to 'char']
1041
+ exponentBegin = stream.pos();
1042
+ while (!stream.eof() && std::isdigit(stream.peek())) {
1043
+ stream.advance();
1044
+ }
1045
+
1046
+ exponentEnd = stream.pos();
1047
+ }
1048
+ }
1049
+
1050
+ while (!stream.eof()) {
1051
+ int c = stream.get();
1052
+ if (c != '\0' && !std::isspace(c)) {
1053
+ folly::throw_exception<std::invalid_argument>("unexpected chars");
1054
+ }
1055
+ }
1056
+ }
1057
+
1058
+ std::pair<char*, char*> formatAsDoubleConversion(
1059
+ bool valueIsZero,
1060
+ DtoaMode mode,
1061
+ unsigned int numDigits,
1062
+ DtoaFlags flags,
1063
+ char* resultBegin,
1064
+ char* resultEnd,
1065
+ char* bufferEnd) {
1066
+ detail::ParsedDecimal parsedDecimal(resultBegin, resultEnd);
1067
+ detail::DtoaFlagsSet flagsSet{flags};
1068
+ if (parsedDecimal.negativeSign && flagsSet.uniqueZero() && valueIsZero) {
1069
+ // skip the negative sign (-) if it's a zero and UNIQUE_ZERO is set
1070
+ resultBegin += 1;
1071
+ }
1072
+
1073
+ unsigned int numTrailingZerosToAdd = 0;
1074
+ if (!flagsSet.noTrailingZero() && mode == DtoaMode::PRECISION) {
1075
+ // std::to_chars outputs no trailing zeros, so if it's not set, add
1076
+ // trailing zeros
1077
+ unsigned int numPrecisionFigures = parsedDecimal.numPrecisionFigures();
1078
+ if (numDigits > numPrecisionFigures) {
1079
+ numTrailingZerosToAdd = numDigits - numPrecisionFigures;
1080
+ }
1081
+ }
1082
+
1083
+ bool insertDecimalPoint = false;
1084
+ char* insertionPoint;
1085
+ if (parsedDecimal.fractionalEnd) {
1086
+ insertionPoint = parsedDecimal.fractionalEnd;
1087
+ } else if (parsedDecimal.decimalPoint) {
1088
+ insertionPoint = parsedDecimal.decimalPoint + 1;
1089
+ } else {
1090
+ insertionPoint = parsedDecimal.integerEnd;
1091
+ if (flagsSet.emitTrailingDecimalPoint() || numTrailingZerosToAdd > 0) {
1092
+ insertDecimalPoint = true;
1093
+ }
1094
+
1095
+ if (flagsSet.emitTrailingZeroAfterPoint()) {
1096
+ numTrailingZerosToAdd += 1;
1097
+ }
1098
+ }
1099
+
1100
+ unsigned int numCharsToInsert =
1101
+ numTrailingZerosToAdd + (insertDecimalPoint ? 1 : 0);
1102
+
1103
+ if (numCharsToInsert > 0) {
1104
+ if (resultEnd + numCharsToInsert > bufferEnd) {
1105
+ folly::throw_exception<std::invalid_argument>("buffer too small");
1106
+ }
1107
+
1108
+ std::optional<detail::ParsedDecimal::FractionalSuffix> fractionalsuffix =
1109
+ parsedDecimal.fractionalSuffix();
1110
+ if (fractionalsuffix.has_value()) {
1111
+ auto [fractionalSuffixBegin, fractionalSuffixEnd] = *fractionalsuffix;
1112
+ std::memmove(
1113
+ insertionPoint + numCharsToInsert,
1114
+ fractionalSuffixBegin,
1115
+ fractionalSuffixEnd - fractionalSuffixBegin);
1116
+ parsedDecimal.shiftFractionalSuffixPtrs(numCharsToInsert);
1117
+ }
1118
+
1119
+ resultEnd += numCharsToInsert;
1120
+ }
1121
+
1122
+ if (insertDecimalPoint) {
1123
+ *insertionPoint++ = '.';
1124
+ }
1125
+
1126
+ while (numTrailingZerosToAdd) {
1127
+ *insertionPoint++ = '0';
1128
+ numTrailingZerosToAdd -= 1;
1129
+ }
1130
+
1131
+ if (parsedDecimal.exponentSymbol) {
1132
+ // std::tochars outputs a lowercase e and it needs to be uppercase.
1133
+ *parsedDecimal.exponentSymbol = 'E';
1134
+ }
1135
+
1136
+ size_t charsToRemove = 0;
1137
+ char* removalBegin = nullptr;
1138
+ if (!flagsSet.emitPositiveExponentSign() && parsedDecimal.exponentSign &&
1139
+ *parsedDecimal.exponentSign == '+') {
1140
+ // std::to_chars outputs a + sign, remove it if the flag wasn't set.
1141
+ // e.g., 1.23e+45 -> 1.23e45
1142
+ removalBegin = parsedDecimal.exponentSign;
1143
+ charsToRemove += 1;
1144
+ }
1145
+
1146
+ if (char* p = parsedDecimal.exponentBegin; p && *p == '0') {
1147
+ // std::to_chars outputs a leading zero, remove it to match
1148
+ // double_conversion formating. e.g., 1.23e+04 -> 1.23e4
1149
+ if (!removalBegin) {
1150
+ removalBegin = p;
1151
+ }
1152
+
1153
+ while (p != parsedDecimal.exponentEnd && *p == '0') {
1154
+ charsToRemove += 1;
1155
+ p += 1;
1156
+ }
1157
+
1158
+ if (p == parsedDecimal.exponentEnd) {
1159
+ // they all were 0 digits. keep a single 0.
1160
+ charsToRemove -= 1;
1161
+ p -= 1;
1162
+ if (p == removalBegin) {
1163
+ // there was only one 0, keep it.
1164
+ removalBegin = nullptr;
1165
+ }
1166
+ }
1167
+ }
1168
+
1169
+ if (charsToRemove && removalBegin) {
1170
+ size_t len = resultEnd - (removalBegin + charsToRemove);
1171
+ std::memmove(removalBegin, removalBegin + charsToRemove, len);
1172
+ resultEnd -= charsToRemove;
1173
+ }
1174
+
1175
+ return std::pair{resultBegin, resultEnd};
1176
+ }
1177
+ #endif // FOLLY_CONV_AVALIABILITY_TO_CHARS_FLOATING_POINT
1178
+ } // namespace detail
1179
+
1180
+ ConversionError makeConversionError(ConversionCode code, StringPiece input) {
1181
+ using namespace detail;
1182
+ static_assert(
1183
+ std::is_unsigned<std::underlying_type<ConversionCode>::type>::value,
1184
+ "ConversionCode should be unsigned");
1185
+ auto index = static_cast<std::size_t>(code);
1186
+ FOLLY_SAFE_CHECK(index < kErrorStrings.size(), "code=", uint64_t(index));
1187
+ const ErrorString& err = kErrorStrings[index];
1188
+ if (code == ConversionCode::EMPTY_INPUT_STRING && input.empty()) {
1189
+ return {err.string, code};
1190
+ }
1191
+ std::string tmp(err.string);
1192
+ tmp.append(": ");
1193
+ if (err.quote) {
1194
+ tmp.append(1, '"');
1195
+ }
1196
+ if (!input.empty()) {
1197
+ tmp.append(input.data(), input.size());
1198
+ }
1199
+ if (err.quote) {
1200
+ tmp.append(1, '"');
1201
+ }
1202
+ return {tmp, code};
1203
+ }
1204
+
1205
+ } // namespace folly