import { eqOr } from "./bop"; import { Ranges, rangeAll } from "./range"; export interface Span> extends ArrayLike { } export class Span> { readonly #arr: A #from: number #to: number private constructor(arr: A, from: number, to: number) { this.#arr = arr this.#from = from this.#to = to return new Proxy(this, { has(target, property) { if (typeof property === 'number') return target.has(property) return Reflect.has(target, property) }, get(target, property, receiver) { if (typeof property === 'number') return target.get(property) if (eqOr(property, 'get', 'set', 'slice')) return Reflect.get(target, property, receiver).bind(target) if (eqOr(property, 'length')) return target[(property as any)] return Reflect.get(target, property, receiver) }, set(target, property, value, receiver) { if (typeof property === 'number') return target.set(property, value) return Reflect.set(target, property, value, receiver) }, }) } static from>(arr: Span, range?: Ranges): Span static from>(arr: A, range?: Ranges): Span static from>(arr: A | Span, range?: Ranges): Span { if (arr instanceof Span) { return arr.slice(range) } else { let [from = 0, to = arr.length] = Ranges.toTuple(range ?? rangeAll()) return new Span(arr, from, to) } } has(i: number): boolean { return i > 0 && i < this.length } get(i: number): A[number] { if (i >= this.length || i < 0) return return this.#arr[this.#from + i] } set(i: number, v: A[number]) { if (i >= this.length || i < 0) return false; (this.#arr as any)[this.#from + i] = v return true } get length() { return this.#to - this.#from } slice(range?: Ranges): Span { let [from = 0, to = this.length] = Ranges.toTuple(range ?? rangeAll()) return new Span(this.#arr, this.#from + from, this.#from + to) } } export namespace Slice { export function get(arr: T[], range: Ranges): T[] { return Array.prototype.slice.call(arr, ...Ranges.toTuple(range)) } }