set up logical operations for indexset
This commit is contained in:
parent
269365e101
commit
a38e93a607
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -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
|
||||||
{
|
{
|
||||||
|
|
|
@ -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));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue