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))
}
}