1220a577a2
900 Port in process: DO NOT USE IT.
134 lines
3.5 KiB
JavaScript
134 lines
3.5 KiB
JavaScript
/* Copyright (C) 2023-2025 anonymous
|
|
|
|
This file is part of PSFree.
|
|
|
|
PSFree is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU Affero General Public License as
|
|
published by the Free Software Foundation, either version 3 of the
|
|
License, or (at your option) any later version.
|
|
|
|
PSFree is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU Affero General Public License for more details.
|
|
|
|
You should have received a copy of the GNU Affero General Public License
|
|
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
|
|
|
// cache some constants
|
|
const isInteger = Number.isInteger;
|
|
|
|
function check_not_in_range(x) {
|
|
return !(isInteger(x) && -0x80000000 <= x && x <= 0xffffffff);
|
|
}
|
|
|
|
// use this if you want to support objects convertible to Int but only need
|
|
// their low/high bits. creating a Int is slower compared to just using this
|
|
// function
|
|
export function lohi_from_one(low) {
|
|
if (low instanceof Int) {
|
|
return low._u32.slice();
|
|
}
|
|
|
|
if (check_not_in_range(low)) {
|
|
throw TypeError(`low not a 32-bit integer: ${low}`);
|
|
}
|
|
|
|
return [low >>> 0, low < 0 ? -1 >>> 0 : 0];
|
|
}
|
|
|
|
// immutable 64-bit integer
|
|
export class Int {
|
|
constructor(low, high) {
|
|
if (high === undefined) {
|
|
this._u32 = new Uint32Array(lohi_from_one(low));
|
|
return;
|
|
}
|
|
|
|
if (check_not_in_range(low)) {
|
|
throw TypeError(`low not a 32-bit integer: ${low}`);
|
|
}
|
|
|
|
if (check_not_in_range(high)) {
|
|
throw TypeError(`high not a 32-bit integer: ${high}`);
|
|
}
|
|
|
|
this._u32 = new Uint32Array([low, high]);
|
|
}
|
|
|
|
get lo() {
|
|
return this._u32[0];
|
|
}
|
|
|
|
get hi() {
|
|
return this._u32[1];
|
|
}
|
|
|
|
// return low/high as signed integers
|
|
|
|
get bot() {
|
|
return this._u32[0] | 0;
|
|
}
|
|
|
|
get top() {
|
|
return this._u32[1] | 0;
|
|
}
|
|
|
|
neg() {
|
|
const u32 = this._u32;
|
|
const low = (~u32[0] >>> 0) + 1;
|
|
return new this.constructor(
|
|
low >>> 0,
|
|
((~u32[1] >>> 0) + (low > 0xffffffff)) >>> 0,
|
|
);
|
|
}
|
|
|
|
eq(b) {
|
|
const values = lohi_from_one(b);
|
|
const u32 = this._u32;
|
|
return (
|
|
u32[0] === values[0]
|
|
&& u32[1] === values[1]
|
|
);
|
|
}
|
|
|
|
ne(b) {
|
|
return !this.eq(b);
|
|
}
|
|
|
|
add(b) {
|
|
const values = lohi_from_one(b);
|
|
const u32 = this._u32;
|
|
const low = u32[0] + values[0];
|
|
return new this.constructor(
|
|
low >>> 0,
|
|
(u32[1] + values[1] + (low > 0xffffffff)) >>> 0,
|
|
);
|
|
}
|
|
|
|
sub(b) {
|
|
const values = lohi_from_one(b);
|
|
const u32 = this._u32;
|
|
const low = u32[0] + (~values[0] >>> 0) + 1;
|
|
return new this.constructor(
|
|
low >>> 0,
|
|
(u32[1] + (~values[1] >>> 0) + (low > 0xffffffff)) >>> 0,
|
|
);
|
|
}
|
|
|
|
toString(is_pretty=false) {
|
|
if (!is_pretty) {
|
|
const low = this.lo.toString(16).padStart(8, '0');
|
|
const high = this.hi.toString(16).padStart(8, '0');
|
|
return '0x' + high + low;
|
|
}
|
|
let high = this.hi.toString(16).padStart(8, '0');
|
|
high = high.substring(0, 4) + '_' + high.substring(4);
|
|
|
|
let low = this.lo.toString(16).padStart(8, '0');
|
|
low = low.substring(0, 4) + '_' + low.substring(4);
|
|
|
|
return '0x' + high + '_' + low;
|
|
}
|
|
}
|