simplify insertion; only recalculate when removed

This commit is contained in:
mischa 2023-07-24 21:55:03 +08:00
parent 000ff99acf
commit ecfe339569
2 changed files with 26 additions and 16 deletions

View File

@ -23,29 +23,37 @@ public class HistoryBounds
public HistoryBounds(int limit) public HistoryBounds(int limit)
{ {
// initialize queue with maximum capacity to avoid runtime resizing // initialize queue with maximum capacity to avoid runtime resizing
// +1 because it makes the code easier if we insert first, and then remove.
this.limit = limit; this.limit = limit;
history = new Queue<Bounds>(limit); history = new Queue<Bounds>(limit + 1);
} }
// insert new bounds into history. calculates new total bounds. // insert new bounds into history. calculates new total bounds.
// Queue.Dequeue() always has the oldest bounds. // Queue.Dequeue() always has the oldest bounds.
public void Insert(Bounds bounds) public void Insert(Bounds bounds)
{ {
// remove oldest if limit reached // initialize 'total' if not initialized yet.
if (history.Count >= limit) // we don't want to call (0,0).Encapsulate(bounds).
if (history.Count == 0)
total = bounds;
// insert and encapsulate the new bounds
history.Enqueue(bounds);
total.Encapsulate(bounds);
// ensure history stays within limit
if (history.Count > limit)
{
// remove oldest
history.Dequeue(); history.Dequeue();
// insert the new bounds // recalculate total bounds
history.Enqueue(bounds); // (only needed after removing the oldest)
// summarize total bounds.
// starting at latest bounds, not at 'new Bounds' because that would
// encapsulate (0,0) too.
// TODO make this not be O(N)
total = bounds; total = bounds;
foreach (Bounds b in history) foreach (Bounds b in history)
total.Encapsulate(b); total.Encapsulate(b);
} }
}
public void Reset() public void Reset()
{ {

View File

@ -22,8 +22,8 @@ public static Bounds MinMax(float min, float max) =>
// simple benchmark to compare some optimizations later. // simple benchmark to compare some optimizations later.
// 64 entries are much more than we would usually use. // 64 entries are much more than we would usually use.
// //
// Unity 2021.3 LTS, release mode, 10_000 x 64 x 8: // Unity 2021.3 LTS, release mode: 10x000 x 65; limit=8
// native O(N) Queue<Bounds> implementation: 1005 ms // native O(N) Queue<Bounds> implementation: 1045 ms
[Test] [Test]
[TestCase(10_000, 64, 8)] [TestCase(10_000, 64, 8)]
public void Benchmark(int iterations, int insertions, int limit) public void Benchmark(int iterations, int insertions, int limit)
@ -158,7 +158,9 @@ public void InsertFar()
[Test] [Test]
public void Reset() public void Reset()
{ {
HistoryBounds history = new HistoryBounds(3); const int limit = 3;
HistoryBounds history = new HistoryBounds(limit);
history.Insert(MinMax(1, 2)); history.Insert(MinMax(1, 2));
history.Insert(MinMax(2, 3)); history.Insert(MinMax(2, 3));
history.Insert(MinMax(3, 4)); history.Insert(MinMax(3, 4));