UNPKG

s2-tools

Version:

A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.

304 lines 9.34 kB
import { base64ToArrayBuffer } from '../util'; import wasmBase64 from './uint64.wasm'; /** Generator that builds Uint64Cells from either lon/lat or face/s/t */ export class Uint64CellGenerator { instance; wasmMemory; tmpString = ''; #finalizationRegistry; /** Creates an instance of Uint64CellGenerator that manages the wasm memory */ constructor() { const mod = new WebAssembly.Module(base64ToArrayBuffer(wasmBase64)); this.instance = new WebAssembly.Instance(mod, { env: {}, }); this.#finalizationRegistry = new FinalizationRegistry((id) => { const freeUint64 = this.instance.exports.free_s2_cell_id; freeUint64(id); }); } /** * @param type - left shift or right shift * @param bits - number of bits * @param input - Uint64 to shift * @returns - shifted Uint64 */ shift(type, bits, input) { const shift = type === 'LEFT' ? this.instance.exports.shift_left : this.instance.exports.shift_right; const id = shift(input.id, bits); const cell = new Uint64Cell(id); // Register the id with the finalization registry to ensure it gets freed this.#finalizationRegistry.register(cell, id); return cell; } /** * @param type - `ADD` | `SUB` | `DIV` | `MUL` | `BIT_AND` | `BIT_OR` | `BIT_XOR` * @param a - first Uint64 * @param b - second Uint64 * @returns - resultant Uint64 */ math(type, a, b) { const math = this.#getMath(type); const id = math(a.id, b.id); const cell = new Uint64Cell(id); // Register the id with the finalization registry to ensure it gets freed this.#finalizationRegistry.register(cell, id); return cell; } /** * @param type - `ADD` | `SUB` | `DIV` | `MUL` | `BIT_AND` | `BIT_OR` | `BIT_XOR` * @returns - the appropriate wasm function */ #getMath(type) { if (type === 'ADD') return this.instance.exports.add; if (type === 'SUB') return this.instance.exports.sub; if (type === 'DIV') return this.instance.exports.div; if (type === 'MUL') return this.instance.exports.mul; if (type === 'BIT_AND') return this.instance.exports.bit_and; if (type === 'BIT_OR') return this.instance.exports.bit_or; if (type === 'BIT_XOR') return this.instance.exports.bit_xor; throw new Error(`Unknown math type ${type}`); } /** * @param input - Uint64 to invert * @returns - inverted Uint64 */ not(input) { const bit_not = this.instance.exports.bit_not; const id = bit_not(input.id); const cell = new Uint64Cell(id); // Register the id with the finalization registry to ensure it gets freed this.#finalizationRegistry.register(cell, id); return cell; } /** * Convert a low/high pair to an Uint64Cell representation * @param low - low 32 bits * @param high - high 32 bits * @returns - an Uint64Cell with the appropriate id and functions */ fromLowHigh(low, high) { const _fromLowHigh = this.instance.exports.from_low_high; const id = _fromLowHigh(low, high); const cell = new Uint64Cell(id); // Register the id with the finalization registry to ensure it gets freed this.#finalizationRegistry.register(cell, id); return cell; } } const cellGen = new Uint64CellGenerator(); /** * A 64 bit unsigned integer */ export class Uint64Cell { id; /** @param id - a number to convert */ constructor(id) { this.id = id; } /** * @param id - a number to convert * @returns - an Uint64Cell with the appropriate id and functions */ static fromNumber(id) { return cellGen.fromLowHigh(id >>> 0, Math.floor(id / 0x100000000) >>> 0); } /** * NOTE: The whole point of this package is to avoid bigint, but for testing we need to be able * to verify large numbers in a convenient way. * @param id - a bigint * @returns the Uint64Cell */ static fromBigint(id) { return cellGen.fromLowHigh(Number(id & 0xffffffffn), Number((id >> 32n) & 0xffffffffn)); } /** * @param low - low 32 bits * @param high - high 32 bits * @returns - an Uint64Cell with the appropriate id and functions */ static fromLowHigh(low, high) { return cellGen.fromLowHigh(low, high); } /** * @param bits - number of bits * @returns - shifted Uint64 */ shiftLeft(bits) { return cellGen.shift('LEFT', bits, this); } /** * @param bits - number of bits * @returns - shifted Uint64 */ shiftRight(bits) { return cellGen.shift('RIGHT', bits, this); } /** * @returns - inverted Uint64 */ not() { return cellGen.not(this); } /** * @param b - the number to compare * @returns - the sum of `this` and `b` */ add(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('ADD', this, b); } /** * @param b - the number to compare * @returns - the difference of `this` and `b` */ sub(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('SUB', this, b); } /** * @param b - the number to compare * @returns - the product of `this` and `b` */ mul(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('MUL', this, b); } /** * @param b - the number to compare * @returns - the quotient of `this` and `b` */ div(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('DIV', this, b); } /** * @param b - the number to compare * @returns - the and of `this` and `b` */ bitAnd(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('BIT_AND', this, b); } /** * @param b - the number to compare * @returns - the or of `this` and `b` */ bitOr(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('BIT_OR', this, b); } /** * @param b - the number to compare * @returns - the xor of `this` and `b` */ bitXor(b) { b = typeof b === 'number' ? Uint64(b) : b; return cellGen.math('BIT_XOR', this, b); } /** * @returns - low and high bits of `this` */ toLoHi() { const low_bits = cellGen.instance.exports.low_bits; const high_bits = cellGen.instance.exports.high_bits; return { lo: low_bits(this.id) >>> 0, hi: high_bits(this.id) >>> 0, }; } /** * Convert the Uint64Cell to a bigint. * NOTE: The whole point of this package is to avoid bigint, but for testing we need to be able * to verify large numbers in a convenient way. * @returns the bigint */ toBigInt() { const loHi = this.toLoHi(); return BigInt(loHi.lo) + (BigInt(loHi.hi) << 32n); } /** @returns the number representation of the Uint64Cell. May lose precision. */ toNumber() { const loHi = this.toLoHi(); return loHi.lo + loHi.hi * 2 ** 32; } /** * @param b - the number to compare * @returns - -1 if `this` is less than `b`, 0 if `this` is equal to `b`, 1 if `this` is greater than `b` */ compare(b) { const comparitor = cellGen.instance.exports.compare_uint64; b = typeof b === 'number' ? Uint64(b) : b; return comparitor(this.id, b.id); } /** * @param b - the number to compare * @returns - true if `this` is equal to `b` */ eq(b) { return this.compare(b) === 0; } /** * @param b - the number to compare * @returns - true if `this` is not equal to `b` */ neq(b) { return this.compare(b) !== 0; } /** * @param b - the number to compare * @returns - true if `this` is less than `b` */ lt(b) { return this.compare(b) === -1; } /** * @param b - the number to compare * @returns - true if `this` is less than or equal to `b` */ lte(b) { return this.compare(b) <= 0; } /** * @param b - the number to compare * @returns - true if `this` is greater than `b` */ gt(b) { return this.compare(b) === 1; } /** * @param b - the number to compare * @returns - true if `this` is greater than or equal to `b` */ gte(b) { return this.compare(b) >= 0; } } /** * Convenience function to convert a number to an Uint64Cell * @param input - the number to convert * @returns - an Uint64Cell with the appropriate id and functions */ export function Uint64(input) { if (typeof input !== 'number') return input; return Uint64Cell.fromNumber(input); } /** * @param lo - low 32 bits * @param hi - high 32 bits * @returns - an Uint64Cell with the appropriate id and functions */ export function Uint64LoHi(lo, hi) { return cellGen.fromLowHigh(lo, hi); } //# sourceMappingURL=uint64.js.map