-
Notifications
You must be signed in to change notification settings - Fork 3.4k
/
Copy pathbigint64array.js
121 lines (115 loc) · 4.23 KB
/
bigint64array.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#if !POLYFILL
#error "this file should never be included unless POLYFILL is set"
#endif
if (typeof globalThis.BigInt64Array === "undefined") {
// BigInt64Array polyfill for Safari versions between v14.0 and v15.0.
// All browsers other than Safari added BigInt and BigInt64Array at the same
// time, but Safari introduced BigInt in v14.0 and introduced BigInt64Array in
// v15.0
function partsToBigIntSigned(lower, upper) {
return BigInt(lower) | (BigInt(upper + 2 * (upper & 0x80000000)) << 32n);
}
function partsToBigIntUnsigned(lower, upper) {
return BigInt(lower) | (BigInt(upper) << 32n);
}
function bigIntToParts(value) {
var lower = Number(BigInt(value) & BigInt(0xffffffff)) | 0;
var upper = Number(BigInt(value) >> 32n) | 0;
return [lower, upper];
}
function createBigIntArrayShim(partsToBigInt) {
/**
* Closure thinks .set is not defined on Proxy objects for some reason. The
* error is on the line with proxy.set but we can only apply the
* suppression at the function level here.
* @suppress {missingProperties}
*/
function createBigInt64Array(array) {
if (typeof array === "number") {
array = new Uint32Array(2 * array);
}
var orig_array;
if (!ArrayBuffer.isView(array)) {
if (array.constructor && array.constructor.name === "ArrayBuffer") {
array = new Uint32Array(array);
} else {
orig_array = array;
array = new Uint32Array(array.length * 2);
}
}
var proxy = new Proxy(
{
slice: function (min, max) {
if (max === undefined) {
max = array.length;
}
var new_buf = array.slice(min * 2, max * 2);
return createBigInt64Array(new_buf);
},
subarray: function (min, max) {
var new_buf = array.subarray(min * 2, max * 2);
return createBigInt64Array(new_buf);
},
[Symbol.iterator]: function* () {
for (var i = 0; i < array.length / 2; i++) {
yield partsToBigInt(array[2 * i], array[2 * i + 1]);
}
},
BYTES_PER_ELEMENT: 2 * array.BYTES_PER_ELEMENT,
buffer: array.buffer,
byteLength: array.byteLength,
byteOffset: array.byteOffset,
length: array.length / 2,
copyWithin: function (target, start, end) {
array.copyWithin(target * 2, start * 2, end * 2);
return proxy;
},
set: function (source, targetOffset) {
if (targetOffset === undefined) {
targetOffset = 0;
}
if (2 * (source.length + targetOffset) > array.length) {
// This is the Chrome error message
// Firefox: "invalid or out-of-range index"
throw new RangeError("offset is out of bounds");
}
for (var i = 0; i < source.length; i++) {
var value = source[i];
var pair = bigIntToParts(value);
array.set(pair, 2 * (targetOffset + i));
}
},
},
{
get: function (target, idx, receiver) {
if (typeof idx !== "string" || !/^\d+$/.test(idx)) {
return Reflect.get(target, idx, receiver);
}
var lower = array[idx * 2];
var upper = array[idx * 2 + 1];
return partsToBigInt(lower, upper);
},
set: function (target, idx, value, receiver) {
if (typeof idx !== "string" || !/^\d+$/.test(idx)) {
return Reflect.set(target, idx, value, receiver);
}
if (typeof value !== "bigint") {
// Chrome error message, Firefox has no "a" in front if "BigInt".
throw new TypeError(`Cannot convert ${value} to a BigInt`);
}
var pair = bigIntToParts(value);
array.set(pair, 2 * idx);
return true;
},
}
);
if (orig_array) {
proxy.set(orig_array);
}
return proxy;
}
return createBigInt64Array;
}
globalThis.BigUint64Array = createBigIntArrayShim(partsToBigIntUnsigned);
globalThis.BigInt64Array = createBigIntArrayShim(partsToBigIntSigned);
}