1
0
Fork 0
mirror of https://github.com/ninjamuffin99/Funkin.git synced 2024-09-20 17:18:55 +00:00
Funkin/source/funkin/util/tools/SongNoteDataArrayTools.hx

70 lines
2.3 KiB
Haxe
Raw Normal View History

package funkin.util.tools;
import funkin.data.song.SongData.SongNoteData;
/**
* A static extension which provides utility functions for `Array<SongNoteData>`s.
*/
class SongNoteDataArrayTools
{
/**
* Queries whether the provided `SongNoteData` 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<SongNoteData>, note:SongNoteData):Int
{
// I would have made this use a generic/predicate, but that would have made it slower!
// Prefix with some simple checks to save time.
if (input.length == 0) return -1;
if (note.time < input[0].time || note.time > input[input.length - 1].time) return -1;
// Thank you Github Copilot for suggesting a binary search!
var lowIndex:Int = 0;
var highIndex:Int = input.length - 1;
// When lowIndex overtakes highIndex
while (lowIndex <= highIndex)
{
// Get the middle index of the range.
var 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.
var 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;
}
// Found it? Do a more thorough check.
else if (midNote == note)
{
return midIndex;
}
else
{
// We may be close, so constrain the range (but only a little) and try again.
highIndex -= 1;
}
}
return -1;
}
public static inline function fastContains(input:Array<SongNoteData>, note:SongNoteData):Bool
{
return fastIndexOf(input, note) != -1;
}
}