set up logical operations for indexset

This commit is contained in:
benbierens 2024-10-14 10:10:18 +02:00
parent 269365e101
commit a38e93a607
No known key found for this signature in database
GPG Key ID: 877D2C2E09A22F3A
3 changed files with 168 additions and 91 deletions

View File

@ -0,0 +1,73 @@
using NUnit.Framework;
namespace FrameworkTests.Utils
{
[TestFixture]
public class RunLengthEncodingLogicalTests
{
[Test]
public void Overlap()
{
var setA = new IndexSet([1, 2, 3, 4, 5, 11, 14]);
var setB = new IndexSet([3, 4, 5, 6, 7, 11, 12, 13]);
var expectedSet = new IndexSet([3, 4, 5, 11]);
var set = setA.Overlap(setB);
Assert.That(set, Is.EqualTo(expectedSet));
}
[Test]
public void Merge()
{
var setA = new IndexSet([1, 2, 3, 4, 5, 11, 14]);
var setB = new IndexSet([3, 4, 5, 6, 7, 11, 12, 13]);
var expectedSet = new IndexSet([1, 2, 3, 4, 5, 6, 7, 11, 12, 13, 14]);
var set = setA.Merge(setB);
Assert.That(set, Is.EqualTo(expectedSet));
}
[Test]
public void Without()
{
var setA = new IndexSet([1, 2, 3, 4, 5, 11, 14]);
var setB = new IndexSet([3, 4, 5, 6, 7, 11, 12, 13]);
var expectedSet = new IndexSet([1, 2, 14]);
var set = setA.Without(setB);
Assert.That(set, Is.EqualTo(expectedSet));
}
}
public partial class IndexSet
{
public IndexSet Overlap(IndexSet other)
{
return this;
}
public IndexSet Merge(IndexSet other)
{
return this;
}
public IndexSet Without(IndexSet other)
{
return this;
}
public override bool Equals(object? obj)
{
return obj is IndexSet set &&
EqualityComparer<SortedList<int, Run>>.Default.Equals(runs, set.runs);
}
public override int GetHashCode()
{
return HashCode.Combine(runs);
}
}
}

View File

@ -1,6 +1,4 @@
using NUnit.Framework; using NUnit.Framework;
using NUnit.Framework.Interfaces;
using static FrameworkTests.Utils.RunLengthEncodingTests;
namespace FrameworkTests.Utils namespace FrameworkTests.Utils
{ {

View File

@ -1,9 +1,4 @@
using Logging; using NUnit.Framework;
using Microsoft.VisualStudio.TestPlatform.Common;
using NuGet.Frameworks;
using NUnit.Framework;
using System.Collections.Concurrent;
using System.Numerics;
using Utils; using Utils;
namespace FrameworkTests.Utils namespace FrameworkTests.Utils
@ -201,119 +196,130 @@ namespace FrameworkTests.Utils
all.Sort(); all.Sort();
return all.ToArray(); return all.ToArray();
} }
}
public class IndexSet public partial class IndexSet
{
private readonly SortedList<int, Run> runs = new SortedList<int, Run>();
public IndexSet()
{ {
private readonly SortedList<int, Run> runs = new SortedList<int, Run>(); }
public IndexSet() public IndexSet(int[] indices)
{
foreach (var i in indices) Set(i);
}
public static IndexSet FromRunLengthEncoded(int[] rle)
{
var set = new IndexSet();
for (var i = 0; i < rle.Length; i += 2)
{ {
var start = rle[i];
var length = rle[i + 1];
set.runs.Add(start, new Run(start, length));
} }
public IndexSet(int[] indices) return set;
}
public bool IsSet(int index)
{
if (runs.ContainsKey(index)) return true;
var run = GetRunBefore(index);
if (run == null) return false;
return run.Includes(index);
}
public void Set(int index)
{
if (runs.ContainsKey(index)) return;
var run = GetRunBefore(index);
if (run == null || !run.ExpandToInclude(index))
{ {
foreach (var i in indices) Set(i); CreateNewRun(index);
} }
}
public static IndexSet FromRunLengthEncoded(int[] rle) public void Unset(int index)
{
if (runs.ContainsKey(index))
{ {
var set = new IndexSet(); HandleUpdate(runs[index].Unset(index));
for (var i = 0; i < rle.Length; i += 2)
{
var start = rle[i];
var length = rle[i + 1];
set.runs.Add(start, new Run(start, length));
}
return set;
} }
else
public bool IsSet(int index)
{ {
if (runs.ContainsKey(index)) return true;
var run = GetRunBefore(index); var run = GetRunBefore(index);
if (run == null) return false; if (run == null) return;
HandleUpdate(run.Unset(index));
return run.Includes(index);
} }
}
public void Set(int index) public void Iterate(Action<int> onIndex)
{
foreach (var run in runs.Values)
{ {
if (runs.ContainsKey(index)) return; run.Iterate(onIndex);
var run = GetRunBefore(index);
if (run == null || !run.ExpandToInclude(index))
{
CreateNewRun(index);
}
} }
}
public void Unset(int index) public int[] RunLengthEncoded()
{
return Encode().ToArray();
}
public override string ToString()
{
var result = "";
var encoded = RunLengthEncoded();
foreach (var pair in runs)
{ {
if (runs.ContainsKey(index)) result += $"[{pair.Value.Start},{pair.Value.Length}]]";
{
HandleUpdate(runs[index].Unset(index));
}
else
{
var run = GetRunBefore(index);
if (run == null) return;
HandleUpdate(run.Unset(index));
}
} }
return result;
}
public void Iterate(Action<int> onIndex) private IEnumerable<int> Encode()
{
foreach (var pair in runs)
{ {
foreach (var run in runs.Values) yield return pair.Value.Start;
{ yield return pair.Value.Length;
run.Iterate(onIndex);
}
} }
}
public int[] RunLengthEncoded() private Run? GetRunBefore(int index)
{
Run? result = null;
foreach (var pair in runs)
{ {
return Encode().ToArray(); if (pair.Key < index) result = pair.Value;
else return result;
} }
return result;
}
private IEnumerable<int> Encode() private void HandleUpdate(RunUpdate runUpdate)
{
foreach (var newRun in runUpdate.NewRuns) runs.Add(newRun.Start, newRun);
foreach (var removeRun in runUpdate.RemoveRuns) runs.Remove(removeRun.Start);
}
private void CreateNewRun(int index)
{
if (runs.ContainsKey(index + 1))
{ {
foreach (var pair in runs) var length = runs[index + 1].Length + 1;
{ runs.Add(index, new Run(index, length));
yield return pair.Value.Start; runs.Remove(index + 1);
yield return pair.Value.Length;
}
} }
else
private Run? GetRunBefore(int index)
{ {
Run? result = null; runs.Add(index, new Run(index, 1));
foreach (var pair in runs)
{
if (pair.Key < index) result = pair.Value;
else return result;
}
return result;
}
private void HandleUpdate(RunUpdate runUpdate)
{
foreach (var newRun in runUpdate.NewRuns) runs.Add(newRun.Start, newRun);
foreach (var removeRun in runUpdate.RemoveRuns) runs.Remove(removeRun.Start);
}
private void CreateNewRun(int index)
{
if (runs.ContainsKey(index + 1))
{
var length = runs[index + 1].Length + 1;
runs.Add(index, new Run(index, length));
runs.Remove(index + 1);
}
else
{
runs.Add(index, new Run(index, 1));
}
} }
} }
} }