mirror of
https://github.com/ppy/osu.git
synced 2025-01-13 07:22:54 +08:00
Replace interval collection with a more-specific immutable component
Covers all small changes into one commit: - Remove generics and use `double` type instead. - Make the component immutable and not enumerable for simplicity of it's worth. - Make the component more-specific (to time period tracking) - Apply small adjustments to the component
This commit is contained in:
parent
bf124a5cc6
commit
00918ecb6d
@ -1,111 +0,0 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Lists;
|
||||
|
||||
namespace osu.Game.Lists
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a list of intervals that can be used for whether a specific value falls into one of them.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of interval values.</typeparam>
|
||||
public class IntervalList<T> : IEnumerable<Interval<T>>
|
||||
where T : struct, IConvertible
|
||||
{
|
||||
private static readonly IComparer<T> type_comparer = Comparer<T>.Default;
|
||||
|
||||
private readonly SortedList<Interval<T>> intervals = new SortedList<Interval<T>>((x, y) => type_comparer.Compare(x.Start, y.Start));
|
||||
private int nearestIndex;
|
||||
|
||||
public Interval<T> this[int i]
|
||||
{
|
||||
get => intervals[i];
|
||||
set => intervals[i] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the provided value is in any interval added to this list.
|
||||
/// </summary>
|
||||
/// <param name="value">The value to check for.</param>
|
||||
public bool IsInAnyInterval(T value)
|
||||
{
|
||||
if (intervals.Count == 0)
|
||||
return false;
|
||||
|
||||
// Clamp the nearest index in case there were intervals
|
||||
// removed from the list causing the index to go out of range.
|
||||
nearestIndex = Math.Clamp(nearestIndex, 0, intervals.Count - 1);
|
||||
|
||||
if (type_comparer.Compare(value, this[nearestIndex].End) > 0)
|
||||
{
|
||||
while (type_comparer.Compare(value, this[nearestIndex].End) > 0 && nearestIndex < intervals.Count - 1)
|
||||
nearestIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (type_comparer.Compare(value, this[nearestIndex].Start) < 0 && nearestIndex > 0)
|
||||
nearestIndex--;
|
||||
}
|
||||
|
||||
var nearestInterval = this[nearestIndex];
|
||||
|
||||
return type_comparer.Compare(value, nearestInterval.Start) >= 0 &&
|
||||
type_comparer.Compare(value, nearestInterval.End) <= 0;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new interval to the list.
|
||||
/// </summary>
|
||||
/// <param name="start">The start value of the interval.</param>
|
||||
/// <param name="end">The end value of the interval.</param>
|
||||
public void Add(T start, T end) => Add(new Interval<T>(start, end));
|
||||
|
||||
/// <summary>
|
||||
/// Adds a new interval to the list
|
||||
/// </summary>
|
||||
/// <param name="interval">The interval to add.</param>
|
||||
public void Add(Interval<T> interval) => intervals.Add(interval);
|
||||
|
||||
/// <summary>
|
||||
/// Removes an existing interval from the list.
|
||||
/// </summary>
|
||||
/// <param name="interval">The interval to remove.</param>
|
||||
/// <returns>Whether the provided interval exists in the list and has been removed.</returns>
|
||||
public bool Remove(Interval<T> interval) => intervals.Remove(interval);
|
||||
|
||||
/// <summary>
|
||||
/// Removes all intervals from the list.
|
||||
/// </summary>
|
||||
public void Clear() => intervals.Clear();
|
||||
|
||||
public IEnumerator<Interval<T>> GetEnumerator() => intervals.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
|
||||
}
|
||||
|
||||
public readonly struct Interval<T>
|
||||
where T : struct, IConvertible
|
||||
{
|
||||
/// <summary>
|
||||
/// The start value of this interval.
|
||||
/// </summary>
|
||||
public readonly T Start;
|
||||
|
||||
/// <summary>
|
||||
/// The end value of this interval.
|
||||
/// </summary>
|
||||
public readonly T End;
|
||||
|
||||
public Interval(T start, T end)
|
||||
{
|
||||
if (Comparer<T>.Default.Compare(start, end) >= 0)
|
||||
throw new ArgumentException($"Invalid interval, {nameof(start)} must be less than {nameof(end)}", nameof(start));
|
||||
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
}
|
||||
}
|
90
osu.Game/Utils/PeriodTracker.cs
Normal file
90
osu.Game/Utils/PeriodTracker.cs
Normal file
@ -0,0 +1,90 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace osu.Game.Utils
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a tracking component used for whether a
|
||||
/// specific time falls into any of the provided periods.
|
||||
/// </summary>
|
||||
public class PeriodTracker
|
||||
{
|
||||
private readonly List<Period> periods = new List<Period>();
|
||||
private int nearestIndex;
|
||||
|
||||
/// <summary>
|
||||
/// The list of periods to add to the tracker for using the required check methods.
|
||||
/// </summary>
|
||||
public IEnumerable<Period> Periods
|
||||
{
|
||||
set
|
||||
{
|
||||
var sortedValue = value?.ToList();
|
||||
sortedValue?.Sort();
|
||||
|
||||
if (sortedValue != null && periods.SequenceEqual(sortedValue))
|
||||
return;
|
||||
|
||||
periods.Clear();
|
||||
nearestIndex = 0;
|
||||
|
||||
if (value?.Any() != true)
|
||||
return;
|
||||
|
||||
periods.AddRange(sortedValue);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether the provided time is in any of the added periods.
|
||||
/// </summary>
|
||||
/// <param name="time">The time value to check for.</param>
|
||||
public bool Contains(double time)
|
||||
{
|
||||
if (periods.Count == 0)
|
||||
return false;
|
||||
|
||||
if (time > periods[nearestIndex].End)
|
||||
{
|
||||
while (time > periods[nearestIndex].End && nearestIndex < periods.Count - 1)
|
||||
nearestIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
while (time < periods[nearestIndex].Start && nearestIndex > 0)
|
||||
nearestIndex--;
|
||||
}
|
||||
|
||||
var nearest = periods[nearestIndex];
|
||||
return time >= nearest.Start && time <= nearest.End;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct Period : IComparable<Period>
|
||||
{
|
||||
/// <summary>
|
||||
/// The start time of this period.
|
||||
/// </summary>
|
||||
public readonly double Start;
|
||||
|
||||
/// <summary>
|
||||
/// The end time of this period.
|
||||
/// </summary>
|
||||
public readonly double End;
|
||||
|
||||
public Period(double start, double end)
|
||||
{
|
||||
if (start >= end)
|
||||
throw new ArgumentException($"Invalid period provided, {nameof(start)} must be less than {nameof(end)}", nameof(start));
|
||||
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
|
||||
public int CompareTo(Period other) => Start.CompareTo(other.Start);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user