toilscript 0.1.4 → 0.1.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.
- package/dist/cli.js +3480 -21
- package/dist/cli.js.map +2 -2
- package/dist/importmap.json +2 -2
- package/dist/web.js +3 -3
- package/package.json +1 -1
- package/std/assembly/bignum/LICENSE +201 -0
- package/std/assembly/bignum/NOTICE +7 -0
- package/std/assembly/bignum/fixed/fp128.ts +58 -0
- package/std/assembly/bignum/fixed/fp256.ts +9 -0
- package/std/assembly/bignum/fixed/index.ts +38 -0
- package/std/assembly/bignum/fixed/safe/fp128.ts +3 -0
- package/std/assembly/bignum/fixed/safe/fp256.ts +3 -0
- package/std/assembly/bignum/fixed/types.ts +103 -0
- package/std/assembly/bignum/globals.ts +546 -0
- package/std/assembly/bignum/index.ts +1 -0
- package/std/assembly/bignum/integer/i128.ts +413 -0
- package/std/assembly/bignum/integer/i256.ts +50 -0
- package/std/assembly/bignum/integer/index.ts +3 -0
- package/std/assembly/bignum/integer/u128.ts +963 -0
- package/std/assembly/bignum/integer/u256.ts +1007 -0
- package/std/assembly/bignum/utils.ts +260 -0
- package/std/assembly/bignum.ts +18 -0
- package/std/assembly/index.d.ts +1 -1
- package/std/assembly/toilscript.d.ts +273 -0
- package/std/assembly/toilscript.ts +0 -16
|
@@ -0,0 +1,1007 @@
|
|
|
1
|
+
import { i128 } from './i128';
|
|
2
|
+
import { u128 } from './u128';
|
|
3
|
+
import { u256toDecimalString } from "../utils";
|
|
4
|
+
import {
|
|
5
|
+
__mul256, __u256carry, __u256carrySub, add64Local, sub64
|
|
6
|
+
} from '../globals';
|
|
7
|
+
|
|
8
|
+
@lazy const HEX_CHARS = '0123456789abcdef';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Represents a 256-bit unsigned integer.
|
|
12
|
+
* Optimized for gas efficiency with unrolled loops and direct memory access.
|
|
13
|
+
*/
|
|
14
|
+
export class u256 {
|
|
15
|
+
/**
|
|
16
|
+
* Constructs a new `u256` with the specified 64-bit limbs.
|
|
17
|
+
* @constructor
|
|
18
|
+
* @param {u64} [lo1=0] - The lowest 64 bits.
|
|
19
|
+
* @param {u64} [lo2=0] - The 64 bits above `lo1`.
|
|
20
|
+
* @param {u64} [hi1=0] - The 64 bits above `lo2`.
|
|
21
|
+
* @param {u64} [hi2=0] - The highest 64 bits.
|
|
22
|
+
*/
|
|
23
|
+
constructor(
|
|
24
|
+
public lo1: u64 = 0,
|
|
25
|
+
public lo2: u64 = 0,
|
|
26
|
+
public hi1: u64 = 0,
|
|
27
|
+
public hi2: u64 = 0,
|
|
28
|
+
) {}
|
|
29
|
+
|
|
30
|
+
@inline static get Zero(): u256 { return new u256(0, 0, 0, 0); }
|
|
31
|
+
@inline static get One(): u256 { return new u256(1, 0, 0, 0); }
|
|
32
|
+
@inline static get Min(): u256 { return new u256(0, 0, 0, 0); }
|
|
33
|
+
@inline static get Max(): u256 { return new u256(-1, -1, -1, -1); }
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* A constant representing the maximum value for 256-bit unsigned integer.
|
|
37
|
+
* All bits set to 1.
|
|
38
|
+
* @returns {u256}
|
|
39
|
+
*/
|
|
40
|
+
/**
|
|
41
|
+
* Creates a new `u256` from an existing `u256`.
|
|
42
|
+
* @param {u256} value - The source `u256` value.
|
|
43
|
+
* @returns {u256} - A new copy of the `value`.
|
|
44
|
+
*/
|
|
45
|
+
@inline
|
|
46
|
+
static fromU256(value: u256): u256 {
|
|
47
|
+
return new u256(value.lo1, value.lo2, value.hi1, value.hi2);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Creates a new `u256` from a 128-bit unsigned integer.
|
|
52
|
+
* @param {u128} value - The 128-bit unsigned integer.
|
|
53
|
+
* @returns {u256} - The resulting 256-bit unsigned integer.
|
|
54
|
+
*/
|
|
55
|
+
@inline
|
|
56
|
+
static fromU128(value: u128): u256 {
|
|
57
|
+
return new u256(value.lo, value.hi);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Creates a new `u256` from a 64-bit unsigned integer.
|
|
62
|
+
* @param {u64} value - The 64-bit unsigned integer.
|
|
63
|
+
* @returns {u256} - The resulting 256-bit unsigned integer.
|
|
64
|
+
*/
|
|
65
|
+
@inline
|
|
66
|
+
static fromU64(value: u64): u256 {
|
|
67
|
+
if (value == 0) return u256.Zero;
|
|
68
|
+
if (value == 1) return u256.One;
|
|
69
|
+
return new u256(value);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Creates a new `u256` from a 64-bit signed integer (sign-extends).
|
|
74
|
+
* @param {i64} value - The 64-bit signed integer.
|
|
75
|
+
* @returns {u256} - The resulting 256-bit unsigned integer.
|
|
76
|
+
*/
|
|
77
|
+
@inline
|
|
78
|
+
static fromI64(value: i64): u256 {
|
|
79
|
+
if (value == 0) return u256.Zero;
|
|
80
|
+
if (value == 1) return u256.One;
|
|
81
|
+
if (value == -1) return u256.Max;
|
|
82
|
+
let mask = value >> 63;
|
|
83
|
+
return new u256(<u64>value, mask, mask, mask);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Creates a new `u256` from a 32-bit unsigned integer.
|
|
88
|
+
* @param {u32} value - The 32-bit unsigned integer.
|
|
89
|
+
* @returns {u256} - The resulting 256-bit unsigned integer.
|
|
90
|
+
*/
|
|
91
|
+
@inline
|
|
92
|
+
static fromU32(value: u32): u256 {
|
|
93
|
+
if (value == 0) return u256.Zero;
|
|
94
|
+
if (value == 1) return u256.One;
|
|
95
|
+
return new u256(value);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Creates a new `u256` from a 32-bit signed integer (sign-extends).
|
|
100
|
+
* @param {i32} value - The 32-bit signed integer.
|
|
101
|
+
* @returns {u256} - The resulting 256-bit unsigned integer.
|
|
102
|
+
*/
|
|
103
|
+
@inline
|
|
104
|
+
static fromI32(value: i32): u256 {
|
|
105
|
+
if (value == 0) return u256.Zero;
|
|
106
|
+
if (value == 1) return u256.One;
|
|
107
|
+
if (value == -1) return u256.Max;
|
|
108
|
+
let mask: u64 = value >> 63;
|
|
109
|
+
return new u256(value, mask, mask, mask);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Creates a new `u256` from 8 separate 32-bit segments (lower to higher).
|
|
114
|
+
* @param {u32} l0 - Lower 32 bits of the first 64-bit segment.
|
|
115
|
+
* @param {u32} l1 - Higher 32 bits of the first 64-bit segment.
|
|
116
|
+
* @param {u32} l2 - Lower 32 bits of the second 64-bit segment.
|
|
117
|
+
* @param {u32} l3 - Higher 32 bits of the second 64-bit segment.
|
|
118
|
+
* @param {u32} h0 - Lower 32 bits of the third 64-bit segment.
|
|
119
|
+
* @param {u32} h1 - Higher 32 bits of the third 64-bit segment.
|
|
120
|
+
* @param {u32} h2 - Lower 32 bits of the fourth 64-bit segment.
|
|
121
|
+
* @param {u32} h3 - Higher 32 bits of the fourth 64-bit segment.
|
|
122
|
+
* @returns {u256} - The resulting 256-bit unsigned integer.
|
|
123
|
+
*/
|
|
124
|
+
@inline
|
|
125
|
+
static fromBits(
|
|
126
|
+
l0: u32, l1: u32, l2: u32, l3: u32,
|
|
127
|
+
h0: u32, h1: u32, h2: u32, h3: u32,
|
|
128
|
+
): u256 {
|
|
129
|
+
return new u256(
|
|
130
|
+
<u64>l0 | ((<u64>l1) << 32),
|
|
131
|
+
<u64>l2 | ((<u64>l3) << 32),
|
|
132
|
+
<u64>h0 | ((<u64>h1) << 32),
|
|
133
|
+
<u64>h2 | ((<u64>h3) << 32),
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates a new `u256` from an array of bytes or `Uint8Array`.
|
|
139
|
+
* @param {T} array - The source array of bytes (u8[] or Uint8Array).
|
|
140
|
+
* @param {boolean} [bigEndian=false] - Whether the bytes are in big-endian format.
|
|
141
|
+
* @throws {TypeError} If the generic type `T` is not supported.
|
|
142
|
+
* @returns {u256} - The resulting `u256`.
|
|
143
|
+
*/
|
|
144
|
+
@inline
|
|
145
|
+
static fromBytes<T>(array: T, bigEndian: bool = false): u256 {
|
|
146
|
+
// @ts-ignore
|
|
147
|
+
if (array instanceof u8[]) {
|
|
148
|
+
return bigEndian
|
|
149
|
+
// @ts-ignore
|
|
150
|
+
? u256.fromBytesBE(<u8[]>array)
|
|
151
|
+
// @ts-ignore
|
|
152
|
+
: u256.fromBytesLE(<u8[]>array);
|
|
153
|
+
} else if (array instanceof Uint8Array) {
|
|
154
|
+
return bigEndian
|
|
155
|
+
? u256.fromUint8ArrayBE(<Uint8Array>array)
|
|
156
|
+
: u256.fromUint8ArrayLE(<Uint8Array>array);
|
|
157
|
+
} else {
|
|
158
|
+
throw new TypeError("Unsupported generic type");
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* Creates a new `u256` from a little-endian array of bytes.
|
|
164
|
+
* @param {u8[]} array - A 32-byte array (little-endian).
|
|
165
|
+
* @returns {u256} - The resulting `u256`.
|
|
166
|
+
*/
|
|
167
|
+
@inline
|
|
168
|
+
static fromBytesLE(array: u8[]): u256 {
|
|
169
|
+
if (array.length !== 32) throw new Error("Invalid length");
|
|
170
|
+
let buffer = array.dataStart;
|
|
171
|
+
return new u256(
|
|
172
|
+
load<u64>(buffer, 0),
|
|
173
|
+
load<u64>(buffer, 8),
|
|
174
|
+
load<u64>(buffer, 16),
|
|
175
|
+
load<u64>(buffer, 24),
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Creates a new `u256` from a big-endian array of bytes.
|
|
181
|
+
* @param {u8[]} array - A 32-byte array (big-endian).
|
|
182
|
+
* @returns {u256} - The resulting `u256`.
|
|
183
|
+
*/
|
|
184
|
+
@inline
|
|
185
|
+
static fromBytesBE(array: u8[]): u256 {
|
|
186
|
+
if (array.length !== 32) throw new Error("Invalid length");
|
|
187
|
+
let buffer = array.dataStart;
|
|
188
|
+
return new u256(
|
|
189
|
+
bswap<u64>(load<u64>(buffer, 24)),
|
|
190
|
+
bswap<u64>(load<u64>(buffer, 16)),
|
|
191
|
+
bswap<u64>(load<u64>(buffer, 8)),
|
|
192
|
+
bswap<u64>(load<u64>(buffer, 0))
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Creates a new `u256` from a little-endian `Uint8Array`.
|
|
198
|
+
* @param {Uint8Array} array - A 32-byte `Uint8Array` (little-endian).
|
|
199
|
+
* @returns {u256} - The resulting `u256`.
|
|
200
|
+
*/
|
|
201
|
+
@inline
|
|
202
|
+
static fromUint8ArrayLE(array: Uint8Array): u256 {
|
|
203
|
+
if (array.length !== 32) throw new Error("Invalid length");
|
|
204
|
+
let buffer = array.dataStart;
|
|
205
|
+
return new u256(
|
|
206
|
+
load<u64>(buffer, 0),
|
|
207
|
+
load<u64>(buffer, 8),
|
|
208
|
+
load<u64>(buffer, 16),
|
|
209
|
+
load<u64>(buffer, 24)
|
|
210
|
+
);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Creates a new `u256` from a big-endian `Uint8Array`.
|
|
215
|
+
* @param {Uint8Array} array - A 32-byte `Uint8Array` (big-endian).
|
|
216
|
+
* @returns {u256} - The resulting `u256`.
|
|
217
|
+
*/
|
|
218
|
+
@inline
|
|
219
|
+
static fromUint8ArrayBE(array: Uint8Array): u256 {
|
|
220
|
+
if (array.length !== 32) throw new Error("Invalid length");
|
|
221
|
+
let buffer = array.dataStart;
|
|
222
|
+
return new u256(
|
|
223
|
+
bswap<u64>(load<u64>(buffer, 24)),
|
|
224
|
+
bswap<u64>(load<u64>(buffer, 16)),
|
|
225
|
+
bswap<u64>(load<u64>(buffer, 8)),
|
|
226
|
+
bswap<u64>(load<u64>(buffer, 0))
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/**
|
|
231
|
+
* Creates a new `u256` from a 64-bit floating-point number.
|
|
232
|
+
* NOTE: This is only correct up to about 2^53.
|
|
233
|
+
* @param {f64} value - The 64-bit float value.
|
|
234
|
+
* @returns {u256} - The resulting `u256`.
|
|
235
|
+
*/
|
|
236
|
+
@inline
|
|
237
|
+
static fromF64(value: f64): u256 {
|
|
238
|
+
let mask = u64(reinterpret<i64>(value) >> 63);
|
|
239
|
+
return new u256(<u64>value, mask, mask, mask);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Creates a new `u256` from a 32-bit floating-point number.
|
|
244
|
+
* NOTE: This is only correct up to about 2^23.
|
|
245
|
+
* @param {f32} value - The 32-bit float value.
|
|
246
|
+
* @returns {u256} - The resulting `u256`.
|
|
247
|
+
*/
|
|
248
|
+
@inline
|
|
249
|
+
static fromF32(value: f32): u256 {
|
|
250
|
+
let mask = u64(reinterpret<i32>(value) >> 31);
|
|
251
|
+
return new u256(<u64>value, mask, mask, mask);
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
/**
|
|
255
|
+
* Creates a new `u256` from a generic value `T`.
|
|
256
|
+
* Supported types: bool, i8, u8, i16, u16, i32, u32, i64, u64, f32, f64, u128, u256, u8[], Uint8Array.
|
|
257
|
+
* @param {T} value - The source value.
|
|
258
|
+
* @throws {TypeError} If the type `T` is not supported.
|
|
259
|
+
* @returns {u256} - The resulting `u256`.
|
|
260
|
+
*/
|
|
261
|
+
@inline
|
|
262
|
+
static from<T>(value: T): u256 {
|
|
263
|
+
if (value instanceof bool) return u256.fromU64(<u64>value);
|
|
264
|
+
else if (value instanceof i8) return u256.fromI64(<i64>value);
|
|
265
|
+
else if (value instanceof u8) return u256.fromU64(<u64>value);
|
|
266
|
+
else if (value instanceof i16) return u256.fromI64(<i64>value);
|
|
267
|
+
else if (value instanceof u16) return u256.fromU64(<u64>value);
|
|
268
|
+
else if (value instanceof i32) return u256.fromI64(<i64>value);
|
|
269
|
+
else if (value instanceof u32) return u256.fromU64(<u64>value);
|
|
270
|
+
else if (value instanceof i64) return u256.fromI64(<i64>value);
|
|
271
|
+
else if (value instanceof u64) return u256.fromU64(<u64>value);
|
|
272
|
+
else if (value instanceof f32) return u256.fromF64(<f64>value);
|
|
273
|
+
else if (value instanceof f64) return u256.fromF64(<f64>value);
|
|
274
|
+
else if (value instanceof u128) return u256.fromU128(<u128>value);
|
|
275
|
+
else if (value instanceof u256) return u256.fromU256(<u256>value);
|
|
276
|
+
else if (value instanceof u8[]) return u256.fromBytes(<u8[]>value);
|
|
277
|
+
else if (value instanceof Uint8Array) return u256.fromBytes(<Uint8Array>value);
|
|
278
|
+
else throw new TypeError("Unsupported generic type");
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Parses a string in decimal or hexadecimal format into a `u256`.
|
|
283
|
+
* @param {string} str - The input string.
|
|
284
|
+
* @param {i32} [radix=10] - The base (10 for decimal, 16 for hexadecimal).
|
|
285
|
+
* @returns {u256} - The resulting `u256`.
|
|
286
|
+
*/
|
|
287
|
+
@inline
|
|
288
|
+
static fromString(str: string, radix: i32 = 10): u256 {
|
|
289
|
+
assert(radix == 10 || radix == 16, "radix must be 10 or 16");
|
|
290
|
+
let len = str.length;
|
|
291
|
+
if (len == 0) return u256.Zero;
|
|
292
|
+
let result = u256.Zero; // Use cached Zero
|
|
293
|
+
if (radix == 10) {
|
|
294
|
+
for (let i = 0; i < len; i++) {
|
|
295
|
+
let c = str.charCodeAt(i);
|
|
296
|
+
assert(c >= 0x30 && c <= 0x39, "Invalid decimal digit");
|
|
297
|
+
let digit: u64 = c - 0x30;
|
|
298
|
+
result = result * u256.from(10) + u256.from(digit);
|
|
299
|
+
}
|
|
300
|
+
} else {
|
|
301
|
+
for (let i = 0; i < len; i++) {
|
|
302
|
+
let c = str.charCodeAt(i);
|
|
303
|
+
let digit: u64 = 0;
|
|
304
|
+
if (c >= 0x30 && c <= 0x39) digit = c - 0x30;
|
|
305
|
+
else if (c >= 0x41 && c <= 0x46) digit = c - 0x41 + 10;
|
|
306
|
+
else if (c >= 0x61 && c <= 0x66) digit = c - 0x61 + 10;
|
|
307
|
+
else assert(false, "Invalid hexadecimal digit");
|
|
308
|
+
result = result * u256.from(16) + u256.from(digit);
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
return result;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
/**
|
|
315
|
+
* Checks if a given `u256` value is zero using the `!` operator.
|
|
316
|
+
* @param {u256} value - The `u256` to check.
|
|
317
|
+
* @returns {boolean} - True if zero, false otherwise.
|
|
318
|
+
*/
|
|
319
|
+
@inline @operator.prefix('!')
|
|
320
|
+
static isEmpty(value: u256): bool {
|
|
321
|
+
return value.isZero();
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
/**
|
|
325
|
+
* Adds two `u256` values and returns a new `u256` with the sum.
|
|
326
|
+
* @param {u256} a - The first `u256` addend.
|
|
327
|
+
* @param {u256} b - The second `u256` addend.
|
|
328
|
+
* @returns {u256} - The sum of `a` and `b`.
|
|
329
|
+
*/
|
|
330
|
+
@operator('+')
|
|
331
|
+
static add(a: u256, b: u256): u256 {
|
|
332
|
+
let lo1 = add64Local(a.lo1, b.lo1, 0);
|
|
333
|
+
let c1 = __u256carry;
|
|
334
|
+
let lo2 = add64Local(a.lo2, b.lo2, c1);
|
|
335
|
+
let c2 = __u256carry;
|
|
336
|
+
let hi1 = add64Local(a.hi1, b.hi1, c2);
|
|
337
|
+
let c3 = __u256carry;
|
|
338
|
+
let hi2 = add64Local(a.hi2, b.hi2, c3);
|
|
339
|
+
return new u256(lo1, lo2, hi1, hi2);
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
* Divides `a` by `b` (integer division).
|
|
344
|
+
* @param {u256} a - The dividend.
|
|
345
|
+
* @param {u256} b - The divisor.
|
|
346
|
+
* @throws {Error} If `b` is zero.
|
|
347
|
+
* @returns {u256} - The quotient of the division.
|
|
348
|
+
* Optimized Division.
|
|
349
|
+
* Performs division in-place on clones to minimize object allocation.
|
|
350
|
+
*/
|
|
351
|
+
@operator('/')
|
|
352
|
+
public static div(a: u256, b: u256): u256 {
|
|
353
|
+
if (b.isZero()) throw new Error('Division by zero');
|
|
354
|
+
if (a.isZero() || u256.lt(a, b)) return u256.Zero; // Return cached Zero
|
|
355
|
+
if (u256.eq(a, b)) return u256.One; // Return cached One
|
|
356
|
+
|
|
357
|
+
// Clone to mutate in-place
|
|
358
|
+
let n = a.clone();
|
|
359
|
+
let d = b.clone();
|
|
360
|
+
let result = u256.Zero.clone(); // Start with fresh Zero
|
|
361
|
+
|
|
362
|
+
const shift = u256.clz(d) - u256.clz(n);
|
|
363
|
+
|
|
364
|
+
// Shift d left by 'shift'
|
|
365
|
+
// Since d is a clone, we can mutate/reassign it
|
|
366
|
+
d = u256.shl(d, shift);
|
|
367
|
+
|
|
368
|
+
// Unrolled restore division
|
|
369
|
+
for (let i = shift; i >= 0; i--) {
|
|
370
|
+
if (u256.ge(n, d)) {
|
|
371
|
+
n.subAssign(d); // In-place subtract
|
|
372
|
+
result.orAssignBit(i); // In-place bit set
|
|
373
|
+
}
|
|
374
|
+
d.rshiftOne(); // In-place right shift by 1
|
|
375
|
+
}
|
|
376
|
+
return result;
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
/**
|
|
380
|
+
* Left-shifts a `u256` by the specified number of bits.
|
|
381
|
+
* @param {u256} value - The `u256` to shift.
|
|
382
|
+
* @param {i32} shift - The number of bits to shift (modulo 256).
|
|
383
|
+
* @returns {u256} - The shifted `u256`.
|
|
384
|
+
* Optimized Left Shift (Massacred allocation overhead).
|
|
385
|
+
* Unrolls the logic into local variables to avoid Array<u64> allocation.
|
|
386
|
+
*/
|
|
387
|
+
@operator('<<')
|
|
388
|
+
public static shl(value: u256, shift: i32): u256 {
|
|
389
|
+
if (shift <= 0) return shift == 0 ? value.clone() : u256.Zero; // Return cached
|
|
390
|
+
if (shift >= 256) return u256.Zero; // Return cached
|
|
391
|
+
|
|
392
|
+
shift &= 255;
|
|
393
|
+
|
|
394
|
+
const bits = 64;
|
|
395
|
+
const segShift = (shift / bits) | 0;
|
|
396
|
+
const bitShift = shift % bits;
|
|
397
|
+
const invShift = bits - bitShift;
|
|
398
|
+
|
|
399
|
+
let r0: u64 = 0, r1: u64 = 0, r2: u64 = 0, r3: u64 = 0;
|
|
400
|
+
const i0 = value.lo1, i1 = value.lo2, i2 = value.hi1, i3 = value.hi2;
|
|
401
|
+
|
|
402
|
+
if (segShift == 0) {
|
|
403
|
+
r0 = i0 << bitShift;
|
|
404
|
+
r1 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
405
|
+
r2 = (i2 << bitShift) | (bitShift == 0 ? 0 : i1 >>> invShift);
|
|
406
|
+
r3 = (i3 << bitShift) | (bitShift == 0 ? 0 : i2 >>> invShift);
|
|
407
|
+
} else if (segShift == 1) {
|
|
408
|
+
r1 = i0 << bitShift;
|
|
409
|
+
r2 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
410
|
+
r3 = (i2 << bitShift) | (bitShift == 0 ? 0 : i1 >>> invShift);
|
|
411
|
+
} else if (segShift == 2) {
|
|
412
|
+
r2 = i0 << bitShift;
|
|
413
|
+
r3 = (i1 << bitShift) | (bitShift == 0 ? 0 : i0 >>> invShift);
|
|
414
|
+
} else if (segShift == 3) {
|
|
415
|
+
r3 = i0 << bitShift;
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
return new u256(r0, r1, r2, r3);
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Subtracts `b` from `a` and returns a new `u256`.
|
|
423
|
+
* @param {u256} a - The minuend.
|
|
424
|
+
* @param {u256} b - The subtrahend.
|
|
425
|
+
* @returns {u256} - The difference `a - b`.
|
|
426
|
+
*/
|
|
427
|
+
@operator('-')
|
|
428
|
+
static sub(a: u256, b: u256): u256 {
|
|
429
|
+
let lo1 = sub64(a.lo1, b.lo1, 0);
|
|
430
|
+
let b1 = __u256carrySub;
|
|
431
|
+
let lo2 = sub64(a.lo2, b.lo2, b1);
|
|
432
|
+
let b2 = __u256carrySub;
|
|
433
|
+
let hi1 = sub64(a.hi1, b.hi1, b2);
|
|
434
|
+
let b3 = __u256carrySub;
|
|
435
|
+
let hi2 = sub64(a.hi2, b.hi2, b3);
|
|
436
|
+
return new u256(lo1, lo2, hi1, hi2);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
/**
|
|
440
|
+
* Bitwise OR between two `u256` values.
|
|
441
|
+
* @param {u256} a - The first operand.
|
|
442
|
+
* @param {u256} b - The second operand.
|
|
443
|
+
* @returns {u256} - The bitwise OR result.
|
|
444
|
+
*/
|
|
445
|
+
@inline @operator('|')
|
|
446
|
+
static or(a: u256, b: u256): u256 {
|
|
447
|
+
return new u256(a.lo1 | b.lo1, a.lo2 | b.lo2, a.hi1 | b.hi1, a.hi2 | b.hi2);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/**
|
|
451
|
+
* Bitwise XOR between two `u256` values.
|
|
452
|
+
* @param {u256} a - The first operand.
|
|
453
|
+
* @param {u256} b - The second operand.
|
|
454
|
+
* @returns {u256} - The bitwise XOR result.
|
|
455
|
+
*/
|
|
456
|
+
@inline @operator('^')
|
|
457
|
+
static xor(a: u256, b: u256): u256 {
|
|
458
|
+
return new u256(a.lo1 ^ b.lo1, a.lo2 ^ b.lo2, a.hi1 ^ b.hi1, a.hi2 ^ b.hi2);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Bitwise AND between two `u256` values.
|
|
463
|
+
* @param {u256} a - The first operand.
|
|
464
|
+
* @param {u256} b - The second operand.
|
|
465
|
+
* @returns {u256} - The bitwise AND result.
|
|
466
|
+
*/
|
|
467
|
+
@inline @operator('&')
|
|
468
|
+
static and(a: u256, b: u256): u256 {
|
|
469
|
+
return new u256(a.lo1 & b.lo1, a.lo2 & b.lo2, a.hi1 & b.hi1, a.hi2 & b.hi2);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Right-shifts a `u256` by the specified number of bits (logical shift).
|
|
474
|
+
* @param {u256} value - The `u256` to shift.
|
|
475
|
+
* @param {i32} shift - The number of bits to shift (modulo 256).
|
|
476
|
+
* @returns {u256} - The shifted `u256`.
|
|
477
|
+
*/
|
|
478
|
+
@operator('>>')
|
|
479
|
+
static shr(value: u256, shift: i32): u256 {
|
|
480
|
+
// If shift <= 0 => shift=0 means "no shift," shift<0 is arguably invalid.
|
|
481
|
+
// We just return a if shift=0, else zero if negative. Adjust to your preference.
|
|
482
|
+
if (shift <= 0) {
|
|
483
|
+
return shift == 0 ? value.clone() : u256.Zero;
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// If shift >= 256 => the result is zero for a 256-bit integer
|
|
487
|
+
if (shift >= 256) {
|
|
488
|
+
return u256.Zero;
|
|
489
|
+
}
|
|
490
|
+
|
|
491
|
+
// Now shift is in [1..255]
|
|
492
|
+
// Some code likes to do shift &= 255; but after the above check, it’s no longer necessary.
|
|
493
|
+
// We'll keep it for consistency:
|
|
494
|
+
shift &= 255;
|
|
495
|
+
|
|
496
|
+
// If after masking shift is 0, that means the original shift was multiple of 256, but we handled it above
|
|
497
|
+
if (shift == 0) return value.clone();
|
|
498
|
+
|
|
499
|
+
const w = shift >>> 6; // how many full 64-bit words to drop
|
|
500
|
+
const b = shift & 63; // how many bits to shift within a word
|
|
501
|
+
|
|
502
|
+
let lo1 = value.lo1;
|
|
503
|
+
let lo2 = value.lo2;
|
|
504
|
+
let hi1 = value.hi1;
|
|
505
|
+
let hi2 = value.hi2;
|
|
506
|
+
|
|
507
|
+
// Shift words down by w words
|
|
508
|
+
if (w >= 4) return u256.Zero; // Return cached
|
|
509
|
+
else if (w == 3) { lo1 = hi2; lo2 = 0; hi1 = 0; hi2 = 0; }
|
|
510
|
+
else if (w == 2) { lo1 = hi1; lo2 = hi2; hi1 = 0; hi2 = 0; }
|
|
511
|
+
else if (w == 1) { lo1 = lo2; lo2 = hi1; hi1 = hi2; hi2 = 0; }
|
|
512
|
+
|
|
513
|
+
// Now apply the bit shift b
|
|
514
|
+
if (b > 0) {
|
|
515
|
+
const invB = 64 - b;
|
|
516
|
+
lo1 = (lo1 >>> b) | (lo2 << invB);
|
|
517
|
+
lo2 = (lo2 >>> b) | (hi1 << invB);
|
|
518
|
+
hi1 = (hi1 >>> b) | (hi2 << invB);
|
|
519
|
+
hi2 = hi2 >>> b;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
return new u256(lo1, lo2, hi1, hi2);
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
/**
|
|
526
|
+
* Unsigned right shift operator (same as `shr` for `u256`).
|
|
527
|
+
* @param {u256} value - The `u256` to shift.
|
|
528
|
+
* @param {i32} shift - The number of bits to shift (modulo 256).
|
|
529
|
+
* @returns {u256} - The shifted `u256`.
|
|
530
|
+
*/
|
|
531
|
+
@inline @operator('>>>')
|
|
532
|
+
static shr_u(value: u256, shift: i32): u256 {
|
|
533
|
+
return u256.shr(value, shift);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
/**
|
|
537
|
+
* Checks if two `u256` values are equal.
|
|
538
|
+
* @param {u256} a - The first operand.
|
|
539
|
+
* @param {u256} b - The second operand.
|
|
540
|
+
* @returns {boolean} - True if the two values are equal, otherwise false.
|
|
541
|
+
*/
|
|
542
|
+
@inline @operator('==')
|
|
543
|
+
static eq(a: u256, b: u256): bool {
|
|
544
|
+
return a.lo1 == b.lo1 && a.lo2 == b.lo2 && a.hi1 == b.hi1 && a.hi2 == b.hi2;
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Checks if two `u256` values are not equal.
|
|
549
|
+
* @param {u256} a - The first operand.
|
|
550
|
+
* @param {u256} b - The second operand.
|
|
551
|
+
* @returns {boolean} - True if the two values differ, otherwise false.
|
|
552
|
+
*/
|
|
553
|
+
@inline @operator('!=')
|
|
554
|
+
static ne(a: u256, b: u256): bool {
|
|
555
|
+
return !u256.eq(a, b);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
/**
|
|
559
|
+
* Checks if `a < b`.
|
|
560
|
+
* @param {u256} a - The first operand.
|
|
561
|
+
* @param {u256} b - The second operand.
|
|
562
|
+
* @returns {boolean} - True if `a` is less than `b`, otherwise false.
|
|
563
|
+
*/
|
|
564
|
+
@operator('<')
|
|
565
|
+
static lt(a: u256, b: u256): bool {
|
|
566
|
+
if (a.hi2 != b.hi2) return a.hi2 < b.hi2;
|
|
567
|
+
if (a.hi1 != b.hi1) return a.hi1 < b.hi1;
|
|
568
|
+
if (a.lo2 != b.lo2) return a.lo2 < b.lo2;
|
|
569
|
+
return a.lo1 < b.lo1;
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
@inline @operator('>')
|
|
573
|
+
static gt(a: u256, b: u256): bool { return b < a; }
|
|
574
|
+
@inline @operator('<=')
|
|
575
|
+
static le(a: u256, b: u256): bool { return !u256.gt(a, b); }
|
|
576
|
+
@inline @operator('>=')
|
|
577
|
+
static ge(a: u256, b: u256): bool { return !u256.lt(a, b); }
|
|
578
|
+
|
|
579
|
+
@inline @operator('*')
|
|
580
|
+
static mul(a: u256, b: u256): u256 {
|
|
581
|
+
return __mul256(a.lo1, a.lo2, a.hi1, a.hi2, b.lo1, b.lo2, b.hi1, b.hi2);
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
/**
|
|
585
|
+
* Counts the number of set bits (1s) in the `u256`.
|
|
586
|
+
* @param {u256} value - The `u256` to count bits for.
|
|
587
|
+
* @returns {i32} - The number of bits set to 1.
|
|
588
|
+
*/
|
|
589
|
+
@inline
|
|
590
|
+
static popcnt(value: u256): i32 {
|
|
591
|
+
return <i32>(popcnt(value.lo1) + popcnt(value.lo2) + popcnt(value.hi1) + popcnt(value.hi2));
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/**
|
|
595
|
+
* Counts leading zeros in the `u256`.
|
|
596
|
+
* @param {u256} value - The `u256` to evaluate.
|
|
597
|
+
* @returns {i32} - The number of leading zero bits.
|
|
598
|
+
*/
|
|
599
|
+
@inline
|
|
600
|
+
static clz(value: u256): i32 {
|
|
601
|
+
if (value.hi2) return <i32>clz(value.hi2);
|
|
602
|
+
if (value.hi1) return <i32>(clz(value.hi1) + 64);
|
|
603
|
+
if (value.lo2) return <i32>(clz(value.lo2) + 128);
|
|
604
|
+
if (value.lo1) return <i32>(clz(value.lo1) + 192);
|
|
605
|
+
return 256;
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
/**
|
|
609
|
+
* Counts trailing zeros in the `u256`.
|
|
610
|
+
* @param {u256} value - The `u256` to evaluate.
|
|
611
|
+
* @returns {i32} - The number of trailing zero bits.
|
|
612
|
+
*/
|
|
613
|
+
@inline
|
|
614
|
+
static ctz(value: u256): i32 {
|
|
615
|
+
if (value.lo1) return <i32>ctz(value.lo1);
|
|
616
|
+
if (value.lo2) return <i32>(ctz(value.lo2) + 64);
|
|
617
|
+
if (value.hi1) return <i32>(ctz(value.hi1) + 128);
|
|
618
|
+
if (value.hi2) return <i32>(ctz(value.hi2) + 192);
|
|
619
|
+
return 256;
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
/**
|
|
623
|
+
* Sets the value of this `u256` to another `u256`.
|
|
624
|
+
* @param {u256} value - The source `u256`.
|
|
625
|
+
* @returns {this} - The current instance.
|
|
626
|
+
*/
|
|
627
|
+
@inline
|
|
628
|
+
set(value: u256): this {
|
|
629
|
+
this.lo1 = value.lo1; this.lo2 = value.lo2; this.hi1 = value.hi1; this.hi2 = value.hi2;
|
|
630
|
+
return this;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
/**
|
|
634
|
+
* Sets the lower 128 bits of this `u256` from a `u128`, resetting the higher 128 bits to zero.
|
|
635
|
+
* @param {u128} value - The source 128-bit unsigned integer.
|
|
636
|
+
* @returns {this} - The current instance.
|
|
637
|
+
*/
|
|
638
|
+
@inline
|
|
639
|
+
setU128(value: u128): this {
|
|
640
|
+
this.lo1 = value.lo; this.lo2 = value.hi; this.hi1 = 0; this.hi2 = 0;
|
|
641
|
+
return this;
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Sets this `u256` to the sign-extended value of a 64-bit signed integer.
|
|
646
|
+
* @param {i64} value - The 64-bit signed integer.
|
|
647
|
+
* @returns {this} - The current instance.
|
|
648
|
+
*/
|
|
649
|
+
@inline
|
|
650
|
+
setI64(value: i64): this {
|
|
651
|
+
let mask: u64 = value >> 63;
|
|
652
|
+
this.lo1 = <u64>value; this.lo2 = mask; this.hi1 = mask; this.hi2 = mask;
|
|
653
|
+
return this;
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
/**
|
|
657
|
+
* Sets this `u256` to the specified 64-bit unsigned integer, clearing higher bits.
|
|
658
|
+
* @param {u64} value - The 64-bit unsigned integer.
|
|
659
|
+
* @returns {this} - The current instance.
|
|
660
|
+
*/
|
|
661
|
+
@inline
|
|
662
|
+
setU64(value: u64): this {
|
|
663
|
+
this.lo1 = value; this.lo2 = 0; this.hi1 = 0; this.hi2 = 0;
|
|
664
|
+
return this;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
/**
|
|
668
|
+
* Sets this `u256` to the sign-extended value of a 32-bit signed integer.
|
|
669
|
+
* @param {i32} value - The 32-bit signed integer.
|
|
670
|
+
* @returns {this} - The current instance.
|
|
671
|
+
*/
|
|
672
|
+
@inline
|
|
673
|
+
setI32(value: i32): this {
|
|
674
|
+
let mask: u64 = value >> 63;
|
|
675
|
+
this.lo1 = value; this.lo2 = mask; this.hi1 = mask; this.hi2 = mask;
|
|
676
|
+
return this;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Sets this `u256` to the specified 32-bit unsigned integer, clearing higher bits.
|
|
681
|
+
* @param {u32} value - The 32-bit unsigned integer.
|
|
682
|
+
* @returns {this} - The current instance.
|
|
683
|
+
*/
|
|
684
|
+
@inline
|
|
685
|
+
setU32(value: u32): this {
|
|
686
|
+
this.lo1 = value; this.lo2 = 0; this.hi1 = 0; this.hi2 = 0;
|
|
687
|
+
return this;
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
/**
|
|
691
|
+
* Checks if this `u256` is equal to zero.
|
|
692
|
+
* @returns {boolean} - True if zero, false otherwise.
|
|
693
|
+
*/
|
|
694
|
+
@inline
|
|
695
|
+
isZero(): bool {
|
|
696
|
+
return !(this.lo1 | this.lo2 | this.hi1 | this.hi2);
|
|
697
|
+
}
|
|
698
|
+
|
|
699
|
+
/**
|
|
700
|
+
* Performs a bitwise NOT operation (`~`) on the current `u256`.
|
|
701
|
+
* @returns {u256} - A new `u256` with inverted bits.
|
|
702
|
+
*/
|
|
703
|
+
@inline @operator.prefix('~')
|
|
704
|
+
not(): u256 {
|
|
705
|
+
return new u256(~this.lo1, ~this.lo2, ~this.hi1, ~this.hi2);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
/**
|
|
709
|
+
* A unary plus operator, returning the current `u256` without changes.
|
|
710
|
+
* @returns {u256} - The current `u256`.
|
|
711
|
+
*/
|
|
712
|
+
@inline @operator.prefix('+')
|
|
713
|
+
pos(): u256 { return this; }
|
|
714
|
+
|
|
715
|
+
/**
|
|
716
|
+
* A unary negation operator (`-x`), computed as `~x + 1`.
|
|
717
|
+
* @returns {u256} - A new `u256` representing the negated value (mod 2^256).
|
|
718
|
+
*/
|
|
719
|
+
@operator.prefix('-')
|
|
720
|
+
neg(): u256 {
|
|
721
|
+
let lo1 = ~this.lo1, lo2 = ~this.lo2, hi1 = ~this.hi1, hi2 = ~this.hi2;
|
|
722
|
+
let sum = lo1 + 1;
|
|
723
|
+
let carry = (sum < lo1) ? 1 : 0;
|
|
724
|
+
lo1 = sum;
|
|
725
|
+
sum = lo2 + carry;
|
|
726
|
+
carry = (sum < lo2) ? 1 : 0;
|
|
727
|
+
lo2 = sum;
|
|
728
|
+
sum = hi1 + carry;
|
|
729
|
+
carry = (sum < hi1) ? 1 : 0;
|
|
730
|
+
hi1 = sum;
|
|
731
|
+
hi2 = hi2 + carry;
|
|
732
|
+
return new u256(lo1, lo2, hi1, hi2);
|
|
733
|
+
}
|
|
734
|
+
|
|
735
|
+
@operator.prefix("++")
|
|
736
|
+
public preInc(): this {
|
|
737
|
+
let sum = this.lo1 + 1;
|
|
738
|
+
let carry = sum < this.lo1 ? 1 : 0;
|
|
739
|
+
this.lo1 = sum;
|
|
740
|
+
sum = this.lo2 + carry;
|
|
741
|
+
carry = sum < this.lo2 ? 1 : 0;
|
|
742
|
+
this.lo2 = sum;
|
|
743
|
+
sum = this.hi1 + carry;
|
|
744
|
+
carry = sum < this.hi1 ? 1 : 0;
|
|
745
|
+
this.hi1 = sum;
|
|
746
|
+
this.hi2 += carry;
|
|
747
|
+
return this;
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
@operator.prefix("--")
|
|
751
|
+
public preDec(): this {
|
|
752
|
+
let diff = this.lo1 - 1;
|
|
753
|
+
let borrow = (diff > this.lo1) ? 1 : 0;
|
|
754
|
+
this.lo1 = diff;
|
|
755
|
+
diff = this.lo2 - borrow;
|
|
756
|
+
borrow = (diff > this.lo2) ? 1 : 0;
|
|
757
|
+
this.lo2 = diff;
|
|
758
|
+
diff = this.hi1 - borrow;
|
|
759
|
+
borrow = (diff > this.hi1) ? 1 : 0;
|
|
760
|
+
this.hi1 = diff;
|
|
761
|
+
this.hi2 -= borrow;
|
|
762
|
+
return this;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
@inline @operator.postfix('++')
|
|
766
|
+
postInc(): u256 { return this.clone().preInc(); }
|
|
767
|
+
|
|
768
|
+
@inline @operator.postfix('--')
|
|
769
|
+
postDec(): u256 { return this.clone().preDec(); }
|
|
770
|
+
|
|
771
|
+
/**
|
|
772
|
+
* Converts this `u256` to a generic type `T`.
|
|
773
|
+
* Supported types: bool, i8, u8, i16, u16, i32, u32, i64, u64, i128, u128, u256, u8[], Uint8Array, StaticArray<u8>, string.
|
|
774
|
+
* @returns {T} - The converted value.
|
|
775
|
+
*/
|
|
776
|
+
@inline
|
|
777
|
+
as<T>(): T {
|
|
778
|
+
if (isReference<T>()) {
|
|
779
|
+
let typeName = nameof<T>();
|
|
780
|
+
if (typeName.indexOf("Array<u8>") >= 0) return changetype<T>(this.toBytes());
|
|
781
|
+
else if (typeName.indexOf("Uint8Array") >= 0) return changetype<T>(this.toUint8Array());
|
|
782
|
+
else if (typeName.indexOf("StaticArray<u8>") >= 0) return changetype<T>(this.toStaticBytes());
|
|
783
|
+
else if (typeName.indexOf("String") >= 0) return changetype<T>(this.toString());
|
|
784
|
+
else if (typeName.indexOf("u128") >= 0) return changetype<T>(this.toU128());
|
|
785
|
+
else if (typeName.indexOf("i128") >= 0) return changetype<T>(this.toI128());
|
|
786
|
+
else if (typeName.indexOf("u256") >= 0) return changetype<T>(this.toU256());
|
|
787
|
+
else throw new TypeError(`Unsupported generic type ${typeName}`);
|
|
788
|
+
} else {
|
|
789
|
+
if (isInteger<T>()) {
|
|
790
|
+
if (sizeof<T>() == 1) return <T><u64>this.toU64();
|
|
791
|
+
else if (sizeof<T>() == 2) return <T><u64>this.toU64();
|
|
792
|
+
else if (sizeof<T>() == 4) return <T><u64>this.toU64();
|
|
793
|
+
else if (sizeof<T>() == 8) return <T>this.toU64();
|
|
794
|
+
else throw new TypeError(`Unsupported generic type ${nameof<T>()}`);
|
|
795
|
+
} else if (isFloat<T>()) {
|
|
796
|
+
return <T><f64>this.toU64();
|
|
797
|
+
} else {
|
|
798
|
+
// bool
|
|
799
|
+
return <T>this.toBool();
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
/**
|
|
805
|
+
* Converts this `u256` to a signed 128-bit integer (i128).
|
|
806
|
+
* The highest bit of the 256-bit value is sign bit for i128.
|
|
807
|
+
* @returns {i128} - The resulting `i128`.
|
|
808
|
+
*/
|
|
809
|
+
@inline
|
|
810
|
+
toI128(): i128 {
|
|
811
|
+
return new i128(this.lo1, (this.lo2 & 0x7FFFFFFFFFFFFFFF) | (this.hi2 & 0x8000000000000000));
|
|
812
|
+
}
|
|
813
|
+
|
|
814
|
+
/**
|
|
815
|
+
* Converts this `u256` to an unsigned 128-bit integer (u128).
|
|
816
|
+
* Truncates higher bits.
|
|
817
|
+
* @returns {u128} - The resulting `u128`.
|
|
818
|
+
*/
|
|
819
|
+
@inline
|
|
820
|
+
toU128(): u128 { return new u128(this.lo1, this.lo2); }
|
|
821
|
+
|
|
822
|
+
/**
|
|
823
|
+
* Returns this `u256` itself, effectively a no-op for `u256`.
|
|
824
|
+
* @returns {u256} - The current `u256`.
|
|
825
|
+
*/
|
|
826
|
+
@inline
|
|
827
|
+
toU256(): this { return this; }
|
|
828
|
+
|
|
829
|
+
/**
|
|
830
|
+
* Converts this `u256` to a signed 64-bit integer (i64).
|
|
831
|
+
* Truncates and treats the highest bit of the 256-bit as sign.
|
|
832
|
+
* @returns {i64} - The resulting 64-bit signed integer.
|
|
833
|
+
*/
|
|
834
|
+
@inline
|
|
835
|
+
toI64(): i64 { return <i64>( (this.lo1 & 0x7FFFFFFFFFFFFFFF) | (this.hi2 & 0x8000000000000000) ); }
|
|
836
|
+
|
|
837
|
+
/**
|
|
838
|
+
* Converts this `u256` to an unsigned 64-bit integer (u64).
|
|
839
|
+
* Truncates higher bits.
|
|
840
|
+
* @returns {u64} - The resulting 64-bit unsigned integer.
|
|
841
|
+
*/
|
|
842
|
+
@inline
|
|
843
|
+
toU64(): u64 { return this.lo1; }
|
|
844
|
+
|
|
845
|
+
/**
|
|
846
|
+
* Converts this `u256` to a signed 32-bit integer (i32).
|
|
847
|
+
* @returns {i32} - The resulting 32-bit signed integer.
|
|
848
|
+
*/
|
|
849
|
+
@inline
|
|
850
|
+
toI32(): i32 { return <i32>this.toI64(); }
|
|
851
|
+
|
|
852
|
+
/**
|
|
853
|
+
* Converts this `u256` to an unsigned 32-bit integer (u32).
|
|
854
|
+
* Truncates higher bits.
|
|
855
|
+
* @returns {u32} - The resulting 32-bit unsigned integer.
|
|
856
|
+
*/
|
|
857
|
+
@inline
|
|
858
|
+
toU32(): u32 { return <u32>this.lo1; }
|
|
859
|
+
|
|
860
|
+
/**
|
|
861
|
+
* Checks if the `u256` is non-zero, then returns `true`; otherwise `false`.
|
|
862
|
+
* @returns {boolean} - True if non-zero, otherwise false.
|
|
863
|
+
*/
|
|
864
|
+
@inline
|
|
865
|
+
toBool(): bool { return <bool>(this.lo1 | this.lo2 | this.hi1 | this.hi2); }
|
|
866
|
+
|
|
867
|
+
/**
|
|
868
|
+
* Converts this `u256` to an array of 32 bytes (u8[]).
|
|
869
|
+
* @param {boolean} [bigEndian=false] - Output in big-endian if true, else little-endian.
|
|
870
|
+
* @returns {u8[]} - The resulting byte array.
|
|
871
|
+
*/
|
|
872
|
+
@inline
|
|
873
|
+
toBytes(bigEndian: bool = false): u8[] {
|
|
874
|
+
let result = new Array<u8>(32);
|
|
875
|
+
this.toArrayBuffer(changetype<usize>(result.dataStart), bigEndian);
|
|
876
|
+
return result;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
/**
|
|
880
|
+
* Converts this `u256` to a static array of 32 bytes (StaticArray<u8>).
|
|
881
|
+
* @param {boolean} [bigEndian=false] - Output in big-endian if true, else little-endian.
|
|
882
|
+
* @returns {StaticArray<u8>} - The resulting static byte array.
|
|
883
|
+
*/
|
|
884
|
+
@inline
|
|
885
|
+
toStaticBytes(bigEndian: bool = false): StaticArray<u8> {
|
|
886
|
+
let result = new StaticArray<u8>(32);
|
|
887
|
+
this.toArrayBuffer(changetype<usize>(result), bigEndian);
|
|
888
|
+
return result;
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
/**
|
|
892
|
+
* Converts this `u256` to a `Uint8Array` of length 32.
|
|
893
|
+
* @param {boolean} [bigEndian=false] - Output in big-endian if true, else little-endian.
|
|
894
|
+
* @returns {Uint8Array} - The resulting `Uint8Array`.
|
|
895
|
+
*/
|
|
896
|
+
@inline
|
|
897
|
+
toUint8Array(bigEndian: bool = false): Uint8Array {
|
|
898
|
+
let result = new Uint8Array(32);
|
|
899
|
+
this.toArrayBuffer(changetype<usize>(result.dataStart), bigEndian);
|
|
900
|
+
return result;
|
|
901
|
+
}
|
|
902
|
+
|
|
903
|
+
/**
|
|
904
|
+
* Creates and returns a clone (deep copy) of this `u256`.
|
|
905
|
+
* @returns {u256} - A new `u256` instance with the same value.
|
|
906
|
+
*/
|
|
907
|
+
clone(): u256 { return new u256(this.lo1, this.lo2, this.hi1, this.hi2); }
|
|
908
|
+
|
|
909
|
+
/**
|
|
910
|
+
* Converts this `u256` to a string in either decimal or hexadecimal format.
|
|
911
|
+
* @param {i32} [radix=10] - The base (10 or 16).
|
|
912
|
+
* @throws {Error} If `radix` is not 10 or 16.
|
|
913
|
+
* @returns {string} - The string representation of the `u256`.
|
|
914
|
+
*/
|
|
915
|
+
toString(radix: i32 = 10): string {
|
|
916
|
+
assert(radix == 10 || radix == 16, 'radix argument must be between 10 or 16');
|
|
917
|
+
if (this.isZero()) return '0';
|
|
918
|
+
if (radix == 16) {
|
|
919
|
+
let result = '';
|
|
920
|
+
let shift: i32 = 252 - (u256.clz(this) & ~3);
|
|
921
|
+
while (shift >= 0) {
|
|
922
|
+
// @ts-ignore
|
|
923
|
+
result += HEX_CHARS.charAt(<i32>((this >> shift).lo1 & 15));
|
|
924
|
+
shift -= 4;
|
|
925
|
+
}
|
|
926
|
+
return result;
|
|
927
|
+
}
|
|
928
|
+
return u256toDecimalString(this);
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/**
|
|
932
|
+
* @private
|
|
933
|
+
* Stores this `u256` into a buffer in little-endian format.
|
|
934
|
+
* @param {usize} buffer - The buffer start pointer.
|
|
935
|
+
*/
|
|
936
|
+
// --- INTERNAL HELPERS FOR DIV OPTIMIZATION ---
|
|
937
|
+
// These allow in-place mutation to avoid allocations inside the div loop.
|
|
938
|
+
|
|
939
|
+
/** In-place subtraction. Assumes this >= other. */
|
|
940
|
+
@inline
|
|
941
|
+
private subAssign(other: u256): void {
|
|
942
|
+
let lo1 = sub64(this.lo1, other.lo1, 0);
|
|
943
|
+
let b1 = __u256carrySub;
|
|
944
|
+
let lo2 = sub64(this.lo2, other.lo2, b1);
|
|
945
|
+
let b2 = __u256carrySub;
|
|
946
|
+
let hi1 = sub64(this.hi1, other.hi1, b2);
|
|
947
|
+
let b3 = __u256carrySub;
|
|
948
|
+
let hi2 = sub64(this.hi2, other.hi2, b3);
|
|
949
|
+
this.lo1 = lo1; this.lo2 = lo2; this.hi1 = hi1; this.hi2 = hi2;
|
|
950
|
+
}
|
|
951
|
+
|
|
952
|
+
/** In-place bit set: this |= (1 << bit) */
|
|
953
|
+
@inline
|
|
954
|
+
private orAssignBit(bit: i32): void {
|
|
955
|
+
const bits = 64;
|
|
956
|
+
const seg = (bit / bits) | 0;
|
|
957
|
+
const shift = bit % bits;
|
|
958
|
+
// FIX: Explicitly cast literal 1 to u64 to ensure proper 64-bit shifting
|
|
959
|
+
const mask: u64 = <u64>1 << shift;
|
|
960
|
+
if (seg == 0) this.lo1 |= mask;
|
|
961
|
+
else if (seg == 1) this.lo2 |= mask;
|
|
962
|
+
else if (seg == 2) this.hi1 |= mask;
|
|
963
|
+
else if (seg == 3) this.hi2 |= mask;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/** In-place right shift by 1. */
|
|
967
|
+
@inline
|
|
968
|
+
private rshiftOne(): void {
|
|
969
|
+
this.lo1 = (this.lo1 >>> 1) | (this.lo2 << 63);
|
|
970
|
+
this.lo2 = (this.lo2 >>> 1) | (this.hi1 << 63);
|
|
971
|
+
this.hi1 = (this.hi1 >>> 1) | (this.hi2 << 63);
|
|
972
|
+
this.hi2 = (this.hi2 >>> 1);
|
|
973
|
+
}
|
|
974
|
+
|
|
975
|
+
@inline
|
|
976
|
+
private toArrayBufferLE(buffer: usize): void {
|
|
977
|
+
store<u64>(buffer, this.lo1, 0);
|
|
978
|
+
store<u64>(buffer, this.lo2, 8);
|
|
979
|
+
store<u64>(buffer, this.hi1, 16);
|
|
980
|
+
store<u64>(buffer, this.hi2, 24);
|
|
981
|
+
}
|
|
982
|
+
|
|
983
|
+
/**
|
|
984
|
+
* @private
|
|
985
|
+
* Stores this `u256` into a buffer in big-endian format.
|
|
986
|
+
* @param {usize} buffer - The buffer start pointer.
|
|
987
|
+
*/
|
|
988
|
+
@inline
|
|
989
|
+
private toArrayBufferBE(buffer: usize): void {
|
|
990
|
+
store<u64>(buffer, bswap(this.hi2), 0);
|
|
991
|
+
store<u64>(buffer, bswap(this.hi1), 8);
|
|
992
|
+
store<u64>(buffer, bswap(this.lo2), 16);
|
|
993
|
+
store<u64>(buffer, bswap(this.lo1), 24);
|
|
994
|
+
}
|
|
995
|
+
|
|
996
|
+
/**
|
|
997
|
+
* @private
|
|
998
|
+
* Stores this `u256` into a buffer in either little-endian or big-endian format.
|
|
999
|
+
* @param {usize} buffer - The buffer start pointer.
|
|
1000
|
+
* @param {boolean} [bigEndian=false] - Use big-endian if true, else little-endian.
|
|
1001
|
+
*/
|
|
1002
|
+
@inline
|
|
1003
|
+
private toArrayBuffer(buffer: usize, bigEndian: bool = false): void {
|
|
1004
|
+
if (bigEndian) this.toArrayBufferBE(buffer);
|
|
1005
|
+
else this.toArrayBufferLE(buffer);
|
|
1006
|
+
}
|
|
1007
|
+
}
|