package funkin.util.tools; import funkin.data.song.SongData.SongEventData; /** * A static extension which provides utility functions for `Array`s. */ class SongEventDataArrayTools { /** * Queries whether the provided `SongEventData` is contained in the provided array. * The input array must be already sorted by `time`. * Vastly more efficient than `array.indexOf`. * This is not crazy or premature optimization, I'm writing this because `ChartEditorState.handleNoteDisplay` is using like 71% of its CPU time on this. * @param arr The array to search. * @param note The note to search for. * @param predicate * @return The index of the note in the array, or `-1` if it is not present. */ public static function fastIndexOf(input:Array, note:SongEventData):Int { // I would have made this use a generic/predicate, but that would have made it slower! // Thank you Github Copilot for suggesting a binary search! var lowIndex:Int = 0; var highIndex:Int = input.length - 1; var midIndex:Int; var midNote:SongEventData; // When lowIndex overtakes highIndex while (lowIndex <= highIndex) { // Get the middle index of the range. midIndex = Std.int((lowIndex + highIndex) / 2); // Compare the middle note of the range to the note we're looking for. // If it matches, return the index, else halve the range and try again. midNote = input[midIndex]; if (midNote.time < note.time) { // Search the upper half of the range. lowIndex = midIndex + 1; } else if (midNote.time > note.time) { // Search the lower half of the range. highIndex = midIndex - 1; } else { // Found it! return midIndex; } } return -1; } public static inline function fastContains(input:Array, note:SongEventData):Bool { return fastIndexOf(input, note) != -1; } }