Skip to content

Instantly share code, notes, and snippets.

@jhmaster2000
Created October 6, 2023 02:53
Show Gist options
  • Save jhmaster2000/21482f2fdf20b580b94fe1ecb33dbda7 to your computer and use it in GitHub Desktop.
Save jhmaster2000/21482f2fdf20b580b94fe1ecb33dbda7 to your computer and use it in GitHub Desktop.
Array with irrational number indexes, PoC
// Because JS isn't cursed enough :)
import util from 'node:util';
class IrrationalArray extends Array {
constructor(...args: any[]) {
super(...args);
const indexes = Object.keys(this).filter(key => !Number.isNaN(Number(key))).map(key => Number(key)).sort((a, b) => a - b);
for (const index of indexes) this._data.set(index, this[index]);
super.length = 0;
return new Proxy(this, {
get(target, prop) {
const index = Number(prop);
if (!Number.isNaN(index)) return target._data.get(index);
if (prop === 'length') return target._length;
return Reflect.get(target, prop, target);
},
defineProperty(target, prop, descriptor) {
const index = Number(prop);
if (!Number.isNaN(index)) {
const isNewProp = !target._data.has(index);
target._data.set(index, descriptor.value);
if (isNewProp) target._reSort();
return true;
}
return Reflect.defineProperty(target, prop, descriptor);
},
deleteProperty(target, prop) {
const index = Number(prop);
if (!Number.isNaN(index)) {
target._data.delete(index);
return true;
}
return Reflect.deleteProperty(target, prop);
}
});
}
private readonly _data: Map<number, unknown> = new Map();
private _reSort(): void {
const entries = [...this._data.entries()].sort(([a0], [b0]) => a0 - b0);
this._data.clear();
for (const [index, value] of entries) this._data.set(index, value);
}
private get _indexes(): number[] { return [...this._data.keys()]; }
private get _lowestIndex(): number { return Math.min(...this._indexes); }
private get _highestIndex(): number { return Math.max(...this._indexes); }
private get _values(): unknown[] { return [...this._data.values()]; }
private get _length(): number { return this._data.size; }
override push(...items: unknown[]): number {
let index = this._highestIndex;
for (const item of items) {
let incr = 0; while (index === (index +=++ incr));
if (index === Infinity) throw new RangeError('Cannot push beyond infinity');
this._data.set(index, item);
}
return this._length;
}
override pop(): unknown {
const value = this._data.get(this._highestIndex);
this._data.delete(this._highestIndex);
return value;
}
override shift(): unknown {
const value = this._data.get(this._lowestIndex);
this._data.delete(this._lowestIndex);
return value;
}
override unshift(...items: unknown[]): number {
let index = this._lowestIndex;
for (const item of items) {
let decr = 0; while (index === (index -=++ decr));
if (index === -Infinity) throw new RangeError('Cannot unshift beyond negative infinity');
this._data.set(index, item);
}
this._reSort();
return this._length;
}
override keys(): IterableIterator<number> { return this._data.keys(); }
override values(): IterableIterator<unknown> { return this._data.values(); }
override entries(): IterableIterator<[number, unknown]> { return this._data.entries(); }
override [Symbol.iterator](): IterableIterator<unknown> { return this.values(); }
[util.inspect.custom](depth: number, options: any): string {
const { name } = this.constructor;
const values = util.inspect(this._values, { ...options, depth: depth });
return `${name}(${this.length}) ${values}`;
}
}
// Example usage:
const arr = new IrrationalArray(0, 1, 2, 3, 4, 5);
console.log(arr);
arr[-1] = 'neg';
arr[1.5] = 'xd';
arr[Math.PI] = 'pi';
console.log(arr);
console.log(arr[-1]);
console.log(arr[1.5]);
console.log(arr[Math.PI]);
console.log(arr.length);
arr[19.84] = 'literally';
arr.push('a', 'b', 'c');
arr.unshift('d', 'e', 'f');
console.log(arr);
arr.pop();
arr.shift();
console.log(arr);
arr[0.75] = 'there';
arr[0.5] = 'hello';
arr[0.25] = 'well';
console.log(arr);
console.log([...arr.entries()]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment