Created
October 6, 2023 02:53
-
-
Save jhmaster2000/21482f2fdf20b580b94fe1ecb33dbda7 to your computer and use it in GitHub Desktop.
Array with irrational number indexes, PoC
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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