@lucent-lang/lucent 0.0.4 → 0.1.1

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 (152) hide show
  1. package/README.md +97 -0
  2. package/app.plugin.js +46 -10
  3. package/dist/{bench-CR3E7e2e.js → bench-eEez4jhQ.js} +10 -6
  4. package/dist/{build-CAIrRSYA.js → build-CpUjeHFz.js} +1 -1
  5. package/dist/{build-check-QozuNJm5.js → build-check-BA1ZEp9s.js} +28 -13
  6. package/dist/{check-1SCmYlqA.js → check-BZx3FgI6.js} +1 -1
  7. package/dist/cli.js +62 -13
  8. package/dist/{codes-CIuwXt1S.js → codes-D-6LxUqD.js} +163 -7
  9. package/dist/compiler.js +4 -4
  10. package/dist/{dashboard-B-NzjjaN.js → dashboard-CC-HXhcd.js} +2 -2
  11. package/dist/{dev-BYWMP7oC.js → dev-DI5yL8zx.js} +62 -23
  12. package/dist/{diagnostic-BM9sXmwl.js → diagnostic-BvwLZQS1.js} +3 -1
  13. package/dist/{doctor-C0PrfWT6.js → doctor-CTAX3euc.js} +1 -1
  14. package/dist/{doctor-DdR4JnVc.js → doctor-CrgOAV5L.js} +1 -1
  15. package/dist/{explain--vV1oaRl.js → explain-Byit07F-.js} +1 -1
  16. package/dist/{packages-HyskKIsY.js → packages-CSmKeaAh.js} +2 -33
  17. package/dist/pipeline-BM_VM2X_.js +700 -0
  18. package/dist/project-BKNoTEEp.js +342 -0
  19. package/dist/sdk-coverage-iiv3JqMp.js +113 -0
  20. package/dist/sdk-diff-ByJ1Gw-F.js +109 -0
  21. package/dist/sdk-lock-BQn7IyRs.js +38 -0
  22. package/dist/{sdk-prefetch-mo04JDZV.js → sdk-prefetch-Bv2pNega.js} +2 -2
  23. package/dist/{sdk-search-Iv4K3-8a.js → sdk-search-CPGJm_Ne.js} +2 -2
  24. package/dist/{sdk-show-CkrdlqlP.js → sdk-show-BUkLqRnA.js} +5 -4
  25. package/dist/sdk-usage-0ZFMAYg1.js +95 -0
  26. package/dist/src-ChnmWLwn.js +40851 -0
  27. package/dist/trace-Bi4hkmPx.js +139 -0
  28. package/lib/core.cjs +368 -1
  29. package/lib/sdk/android.d.ts +54 -1
  30. package/lib/sdk/compose.d.ts +94 -0
  31. package/lib/sdk/compose.schemas.json.gz +0 -0
  32. package/lib/sdk/core.d.ts +201 -0
  33. package/lib/sdk/ios.d.ts +75 -2
  34. package/lib/sdk/ui.d.ts +129 -0
  35. package/metro/transformer.cjs +11 -2
  36. package/package.json +4 -3
  37. package/runtime/cpp/lucent/abort.cpp +59 -11
  38. package/runtime/cpp/lucent/abort.h +22 -6
  39. package/runtime/cpp/lucent/array.h +12 -2
  40. package/runtime/cpp/lucent/async.h +101 -21
  41. package/runtime/cpp/lucent/bigint.cpp +898 -0
  42. package/runtime/cpp/lucent/bigint.h +302 -0
  43. package/runtime/cpp/lucent/buffer.cpp +228 -0
  44. package/runtime/cpp/lucent/buffer.h +328 -0
  45. package/runtime/cpp/lucent/builtins.cpp +4 -1
  46. package/runtime/cpp/lucent/bytes.h +21 -2
  47. package/runtime/cpp/lucent/callback.cpp +29 -0
  48. package/runtime/cpp/lucent/callback.h +230 -0
  49. package/runtime/cpp/lucent/compute.cpp +370 -0
  50. package/runtime/cpp/lucent/compute.h +455 -0
  51. package/runtime/cpp/lucent/conversions.h +111 -0
  52. package/runtime/cpp/lucent/core.h +16 -5
  53. package/runtime/cpp/lucent/equality.h +107 -28
  54. package/runtime/cpp/lucent/execution.cpp +416 -0
  55. package/runtime/cpp/lucent/execution.h +270 -0
  56. package/runtime/cpp/lucent/extension.cpp +97 -0
  57. package/runtime/cpp/lucent/extension.h +210 -0
  58. package/runtime/cpp/lucent/helpers.h +12 -5
  59. package/runtime/cpp/lucent/items.h +52 -0
  60. package/runtime/cpp/lucent/jserror.cpp +9 -0
  61. package/runtime/cpp/lucent/jserror.h +11 -0
  62. package/runtime/cpp/lucent/jsi/convert.cpp +138 -0
  63. package/runtime/cpp/lucent/jsi/convert.h +128 -59
  64. package/runtime/cpp/lucent/jsi/host.cpp +213 -35
  65. package/runtime/cpp/lucent/jsi/host.h +116 -16
  66. package/runtime/cpp/lucent/json.h +19 -1
  67. package/runtime/cpp/lucent/lifecycle.cpp +260 -0
  68. package/runtime/cpp/lucent/lifecycle.h +124 -0
  69. package/runtime/cpp/lucent/lucent.h +7 -0
  70. package/runtime/cpp/lucent/map.h +41 -7
  71. package/runtime/cpp/lucent/native.cpp +35 -47
  72. package/runtime/cpp/lucent/native.h +116 -26
  73. package/runtime/cpp/lucent/number.cpp +38 -38
  74. package/runtime/cpp/lucent/number.h +33 -0
  75. package/runtime/cpp/lucent/operation.h +65 -0
  76. package/runtime/cpp/lucent/ops.h +14 -6
  77. package/runtime/cpp/lucent/platform/android.cpp +223 -10
  78. package/runtime/cpp/lucent/platform/android.h +227 -4
  79. package/runtime/cpp/lucent/platform/android_activity.cpp +258 -0
  80. package/runtime/cpp/lucent/platform/android_requests.h +140 -0
  81. package/runtime/cpp/lucent/platform/compose.h +256 -0
  82. package/runtime/cpp/lucent/platform/ios.h +325 -25
  83. package/runtime/cpp/lucent/platform/ios.mm +1 -14
  84. package/runtime/cpp/lucent/platform/ios_ui.h +192 -0
  85. package/runtime/cpp/lucent/platform/ios_ui.mm +454 -0
  86. package/runtime/cpp/lucent/platform/swiftui.h +190 -0
  87. package/runtime/cpp/lucent/presentation.cpp +11 -0
  88. package/runtime/cpp/lucent/presentation.h +109 -0
  89. package/runtime/cpp/lucent/reactive.cpp +406 -0
  90. package/runtime/cpp/lucent/reactive.h +566 -0
  91. package/runtime/cpp/lucent/report.cpp +40 -0
  92. package/runtime/cpp/lucent/report.h +16 -0
  93. package/runtime/cpp/lucent/resource.cpp +83 -0
  94. package/runtime/cpp/lucent/resource.h +75 -0
  95. package/runtime/cpp/lucent/scheduler.cpp +38 -124
  96. package/runtime/cpp/lucent/scheduler.h +102 -83
  97. package/runtime/cpp/lucent/scope.cpp +308 -0
  98. package/runtime/cpp/lucent/scope.h +452 -0
  99. package/runtime/cpp/lucent/sizing.h +263 -0
  100. package/runtime/cpp/lucent/slots.h +231 -0
  101. package/runtime/cpp/lucent/trace.cpp +539 -0
  102. package/runtime/cpp/lucent/trace.h +251 -0
  103. package/runtime/cpp/lucent/transport.cpp +9 -0
  104. package/runtime/cpp/lucent/transport.h +341 -0
  105. package/runtime/cpp/lucent/view.cpp +123 -0
  106. package/runtime/cpp/lucent/view.h +157 -0
  107. package/runtime/cpp/rn/LucentComponentView.h +121 -0
  108. package/runtime/cpp/rn/LucentComponentView.mm +479 -0
  109. package/runtime/cpp/rn/LucentModule.cpp +37 -7
  110. package/runtime/cpp/rn/LucentModule.h +3 -0
  111. package/runtime/cpp/rn/LucentViewChildren.h +80 -0
  112. package/runtime/cpp/rn/LucentViewChildren.mm +211 -0
  113. package/runtime/cpp/rn/LucentViewRegistry.h +62 -0
  114. package/runtime/cpp/rn/LucentViewRequests.cpp +91 -0
  115. package/runtime/cpp/rn/LucentViewRequests.h +104 -0
  116. package/runtime/cpp/rn/LucentViewSizing.h +345 -0
  117. package/runtime/cpp/rn/LucentViewSlots.h +242 -0
  118. package/runtime/cpp/rn/LucentViewValues.h +125 -0
  119. package/runtime/cpp/rn/LucentViews.h +440 -0
  120. package/runtime/cpp/rn/LucentViewsAndroid.cpp +439 -0
  121. package/runtime/cpp/rn/LucentViewsAndroid.h +138 -0
  122. package/runtime/cpp/third_party/dragonbox/LICENSE-Boost +23 -0
  123. package/runtime/cpp/third_party/dragonbox/README.md +16 -0
  124. package/runtime/cpp/third_party/dragonbox/dragonbox.h +4440 -0
  125. package/runtime/js/index.d.ts +11 -1
  126. package/runtime/js/index.js +84 -8
  127. package/runtime/js/views.d.ts +38 -0
  128. package/runtime/js/views.js +226 -0
  129. package/runtime/native/android/CMakeLists.txt +4 -1
  130. package/runtime/native/android/src/compose/java/dev/lucent/compose/CompositionRules.kt +44 -0
  131. package/runtime/native/android/src/compose/java/dev/lucent/compose/LucentComposition.kt +161 -0
  132. package/runtime/native/android/src/main/java/dev/lucent/LucentActivities.java +292 -0
  133. package/runtime/native/android/src/main/java/dev/lucent/LucentChildren.java +174 -0
  134. package/runtime/native/android/src/main/java/dev/lucent/LucentHostView.java +232 -0
  135. package/runtime/native/android/src/main/java/dev/lucent/LucentInitializer.java +46 -0
  136. package/runtime/native/android/src/main/java/dev/lucent/LucentPackage.java +4 -3
  137. package/runtime/native/android/src/main/java/dev/lucent/LucentRequestActivity.java +92 -0
  138. package/runtime/native/android/src/main/java/dev/lucent/LucentSlotView.java +102 -0
  139. package/runtime/native/android/src/main/java/dev/lucent/LucentViewManager.java +149 -0
  140. package/runtime/native/android/src/main/java/dev/lucent/LucentViewManagers.java +16 -0
  141. package/runtime/native/android/src/main/java/dev/lucent/LucentViews.java +44 -0
  142. package/runtime/test/jsi/harness.cpp +9 -0
  143. package/schemas/build.schema.json +96 -1
  144. package/schemas/check.schema.json +56 -1
  145. package/schemas/lucent.schema.json +495 -9
  146. package/schemas/sdk-diff.schema.json +70 -0
  147. package/schemas/sdk-lock.schema.json +67 -0
  148. package/ts-plugin/index.js +85 -4
  149. package/dist/pipeline-CH7-2cxu.js +0 -232
  150. package/dist/project-D8tEet0k.js +0 -150
  151. package/dist/sdk-coverage-BoW_3Efd.js +0 -64
  152. package/dist/src-BD7f1_aZ.js +0 -11493
@@ -0,0 +1,898 @@
1
+ #include "bigint.h"
2
+
3
+ #include <algorithm>
4
+ #include <bit>
5
+ #include <cmath>
6
+ #include <limits>
7
+ #include <string>
8
+ #include <vector>
9
+
10
+ #include "jserror.h"
11
+ #include "number.h"
12
+
13
+ namespace lucent {
14
+
15
+ using Mag = std::vector<uint32_t>;
16
+
17
+ struct BigInt::Big {
18
+ bool negative;
19
+ Mag magnitude;
20
+ };
21
+
22
+ namespace {
23
+
24
+ /// V8's limit: beyond it a result throws a RangeError instead of exhausting
25
+ /// memory.
26
+ constexpr uint64_t kMaxBits = uint64_t{1} << 30;
27
+
28
+ constexpr uint64_t kLimb = uint64_t{1} << 32;
29
+
30
+ [[noreturn]] void tooBig() { throwRangeError("Maximum BigInt size exceeded"); }
31
+
32
+ [[noreturn]] void syntaxError(const std::string& text) {
33
+ throwError(String::fromLatin1("SyntaxError"), String::fromUtf8("Cannot convert " + text + " to a BigInt"));
34
+ }
35
+
36
+ /// A value as a sign and a magnitude, for the paths beyond int64.
37
+ struct Parts {
38
+ bool negative = false;
39
+ Mag magnitude;
40
+ };
41
+
42
+ void trim(Mag& m) {
43
+ while (!m.empty() && m.back() == 0) m.pop_back();
44
+ }
45
+
46
+ Mag magnitudeOf(uint64_t u) {
47
+ Mag m;
48
+ if (u) m.push_back(static_cast<uint32_t>(u));
49
+ if (u >> 32) m.push_back(static_cast<uint32_t>(u >> 32));
50
+ return m;
51
+ }
52
+
53
+ uint64_t bitLength(const Mag& m) {
54
+ if (m.empty()) return 0;
55
+
56
+ return (m.size() - 1) * 32 + (32 - static_cast<uint64_t>(std::countl_zero(m.back())));
57
+ }
58
+
59
+ int compareMagnitudes(const Mag& a, const Mag& b) {
60
+ if (a.size() != b.size()) return a.size() < b.size() ? -1 : 1;
61
+
62
+ for (size_t i = a.size(); i-- > 0;) {
63
+ if (a[i] != b[i]) return a[i] < b[i] ? -1 : 1;
64
+ }
65
+
66
+ return 0;
67
+ }
68
+
69
+ Mag addMagnitudes(const Mag& a, const Mag& b) {
70
+ const Mag& longer = a.size() >= b.size() ? a : b;
71
+ const Mag& shorter = a.size() >= b.size() ? b : a;
72
+
73
+ Mag out(longer.size() + 1);
74
+ uint64_t carry = 0;
75
+
76
+ for (size_t i = 0; i < longer.size(); i++) {
77
+ uint64_t sum = uint64_t{longer[i]} + (i < shorter.size() ? shorter[i] : 0) + carry;
78
+ out[i] = static_cast<uint32_t>(sum);
79
+ carry = sum >> 32;
80
+ }
81
+
82
+ out[longer.size()] = static_cast<uint32_t>(carry);
83
+ trim(out);
84
+ return out;
85
+ }
86
+
87
+ /// a - b, with a >= b.
88
+ Mag subtractMagnitudes(const Mag& a, const Mag& b) {
89
+ Mag out(a.size());
90
+ int64_t borrow = 0;
91
+
92
+ for (size_t i = 0; i < a.size(); i++) {
93
+ int64_t diff = int64_t{a[i]} - (i < b.size() ? int64_t{b[i]} : 0) - borrow;
94
+ borrow = diff < 0 ? 1 : 0;
95
+ out[i] = static_cast<uint32_t>(diff + (borrow ? static_cast<int64_t>(kLimb) : 0));
96
+ }
97
+
98
+ trim(out);
99
+ return out;
100
+ }
101
+
102
+ Mag multiplyMagnitudes(const Mag& a, const Mag& b) {
103
+ if (a.empty() || b.empty()) return {};
104
+
105
+ if (bitLength(a) + bitLength(b) > kMaxBits + 1) tooBig();
106
+
107
+ Mag out(a.size() + b.size());
108
+
109
+ for (size_t i = 0; i < a.size(); i++) {
110
+ uint64_t carry = 0;
111
+
112
+ for (size_t j = 0; j < b.size(); j++) {
113
+ uint64_t t = uint64_t{a[i]} * b[j] + out[i + j] + carry;
114
+ out[i + j] = static_cast<uint32_t>(t);
115
+ carry = t >> 32;
116
+ }
117
+
118
+ out[i + b.size()] = static_cast<uint32_t>(carry);
119
+ }
120
+
121
+ trim(out);
122
+ return out;
123
+ }
124
+
125
+ /// m = m * factor + addend, in place.
126
+ void multiplyAdd(Mag& m, uint32_t factor, uint32_t addend) {
127
+ uint64_t carry = addend;
128
+
129
+ for (auto& limb : m) {
130
+ uint64_t t = uint64_t{limb} * factor + carry;
131
+ limb = static_cast<uint32_t>(t);
132
+ carry = t >> 32;
133
+ }
134
+
135
+ if (carry) m.push_back(static_cast<uint32_t>(carry));
136
+ }
137
+
138
+ /// m /= divisor in place; returns the remainder.
139
+ uint32_t divideSmall(Mag& m, uint32_t divisor) {
140
+ uint64_t rest = 0;
141
+
142
+ for (size_t i = m.size(); i-- > 0;) {
143
+ uint64_t cur = (rest << 32) | m[i];
144
+ m[i] = static_cast<uint32_t>(cur / divisor);
145
+ rest = cur % divisor;
146
+ }
147
+
148
+ trim(m);
149
+ return static_cast<uint32_t>(rest);
150
+ }
151
+
152
+ /// Quotient and remainder of magnitudes (Knuth's algorithm D, as in
153
+ /// Hacker's Delight's divmnu).
154
+ void divideMagnitudes(const Mag& u, const Mag& v, Mag& quotient, Mag& remainder) {
155
+ if (compareMagnitudes(u, v) < 0) {
156
+ quotient.clear();
157
+ remainder = u;
158
+ return;
159
+ }
160
+
161
+ if (v.size() == 1) {
162
+ quotient = u;
163
+ uint32_t r = divideSmall(quotient, v[0]);
164
+ remainder = magnitudeOf(r);
165
+ return;
166
+ }
167
+
168
+ const size_t n = v.size();
169
+ const size_t m = u.size();
170
+ const int s = std::countl_zero(v.back());
171
+
172
+ // Normalized so that the divisor's top limb has its high bit set.
173
+ Mag vn(n);
174
+ for (size_t i = n - 1; i > 0; i--) vn[i] = s ? (v[i] << s) | (v[i - 1] >> (32 - s)) : v[i];
175
+ vn[0] = v[0] << s;
176
+
177
+ Mag un(m + 1);
178
+ un[m] = s ? u[m - 1] >> (32 - s) : 0;
179
+ for (size_t i = m - 1; i > 0; i--) un[i] = s ? (u[i] << s) | (u[i - 1] >> (32 - s)) : u[i];
180
+ un[0] = u[0] << s;
181
+
182
+ quotient.assign(m - n + 1, 0);
183
+
184
+ for (size_t j = m - n + 1; j-- > 0;) {
185
+ uint64_t numerator = (uint64_t{un[j + n]} << 32) | un[j + n - 1];
186
+ uint64_t qhat = numerator / vn[n - 1];
187
+ uint64_t rhat = numerator % vn[n - 1];
188
+
189
+ while (qhat >= kLimb || qhat * vn[n - 2] > ((rhat << 32) | un[j + n - 2])) {
190
+ qhat--;
191
+ rhat += vn[n - 1];
192
+ if (rhat >= kLimb) break;
193
+ }
194
+
195
+ // Multiply and subtract.
196
+ int64_t borrow = 0;
197
+ int64_t t = 0;
198
+ for (size_t i = 0; i < n; i++) {
199
+ uint64_t p = qhat * vn[i];
200
+ t = int64_t{un[i + j]} - borrow - static_cast<int64_t>(p & 0xFFFFFFFFu);
201
+ un[i + j] = static_cast<uint32_t>(t);
202
+ borrow = static_cast<int64_t>(p >> 32) - (t >> 32);
203
+ }
204
+
205
+ t = int64_t{un[j + n]} - borrow;
206
+ un[j + n] = static_cast<uint32_t>(t);
207
+ quotient[j] = static_cast<uint32_t>(qhat);
208
+
209
+ // Subtracted too much: add one divisor back.
210
+ if (t < 0) {
211
+ quotient[j]--;
212
+
213
+ uint64_t carry = 0;
214
+ for (size_t i = 0; i < n; i++) {
215
+ uint64_t sum = uint64_t{un[i + j]} + vn[i] + carry;
216
+ un[i + j] = static_cast<uint32_t>(sum);
217
+ carry = sum >> 32;
218
+ }
219
+
220
+ un[j + n] = static_cast<uint32_t>(uint64_t{un[j + n]} + carry);
221
+ }
222
+ }
223
+
224
+ remainder.assign(n, 0);
225
+ for (size_t i = 0; i < n; i++) remainder[i] = s ? (un[i] >> s) | (un[i + 1] << (32 - s)) : un[i];
226
+
227
+ trim(quotient);
228
+ trim(remainder);
229
+ }
230
+
231
+ Mag shiftLeftMagnitude(const Mag& m, uint64_t bits) {
232
+ if (m.empty()) return {};
233
+
234
+ if (bitLength(m) + bits > kMaxBits) tooBig();
235
+
236
+ size_t limbs = static_cast<size_t>(bits / 32);
237
+ int rest = static_cast<int>(bits % 32);
238
+
239
+ Mag out(m.size() + limbs + 1, 0);
240
+ for (size_t i = 0; i < m.size(); i++) {
241
+ out[i + limbs] |= m[i] << rest;
242
+ if (rest) out[i + limbs + 1] |= m[i] >> (32 - rest);
243
+ }
244
+
245
+ trim(out);
246
+ return out;
247
+ }
248
+
249
+ Mag shiftRightMagnitude(const Mag& m, uint64_t bits) {
250
+ if (bits >= uint64_t{m.size()} * 32) return {};
251
+
252
+ size_t limbs = static_cast<size_t>(bits / 32);
253
+ int rest = static_cast<int>(bits % 32);
254
+
255
+ Mag out(m.size() - limbs);
256
+ for (size_t i = 0; i < out.size(); i++) {
257
+ uint32_t low = m[i + limbs] >> rest;
258
+ uint32_t high = rest && i + limbs + 1 < m.size() ? m[i + limbs + 1] << (32 - rest) : 0;
259
+ out[i] = low | high;
260
+ }
261
+
262
+ trim(out);
263
+ return out;
264
+ }
265
+
266
+ /// Two's complement in `width` limbs (sign-extended).
267
+ Mag twosComplement(const Parts& p, size_t width) {
268
+ Mag out(width, p.negative ? 0xFFFFFFFFu : 0);
269
+
270
+ if (!p.negative) {
271
+ std::copy(p.magnitude.begin(), p.magnitude.end(), out.begin());
272
+ return out;
273
+ }
274
+
275
+ // -m is ~(m - 1).
276
+ Mag less = subtractMagnitudes(p.magnitude, Mag{1});
277
+ for (size_t i = 0; i < less.size(); i++) out[i] = ~less[i];
278
+
279
+ return out;
280
+ }
281
+
282
+ /// The value of `limbs` read as two's complement.
283
+ Parts fromTwosComplement(Mag limbs) {
284
+ Parts p;
285
+ p.negative = !limbs.empty() && (limbs.back() & 0x80000000u);
286
+
287
+ if (p.negative) {
288
+ for (auto& limb : limbs) limb = ~limb;
289
+ trim(limbs);
290
+ limbs = addMagnitudes(limbs, Mag{1});
291
+ }
292
+
293
+ trim(limbs);
294
+ p.magnitude = std::move(limbs);
295
+ return p;
296
+ }
297
+
298
+ /// ToIndex, as BigInt.asIntN and asUintN convert their `bits`.
299
+ uint64_t toIndex(double bits) {
300
+ double t = std::isnan(bits) ? 0 : std::trunc(bits);
301
+ if (!(t >= 0 && t <= 9007199254740991.0)) throwRangeError("Invalid value: not (convertible to) a safe integer");
302
+
303
+ return static_cast<uint64_t>(t);
304
+ }
305
+
306
+ int digitValue(char16_t c) {
307
+ if (c >= '0' && c <= '9') return c - '0';
308
+ if (c >= 'a' && c <= 'z') return c - 'a' + 10;
309
+ if (c >= 'A' && c <= 'Z') return c - 'A' + 10;
310
+ return 99;
311
+ }
312
+
313
+ /// radix^k, the largest power below 2^32, and k.
314
+ std::pair<uint32_t, int> chunkOf(uint32_t radix) {
315
+ uint64_t power = radix;
316
+ int digits = 1;
317
+
318
+ while (power * radix < kLimb) {
319
+ power *= radix;
320
+ digits++;
321
+ }
322
+
323
+ return {static_cast<uint32_t>(power), digits};
324
+ }
325
+
326
+ } // namespace
327
+
328
+ /// Parts and canonical construction, for the paths beyond int64.
329
+ struct BigIntAccess {
330
+ static Parts parts(const BigInt& x) {
331
+ if (x.big_) return {x.big_->negative, x.big_->magnitude};
332
+
333
+ bool negative = x.small_ < 0;
334
+ uint64_t u = negative ? static_cast<uint64_t>(-(x.small_ + 1)) + 1 : static_cast<uint64_t>(x.small_);
335
+ return {negative, magnitudeOf(u)};
336
+ }
337
+
338
+ static const Mag& magnitude(const BigInt& x) { return x.big_->magnitude; }
339
+
340
+ static bool isBig(const BigInt& x) { return x.big_ != nullptr; }
341
+
342
+ static int64_t small(const BigInt& x) { return x.small_; }
343
+
344
+ static bool negative(const BigInt& x) { return x.big_ ? x.big_->negative : x.small_ < 0; }
345
+
346
+ /// The canonical value: inline whenever it fits in int64.
347
+ static BigInt make(bool negative, Mag magnitude) {
348
+ trim(magnitude);
349
+
350
+ if (magnitude.size() <= 2) {
351
+ uint64_t u = magnitude.empty() ? 0 : magnitude[0];
352
+ if (magnitude.size() == 2) u |= uint64_t{magnitude[1]} << 32;
353
+
354
+ if (!negative && u <= static_cast<uint64_t>(INT64_MAX)) return BigInt::fromInt64(static_cast<int64_t>(u));
355
+ if (negative && u <= uint64_t{1} << 63) return BigInt::fromInt64(u == uint64_t{1} << 63 ? INT64_MIN : -static_cast<int64_t>(u));
356
+ }
357
+
358
+ if (bitLength(magnitude) > kMaxBits) tooBig();
359
+
360
+ BigInt out;
361
+ out.big_ = std::make_shared<const BigInt::Big>(BigInt::Big{negative, std::move(magnitude)});
362
+ return out;
363
+ }
364
+
365
+ static BigInt make(Parts p) { return make(p.negative, std::move(p.magnitude)); }
366
+ };
367
+
368
+ using A = BigIntAccess;
369
+
370
+ // --- construction ------------------------------------------------------------------
371
+
372
+ BigInt BigInt::fromUint64Beyond(uint64_t value) { return A::make(false, magnitudeOf(value)); }
373
+
374
+ BigInt BigInt::fromDouble(double value) {
375
+ if (!std::isfinite(value) || std::trunc(value) != value) {
376
+ throwRangeError(("The number " + numberToString(value).toUtf8() + " cannot be converted to a BigInt because it is not an integer").c_str());
377
+ }
378
+
379
+ if (value >= -9223372036854775808.0 && value < 9223372036854775808.0) return fromInt64(static_cast<int64_t>(value));
380
+
381
+ // |value| >= 2^63: a 53-bit integer times a power of two.
382
+ int exponent;
383
+ double fraction = std::frexp(std::fabs(value), &exponent);
384
+ auto mantissa = static_cast<uint64_t>(std::ldexp(fraction, 53));
385
+
386
+ return A::make(value < 0, shiftLeftMagnitude(magnitudeOf(mantissa), static_cast<uint64_t>(exponent - 53)));
387
+ }
388
+
389
+ BigInt BigInt::fromDigits(std::string_view text, int radix) {
390
+ std::string_view digits = text;
391
+ bool negative = !digits.empty() && digits[0] == '-';
392
+ if (negative) digits.remove_prefix(1);
393
+
394
+ if (digits.empty() || radix < 2 || radix > 36) syntaxError(std::string(text));
395
+
396
+ // Within 64 bits, no allocation.
397
+ uint64_t value = 0;
398
+ size_t i = 0;
399
+
400
+ for (; i < digits.size(); i++) {
401
+ int d = digitValue(static_cast<unsigned char>(digits[i]));
402
+ if (d >= radix) syntaxError(std::string(text));
403
+
404
+ uint64_t next;
405
+ if (__builtin_mul_overflow(value, static_cast<uint64_t>(radix), &next) || __builtin_add_overflow(next, static_cast<uint64_t>(d), &next)) break;
406
+
407
+ value = next;
408
+ }
409
+
410
+ if (i == digits.size()) {
411
+ if (!negative) return fromUint64(value);
412
+ if (value <= uint64_t{1} << 63) return fromInt64(value == uint64_t{1} << 63 ? INT64_MIN : -static_cast<int64_t>(value));
413
+
414
+ return A::make(true, magnitudeOf(value));
415
+ }
416
+
417
+ Mag m = magnitudeOf(value);
418
+ int perChunk = chunkOf(static_cast<uint32_t>(radix)).second;
419
+
420
+ while (i < digits.size()) {
421
+ uint32_t chunk = 0;
422
+ uint32_t factor = 1;
423
+
424
+ for (int k = 0; k < perChunk && i < digits.size(); k++, i++) {
425
+ int d = digitValue(static_cast<unsigned char>(digits[i]));
426
+ if (d >= radix) syntaxError(std::string(text));
427
+
428
+ chunk = chunk * radix + static_cast<uint32_t>(d);
429
+ factor *= static_cast<uint32_t>(radix);
430
+ }
431
+
432
+ multiplyAdd(m, factor, chunk);
433
+ }
434
+
435
+ return A::make(negative, std::move(m));
436
+ }
437
+
438
+ namespace {
439
+
440
+ /// StringToBigInt over any code units.
441
+ template <class Unit>
442
+ BigInt parseUnits(const Unit* units, size_t length) {
443
+ size_t begin = 0;
444
+ size_t end = length;
445
+
446
+ while (begin < end && isJsWhitespace(static_cast<char16_t>(units[begin]))) begin++;
447
+ while (end > begin && isJsWhitespace(static_cast<char16_t>(units[end - 1]))) end--;
448
+
449
+ std::string text;
450
+ for (size_t i = 0; i < length; i++) {
451
+ char16_t c = static_cast<char16_t>(units[i]);
452
+ text.push_back(c < 0x80 ? static_cast<char>(c) : '?');
453
+ }
454
+
455
+ if (begin == end) return BigInt();
456
+
457
+ // Every character left must be ASCII: digits, a sign, a prefix.
458
+ std::string body;
459
+ for (size_t i = begin; i < end; i++) {
460
+ char16_t c = static_cast<char16_t>(units[i]);
461
+ if (c >= 0x80) syntaxError(text);
462
+ body.push_back(static_cast<char>(c));
463
+ }
464
+
465
+ int radix = 10;
466
+ std::string_view digits = body;
467
+
468
+ if (digits.size() >= 2 && digits[0] == '0') {
469
+ char p = digits[1];
470
+ if (p == 'x' || p == 'X') radix = 16;
471
+ if (p == 'o' || p == 'O') radix = 8;
472
+ if (p == 'b' || p == 'B') radix = 2;
473
+ }
474
+
475
+ if (radix != 10) {
476
+ digits.remove_prefix(2);
477
+ if (digits.empty() || digits[0] == '-' || digits[0] == '+') syntaxError(text);
478
+
479
+ return BigInt::fromDigits(digits, radix);
480
+ }
481
+
482
+ bool negative = false;
483
+ if (digits[0] == '+' || digits[0] == '-') {
484
+ negative = digits[0] == '-';
485
+ digits.remove_prefix(1);
486
+ }
487
+
488
+ if (digits.empty() || digits[0] == '-' || digits[0] == '+') syntaxError(text);
489
+
490
+ for (char c : digits) {
491
+ if (c < '0' || c > '9') syntaxError(text);
492
+ }
493
+
494
+ BigInt value = BigInt::fromDigits(digits, 10);
495
+ return negative ? -value : value;
496
+ }
497
+
498
+ } // namespace
499
+
500
+ BigInt BigInt::parse(std::string_view text) { return parseUnits(text.data(), text.size()); }
501
+
502
+ BigInt BigInt::parse(const String& text) {
503
+ if (text.isOneByte()) {
504
+ std::string_view latin1 = text.latin1();
505
+ return parseUnits(reinterpret_cast<const unsigned char*>(latin1.data()), latin1.size());
506
+ }
507
+
508
+ std::u16string_view wide = text.utf16();
509
+ return parseUnits(wide.data(), wide.size());
510
+ }
511
+
512
+ // --- arithmetic ------------------------------------------------------------------
513
+
514
+ BigInt BigInt::add(const BigInt& a, const BigInt& b, bool subtract) {
515
+ Parts x = A::parts(a);
516
+ Parts y = A::parts(b);
517
+ if (subtract) y.negative = !y.negative && !y.magnitude.empty();
518
+
519
+ if (x.negative == y.negative) return A::make(x.negative, addMagnitudes(x.magnitude, y.magnitude));
520
+
521
+ int order = compareMagnitudes(x.magnitude, y.magnitude);
522
+ if (order == 0) return BigInt();
523
+
524
+ if (order > 0) return A::make(x.negative, subtractMagnitudes(x.magnitude, y.magnitude));
525
+
526
+ return A::make(y.negative, subtractMagnitudes(y.magnitude, x.magnitude));
527
+ }
528
+
529
+ BigInt BigInt::multiply(const BigInt& a, const BigInt& b) {
530
+ Parts x = A::parts(a);
531
+ Parts y = A::parts(b);
532
+
533
+ return A::make(x.negative != y.negative, multiplyMagnitudes(x.magnitude, y.magnitude));
534
+ }
535
+
536
+ BigInt BigInt::divide(const BigInt& a, const BigInt& b, bool remainder) {
537
+ if (b.isZero()) throwRangeError("Division by zero");
538
+
539
+ Parts x = A::parts(a);
540
+ Parts y = A::parts(b);
541
+
542
+ Mag q, r;
543
+ divideMagnitudes(x.magnitude, y.magnitude, q, r);
544
+
545
+ if (remainder) return A::make(x.negative, std::move(r));
546
+
547
+ return A::make(x.negative != y.negative, std::move(q));
548
+ }
549
+
550
+ BigInt BigInt::negateBeyond() const {
551
+ Parts p = A::parts(*this);
552
+ // Read before the move: arguments are evaluated in no set order (GCC goes right to left).
553
+ bool negative = !p.negative && !p.magnitude.empty();
554
+
555
+ return A::make(negative, std::move(p.magnitude));
556
+ }
557
+
558
+ BigInt BigInt::pow(const BigInt& base, const BigInt& exponent) {
559
+ if (exponent.sign() < 0) throwRangeError("Exponent must be non-negative");
560
+
561
+ if (exponent.isZero()) return fromInt64(1);
562
+
563
+ if (base.isZero() || base == fromInt64(1)) return base;
564
+
565
+ if (base == fromInt64(-1)) return (exponent & fromInt64(1)).isZero() ? fromInt64(1) : base;
566
+
567
+ // Any larger base doubles in size at least every step.
568
+ if (A::isBig(exponent) || A::small(exponent) > static_cast<int64_t>(kMaxBits)) tooBig();
569
+
570
+ auto e = static_cast<uint64_t>(A::small(exponent));
571
+
572
+ // Within 64 bits, no allocation.
573
+ if (!A::isBig(base)) {
574
+ int64_t result = 1;
575
+ int64_t square = A::small(base);
576
+ uint64_t left = e;
577
+ bool fits = true;
578
+
579
+ while (left) {
580
+ if ((left & 1) && __builtin_mul_overflow(result, square, &result)) {
581
+ fits = false;
582
+ break;
583
+ }
584
+
585
+ left >>= 1;
586
+ if (left && __builtin_mul_overflow(square, square, &square)) {
587
+ fits = false;
588
+ break;
589
+ }
590
+ }
591
+
592
+ if (fits) return fromInt64(result);
593
+ }
594
+
595
+ Parts p = A::parts(base);
596
+ if ((bitLength(p.magnitude) - 1) * e > kMaxBits) tooBig();
597
+
598
+ Mag result{1};
599
+ Mag square = p.magnitude;
600
+
601
+ for (uint64_t left = e; left; left >>= 1) {
602
+ if (left & 1) result = multiplyMagnitudes(result, square);
603
+ if (left > 1) square = multiplyMagnitudes(square, square);
604
+ }
605
+
606
+ return A::make(p.negative && (e & 1), std::move(result));
607
+ }
608
+
609
+ // --- bits ---------------------------------------------------------------------------
610
+
611
+ BigInt BigInt::bitwise(const BigInt& a, const BigInt& b, char op) {
612
+ Parts x = A::parts(a);
613
+ Parts y = A::parts(b);
614
+ size_t width = std::max(x.magnitude.size(), y.magnitude.size()) + 1;
615
+
616
+ Mag l = twosComplement(x, width);
617
+ Mag r = twosComplement(y, width);
618
+
619
+ for (size_t i = 0; i < width; i++) {
620
+ if (op == '&') l[i] &= r[i];
621
+ if (op == '|') l[i] |= r[i];
622
+ if (op == '^') l[i] ^= r[i];
623
+ }
624
+
625
+ return A::make(fromTwosComplement(std::move(l)));
626
+ }
627
+
628
+ BigInt BigInt::shift(const BigInt& a, const BigInt& count, bool left) {
629
+ // A count beyond int64 moves every bit out, or far past the limit.
630
+ if (A::isBig(count)) {
631
+ bool growing = left != A::negative(count);
632
+ if (!growing) return a.sign() < 0 ? fromInt64(-1) : BigInt();
633
+ if (a.isZero()) return a;
634
+ tooBig();
635
+ }
636
+
637
+ int64_t n = A::small(count);
638
+ if (!left) n = n == INT64_MIN ? INT64_MAX : -n;
639
+
640
+ // From here, n > 0 shifts left and n < 0 right.
641
+ if (n >= 0) {
642
+ if (a.isZero()) return a;
643
+
644
+ if (!A::isBig(a) && n < 63) {
645
+ int64_t r;
646
+ if (!__builtin_mul_overflow(A::small(a), int64_t{1} << n, &r)) return fromInt64(r);
647
+ }
648
+
649
+ Parts p = A::parts(a);
650
+ return A::make(p.negative, shiftLeftMagnitude(p.magnitude, static_cast<uint64_t>(n)));
651
+ }
652
+
653
+ uint64_t bits = n == INT64_MIN ? uint64_t{1} << 63 : static_cast<uint64_t>(-n);
654
+
655
+ if (!A::isBig(a)) {
656
+ int64_t v = A::small(a);
657
+ if (bits >= 63) return fromInt64(v < 0 ? -1 : 0);
658
+
659
+ return fromInt64(v >> bits);
660
+ }
661
+
662
+ Parts p = A::parts(a);
663
+ if (!p.negative) return A::make(false, shiftRightMagnitude(p.magnitude, bits));
664
+
665
+ // Toward negative infinity: -(((|a| - 1) >> bits) + 1).
666
+ Mag shifted = shiftRightMagnitude(subtractMagnitudes(p.magnitude, Mag{1}), bits);
667
+ return A::make(true, addMagnitudes(shifted, Mag{1}));
668
+ }
669
+
670
+ BigInt BigInt::unsignedShiftRight(const BigInt&, const BigInt&) {
671
+ throwTypeError("BigInts have no unsigned right shift, use >> instead");
672
+ }
673
+
674
+ BigInt BigInt::asUintN(double bitsValue, const BigInt& value) {
675
+ uint64_t bits = toIndex(bitsValue);
676
+ if (bits == 0) return BigInt();
677
+
678
+ Parts p = A::parts(value);
679
+ if (!p.negative && bitLength(p.magnitude) <= bits) return value;
680
+
681
+ // A negative value becomes 2^bits minus its magnitude: that many bits.
682
+ if (bits > kMaxBits) tooBig();
683
+
684
+ size_t width = static_cast<size_t>((bits + 31) / 32);
685
+ Mag limbs = twosComplement(p, std::max(width, p.magnitude.size() + 1));
686
+ limbs.resize(width);
687
+
688
+ if (bits % 32) limbs.back() &= (uint32_t{1} << (bits % 32)) - 1;
689
+
690
+ return A::make(false, std::move(limbs));
691
+ }
692
+
693
+ BigInt BigInt::asIntN(double bitsValue, const BigInt& value) {
694
+ uint64_t bits = toIndex(bitsValue);
695
+ if (bits == 0) return BigInt();
696
+
697
+ Parts p = A::parts(value);
698
+
699
+ // Already within [-2^(bits-1), 2^(bits-1)).
700
+ if (bitLength(p.magnitude) + 1 < bits) return value;
701
+
702
+ size_t width = static_cast<size_t>((bits + 31) / 32);
703
+ Mag limbs = twosComplement(p, std::max(width, p.magnitude.size() + 1));
704
+ limbs.resize(width);
705
+
706
+ // Sign-extend from bit `bits - 1` across the top limb.
707
+ unsigned top = static_cast<unsigned>((bits - 1) % 32);
708
+ uint32_t& last = limbs.back();
709
+ bool negative = (last >> top) & 1;
710
+
711
+ if (top < 31) {
712
+ uint32_t above = ~((uint32_t{1} << (top + 1)) - 1);
713
+ last = negative ? (last | above) : (last & ~above);
714
+ }
715
+
716
+ return A::make(fromTwosComplement(std::move(limbs)));
717
+ }
718
+
719
+ // --- comparisons ------------------------------------------------------------------
720
+
721
+ int BigInt::sign() const noexcept {
722
+ if (big_) return big_->negative ? -1 : 1;
723
+
724
+ return small_ < 0 ? -1 : (small_ > 0 ? 1 : 0);
725
+ }
726
+
727
+ bool BigInt::equalBeyond(const BigInt& a, const BigInt& b) noexcept {
728
+ if (!a.big_ || !b.big_) return false;
729
+
730
+ return a.big_->negative == b.big_->negative && a.big_->magnitude == b.big_->magnitude;
731
+ }
732
+
733
+ std::strong_ordering BigInt::compareBeyond(const BigInt& a, const BigInt& b) noexcept {
734
+ // Canonical: a value beyond int64 is beyond every inline one.
735
+ if (!b.big_) return a.big_->negative ? std::strong_ordering::less : std::strong_ordering::greater;
736
+ if (!a.big_) return b.big_->negative ? std::strong_ordering::greater : std::strong_ordering::less;
737
+
738
+ if (a.big_->negative != b.big_->negative) return a.big_->negative ? std::strong_ordering::less : std::strong_ordering::greater;
739
+
740
+ int order = compareMagnitudes(a.big_->magnitude, b.big_->magnitude);
741
+ if (a.big_->negative) order = -order;
742
+
743
+ return order < 0 ? std::strong_ordering::less : order > 0 ? std::strong_ordering::greater : std::strong_ordering::equal;
744
+ }
745
+
746
+ std::partial_ordering compare(const BigInt& a, double b) noexcept {
747
+ if (std::isnan(b)) return std::partial_ordering::unordered;
748
+ if (std::isinf(b)) return b > 0 ? std::partial_ordering::less : std::partial_ordering::greater;
749
+
750
+ constexpr double kTwo63 = 9223372036854775808.0;
751
+ double floor = std::floor(b);
752
+ bool integral = floor == b;
753
+
754
+ if (!A::isBig(a)) {
755
+ if (b >= kTwo63) return std::partial_ordering::less;
756
+ if (b < -kTwo63) return std::partial_ordering::greater;
757
+
758
+ // An integer below b's fraction is below b; at or above its ceiling, above.
759
+ auto f = static_cast<int64_t>(floor);
760
+ int64_t v = A::small(a);
761
+
762
+ if (integral) return v <=> f;
763
+ return v <= f ? std::partial_ordering::less : std::partial_ordering::greater;
764
+ }
765
+
766
+ // Beyond int64 and |b| finite: exact, through b's integer part (a double
767
+ // this large is an integer already).
768
+ BigInt f = BigInt::fromDouble(floor);
769
+ auto order = a <=> f;
770
+
771
+ if (integral || order != 0) return order;
772
+ return std::partial_ordering::less;
773
+ }
774
+
775
+ // --- conversions ----------------------------------------------------------------------
776
+
777
+ String BigInt::toString() const { return toString(10); }
778
+
779
+ String BigInt::toString(double radixValue) const {
780
+ double r = std::isnan(radixValue) ? 0 : std::trunc(radixValue);
781
+ if (!(r >= 2 && r <= 36)) throwRangeError("toString() radix argument must be between 2 and 36");
782
+
783
+ auto radix = static_cast<uint32_t>(r);
784
+ static constexpr char kDigits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
785
+
786
+ std::string out;
787
+
788
+ if (!big_) {
789
+ uint64_t u = small_ < 0 ? static_cast<uint64_t>(-(small_ + 1)) + 1 : static_cast<uint64_t>(small_);
790
+
791
+ do {
792
+ out.push_back(kDigits[u % radix]);
793
+ u /= radix;
794
+ } while (u);
795
+
796
+ if (small_ < 0) out.push_back('-');
797
+
798
+ std::reverse(out.begin(), out.end());
799
+ return String::fromLatin1(out);
800
+ }
801
+
802
+ Mag m = big_->magnitude;
803
+ auto [power, perChunk] = chunkOf(radix);
804
+
805
+ // Least significant chunk first, each padded to its full width but the
806
+ // last.
807
+ while (!m.empty()) {
808
+ uint32_t chunk = divideSmall(m, power);
809
+
810
+ for (int k = 0; k < perChunk && (chunk || !m.empty()); k++) {
811
+ out.push_back(kDigits[chunk % radix]);
812
+ chunk /= radix;
813
+ }
814
+ }
815
+
816
+ if (big_->negative) out.push_back('-');
817
+
818
+ std::reverse(out.begin(), out.end());
819
+ return String::fromLatin1(out);
820
+ }
821
+
822
+ double BigInt::toDouble() const noexcept {
823
+ if (!big_) return static_cast<double>(small_);
824
+
825
+ const Mag& m = big_->magnitude;
826
+ uint64_t length = bitLength(m);
827
+ double sign = big_->negative ? -1.0 : 1.0;
828
+
829
+ if (length > 1024) return sign * std::numeric_limits<double>::infinity();
830
+
831
+ // The top 64 bits, and whether any below them is set.
832
+ uint64_t below = length - 64;
833
+ Mag top = shiftRightMagnitude(m, below);
834
+ uint64_t high = top[0] | (top.size() > 1 ? uint64_t{top[1]} << 32 : 0);
835
+
836
+ bool sticky = false;
837
+ for (uint64_t i = 0; i < below / 32 && !sticky; i++) sticky = m[i] != 0;
838
+ if (!sticky && below % 32) sticky = (m[below / 32] & ((uint32_t{1} << (below % 32)) - 1)) != 0;
839
+
840
+ // To 53 bits, the nearest, ties to even.
841
+ uint64_t mantissa = high >> 11;
842
+ uint64_t rest = high & 0x7FF;
843
+
844
+ if (rest > 0x400 || (rest == 0x400 && (sticky || (mantissa & 1)))) mantissa++;
845
+
846
+ return sign * std::ldexp(static_cast<double>(mantissa), static_cast<int>(length - 53));
847
+ }
848
+
849
+ void BigInt::throwOutOfRange(bool isSigned) const {
850
+ throwRangeError((toString().toUtf8() + (isSigned ? " is out of range for a 64-bit signed integer" : " is out of range for a 64-bit unsigned integer")).c_str());
851
+ }
852
+
853
+ uint64_t BigInt::toUint64Beyond() const {
854
+ if (auto u = tryUint64()) return *u;
855
+
856
+ throwOutOfRange(false);
857
+ }
858
+
859
+ std::optional<uint64_t> BigInt::tryUint64() const noexcept {
860
+ if (!big_) {
861
+ if (small_ < 0) return std::nullopt;
862
+ return static_cast<uint64_t>(small_);
863
+ }
864
+
865
+ if (big_->negative || big_->magnitude.size() > 2) return std::nullopt;
866
+
867
+ return uint64_t{big_->magnitude[0]} | uint64_t{big_->magnitude[1]} << 32;
868
+ }
869
+
870
+ uint64_t BigInt::wrapBeyond() const noexcept {
871
+ const Mag& m = big_->magnitude;
872
+ uint64_t low = uint64_t{m[0]} | (m.size() > 1 ? uint64_t{m[1]} << 32 : 0);
873
+
874
+ return big_->negative ? ~low + 1 : low;
875
+ }
876
+
877
+ size_t BigInt::hash() const noexcept {
878
+ if (!big_) return std::hash<int64_t>()(small_);
879
+
880
+ uint64_t h = big_->negative ? 0xcbf29ce484222325ull : 0x84222325cbf29ce4ull;
881
+ for (uint32_t limb : big_->magnitude) h = (h ^ limb) * 0x100000001b3ull;
882
+
883
+ return static_cast<size_t>(h);
884
+ }
885
+
886
+ String toJsString(const BigInt& value) { return value.toString(); }
887
+
888
+ namespace detail {
889
+
890
+ void throwOutOfNativeRange(const BigInt& value, const char* what, bool isSigned, size_t bits) {
891
+ std::string message = std::string(what) + ": " + value.toString().toUtf8() + " is out of range for a " +
892
+ std::to_string(bits) + "-bit " + (isSigned ? "signed" : "unsigned") + " integer";
893
+ throwRangeError(message.c_str());
894
+ }
895
+
896
+ } // namespace detail
897
+
898
+ } // namespace lucent