package funkin.audio.visualize.dsp; /** * A view into an Array with an indexing offset. * * Usages include 1-indexed sequences or zero-centered buffers with negative indexing. */ @:forward(array, offset) @:nullSafety abstract OffsetArray({ final array:Array; final offset:Int; }) { public inline function new(array:Array, offset:Int) this = {array: array, offset: offset}; public var length(get, never):Int; inline function get_length() return this.array.length; @:arrayAccess public inline function get(index:Int):T return this.array[index - this.offset]; @:arrayAccess public inline function set(index:Int, value:T):Void this.array[index - this.offset] = value; /** * Iterates through items in their original order while providing the altered indexes as keys. */ public inline function keyValueIterator():KeyValueIterator return new OffsetArrayIterator(this.array, this.offset); @:from static inline function fromArray(array:Array):OffsetArray { return new OffsetArray(array, 0); } @:to inline function toArray():Array { return this.array; } /** * Makes a shifted version of the given `array`, where elements are in the * same order but shifted by `n` positions (to the right if positive and to * the left if negative) in **circular** fashion (no elements discarded). * * @param array The array to shift * @param n The number of positions to shift * @return The resulting offset array */ public static function circShift(array:Array, n:Int):Array { if (n < 0) return circShift(array, array.length + n); var shifted = []; n = n % array.length; for (i in array.length - n...array.length) { shifted.push(array[i]); } for (i in 0...array.length - n) { shifted.push(array[i]); } return shifted; } } private class OffsetArrayIterator { final array:Array; final offset:Int; var enumeration:Int; public inline function new(array:Array, offset:Int) { this.array = array; this.offset = offset; this.enumeration = 0; } public inline function next(): {key:Int, value:T} { var i = this.enumeration++; return {key: i + this.offset, value: this.array[i]}; } public inline function hasNext():Bool { return this.enumeration < this.array.length; } }