/* 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 . */ // 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; } }