s2-tools
Version:
A collection of geospatial tools primarily designed for WGS84, Web Mercator, and S2.
304 lines • 9.34 kB
JavaScript
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