Skip to content

Commit

Permalink
Merge branch 'halgari-main'
Browse files Browse the repository at this point in the history
  • Loading branch information
jamarino committed Mar 1, 2025
2 parents d2ee04e + 590b519 commit 0618e00
Show file tree
Hide file tree
Showing 6 changed files with 166 additions and 23 deletions.
7 changes: 7 additions & 0 deletions Source/IntervalTree/IIntervalTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,13 @@ public interface IIntervalTree<TKey, TValue> : IEnumerable<Interval<TKey, TValue
/// <param name="value">Values to look for</param>
void Remove(IEnumerable<TValue> values);

/// <summary>
/// Remove all values where the value matches the provided predicate. State is passed to the predicate.
/// </summary>
/// <param name="predicate">Predicate to test values against</param>
/// <param name="state">State to pass to the predicate</param>
void RemoveAll<TState>(Func<Interval<TKey, TValue>, TState, bool> predicate, TState state);

/// <summary>
/// Clear all data from tree. Allows for reusing of trees, instead of allocating a new ones.
/// </summary>
Expand Down
28 changes: 19 additions & 9 deletions Source/IntervalTree/LightIntervalTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public void Add(TKey from, TKey to, TValue value)
}

public IEnumerator<Interval<TKey, TValue>> GetEnumerator() =>
_intervals.Take(_count).Select(i => new Interval<TKey, TValue>(i.From, i.To, i.Value)).GetEnumerator();
_intervals.Take(_count).Select(i => i.ToInterval()).GetEnumerator();

IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();

Expand Down Expand Up @@ -269,12 +269,25 @@ TKey UpdateMaxRec(int min, int max, int recursionLevel)
}

public void Remove(TValue value)
{
RemoveAll(
static (interval, val) => Equals(interval.Value, val),
value);
}

public void Remove(IEnumerable<TValue> values)
{
foreach (var val in values)
Remove(val);
}

public void RemoveAll<TState>(Func<Interval<TKey, TValue>, TState, bool> predicate, TState state)
{
var i = 0;
while (i < _count)
{
var interval = _intervals[i];
if (Equals(interval.Value, value))
var interval = _intervals[i].ToInterval();
if (predicate(interval, state))
{
_count--;
_intervals[i] = _intervals[_count];
Expand All @@ -287,12 +300,6 @@ public void Remove(TValue value)
}
}

public void Remove(IEnumerable<TValue> values)
{
foreach (var val in values)
Remove(val);
}

public void Clear()
{
_count = 0;
Expand Down Expand Up @@ -326,5 +333,8 @@ public int CompareTo(AugmentedInterval other)
return fromComparison;
return To.CompareTo(other.To);
}

public readonly Interval<TKey, TValue> ToInterval()
=> new(From, To, Value);
}
}
21 changes: 14 additions & 7 deletions Source/IntervalTree/LinearIntervalTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,24 +101,31 @@ public IEnumerable<TValue> Query(TKey low, TKey high)
}

public void Remove(TValue value)
{
RemoveAll(
static (interval, val) => Equals(interval.Value, val),
value);
}

public void Remove(IEnumerable<TValue> values)
{
foreach (var val in values)
Remove(val);
}

public void RemoveAll<TState>(Func<Interval<TKey, TValue>, TState, bool> predicate, TState state)
{
var i = 0;
while (i < _count)
{
var interval = _intervals[i];
if (Equals(interval.Value, value))
if (predicate(interval, state))
_intervals[i] = _intervals[--_count];
else
i++;
}
}

public void Remove(IEnumerable<TValue> values)
{
foreach (var val in values)
Remove(val);
}

public void Clear()
{
_count = 0;
Expand Down
21 changes: 14 additions & 7 deletions Source/IntervalTree/QuickIntervalTree.cs
Original file line number Diff line number Diff line change
Expand Up @@ -378,12 +378,25 @@ void BuildRec(int min, int max, int nodeIndex, int recursionLevel)
}

public void Remove(TValue value)
{
RemoveAll(
static (interval, val) => Equals(interval.Value, val),
value);
}

public void Remove(IEnumerable<TValue> values)
{
foreach (var val in values)
Remove(val);
}

public void RemoveAll<TState>(Func<Interval<TKey, TValue>, TState, bool> predicate, TState state)
{
var i = 0;
while (i < _intervalCount)
{
var interval = _intervals[i];
if (Equals(interval.Value, value))
if (predicate(interval, state))
{
_intervalCount--;
_intervals[i] = _intervals[_intervalCount];
Expand All @@ -396,12 +409,6 @@ public void Remove(TValue value)
}
}

public void Remove(IEnumerable<TValue> values)
{
foreach (var val in values)
Remove(val);
}

public void Clear()
{
_intervalCount = 0;
Expand Down
106 changes: 106 additions & 0 deletions Tests/UnitTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -740,4 +740,110 @@ public void ATreeWithDuplicateIntervals_ShouldYieldDuplicateValues(string treeTy
Assert.That(intervals, Is.EquivalentTo(Enumerable.Range(0, 3).Select(_ => new IntervalTree.RangeValuePair<long, int>(1, 2, 1))));
}
}

public class Removing : UnitTests
{
[Test]
[TestCaseSource(typeof(TreeFactory), nameof(TreeFactory.TreeTypes))]
public void FromAnEmptyTree_DoNothing(string treeType)
{
var tree = TreeFactory.CreateEmptyTree<long, int>(treeType);

tree.Remove(1);

Assert.That(tree.Count, Is.EqualTo(0));
}

[Test]
[TestCaseSource(typeof(TreeFactory), nameof(TreeFactory.TreeTypes))]
public void FromATreeWithMultipleOfSameValue_RemovesAllOccurences(string treeType)
{
var tree = TreeFactory.CreateEmptyTree<long, int>(treeType);
tree.Add(1, 3, 5);
tree.Add(1, 3, 5);
tree.Add(41, 300, 5);
tree.Add(20, 21, 6);

tree.Remove(5);

Assert.That(tree.Count, Is.EqualTo(1));
}

[Test]
[TestCaseSource(typeof(TreeFactory), nameof(TreeFactory.TreeTypes))]
public void FromATreeUsingEnumerable_RemovesAllOccurences(string treeType)
{
var tree = TreeFactory.CreateEmptyTree<long, int>(treeType);

tree.Add(1, 3, 5);
tree.Add(1, 3, 5);
tree.Add(20, 21, 6);
tree.Add(41, 300, 5);
tree.Add(20, 22, 6);

tree.Add(10, 20, 7);
tree.Add(20, 30, 8);

tree.Remove([5, 6]);

Assert.That(tree.Count, Is.EqualTo(2));
}

[Test]
[TestCaseSource(typeof(TreeFactory), nameof(TreeFactory.TreeTypesSansReference))]
public void FromATreeUsingPredicate_RemovesAllOccurencesByValue(string treeType)
{
var tree = TreeFactory.CreateNonReferenceTree<long, int>(treeType);

tree.Add(1, 3, 5);
tree.Add(1, 3, 5);
tree.Add(20, 21, 6);
tree.Add(41, 300, 5);
tree.Add(20, 22, 6);
tree.Add(10, 20, 7);
tree.Add(20, 30, 8);

tree.RemoveAll((intv, _) => intv.Value is 5 or 6, 0);

Assert.That(tree.Count, Is.EqualTo(2));
}

[Test]
[TestCaseSource(typeof(TreeFactory), nameof(TreeFactory.TreeTypesSansReference))]
public void FromATreeUsingPredicate_RemovesAllOccurencesByFrom(string treeType)
{
var tree = TreeFactory.CreateNonReferenceTree<long, int>(treeType);

tree.Add(1, 3, 5);
tree.Add(1, 3, 5);
tree.Add(41, 300, 5);
tree.Add(20, 21, 6);
tree.Add(20, 22, 6);
tree.Add(10, 20, 7);
tree.Add(20, 30, 8);

tree.RemoveAll((intv, _) => intv.From is 20, 0);

Assert.That(tree.Count, Is.EqualTo(4));
}

[Test]
[TestCaseSource(typeof(TreeFactory), nameof(TreeFactory.TreeTypesSansReference))]
public void FromATreeUsingPredicate_RemovesAllOccurencesByTo(string treeType)
{
var tree = TreeFactory.CreateNonReferenceTree<long, int>(treeType);

tree.Add(1, 3, 5);
tree.Add(1, 3, 5);
tree.Add(41, 300, 5);
tree.Add(20, 21, 6);
tree.Add(20, 22, 6);
tree.Add(10, 20, 7);
tree.Add(20, 30, 8);

tree.RemoveAll((intv, _) => intv.To is 21 or 22, 0);

Assert.That(tree.Count, Is.EqualTo(5));
}
}
}
6 changes: 6 additions & 0 deletions Tools/Extras/TreeFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@ public static IntervalTree.IIntervalTree<TKey, TValue> CreateEmptyTree<TKey, TVa
return new TreeAdapter<TKey, TValue>((IIntervalTree<TKey, TValue>)tree);
}

public static IIntervalTree<TKey, TValue> CreateNonReferenceTree<TKey, TValue>(string type, int? capacity = null)
where TKey : IComparable<TKey>
{
return (IIntervalTree<TKey, TValue>)CreateEmptyTreeRaw<TKey, TValue>(type, capacity);
}

public static object CreateEmptyTreeRaw<TKey, TValue>(string type, int? capacity = null) where TKey : IComparable<TKey>
{
if (capacity is null)
Expand Down

0 comments on commit 0618e00

Please sign in to comment.