Files
Kameleon 1220a577a2 Update to psfree-1.5rc1
900 Port in process: DO NOT USE IT.
2025-05-10 09:34:58 -06:00

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;
}
}