Skip to content

Commit 2cbe030

Browse files
committed
Implements logical operations for indexSets
1 parent a38e93a commit 2cbe030

File tree

3 files changed

+257
-40
lines changed

3 files changed

+257
-40
lines changed

Tests/FrameworkTests/Utils/RunLengthEncodingLogicalTests.cs

Lines changed: 86 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,56 @@ namespace FrameworkTests.Utils
55
[TestFixture]
66
public class RunLengthEncodingLogicalTests
77
{
8+
[Test]
9+
public void EqualityTest()
10+
{
11+
var setA = new IndexSet([1, 2, 3, 4]);
12+
var setB = new IndexSet([1, 2, 3, 4]);
13+
14+
Assert.That(setA, Is.EqualTo(setB));
15+
Assert.That(setA == setB);
16+
}
17+
18+
[Test]
19+
public void InequalityTest1()
20+
{
21+
var setA = new IndexSet([1, 2, 4, 5]);
22+
var setB = new IndexSet([1, 2, 3, 4]);
23+
24+
Assert.That(setA, Is.Not.EqualTo(setB));
25+
Assert.That(setA != setB);
26+
}
27+
28+
[Test]
29+
public void InequalityTest2()
30+
{
31+
var setA = new IndexSet([1, 2, 3]);
32+
var setB = new IndexSet([1, 2, 3, 4]);
33+
34+
Assert.That(setA, Is.Not.EqualTo(setB));
35+
Assert.That(setA != setB);
36+
}
37+
38+
[Test]
39+
public void InequalityTest3()
40+
{
41+
var setA = new IndexSet([2, 3, 4, 5]);
42+
var setB = new IndexSet([1, 2, 3, 4]);
43+
44+
Assert.That(setA, Is.Not.EqualTo(setB));
45+
Assert.That(setA != setB);
46+
}
47+
48+
[Test]
49+
public void InequalityTest()
50+
{
51+
var setA = new IndexSet([2, 3, 4]);
52+
var setB = new IndexSet([1, 2, 3, 4]);
53+
54+
Assert.That(setA, Is.Not.EqualTo(setB));
55+
Assert.That(setA != setB);
56+
}
57+
858
[Test]
959
public void Overlap()
1060
{
@@ -46,28 +96,59 @@ public partial class IndexSet
4696
{
4797
public IndexSet Overlap(IndexSet other)
4898
{
49-
return this;
99+
var result = new IndexSet();
100+
Iterate(i =>
101+
{
102+
if (other.IsSet(i)) result.Set(i);
103+
});
104+
return result;
50105
}
51106

52107
public IndexSet Merge(IndexSet other)
53108
{
54-
return this;
109+
var result = new IndexSet();
110+
Iterate(result.Set);
111+
other.Iterate(result.Set);
112+
return result;
55113
}
56114

57115
public IndexSet Without(IndexSet other)
58116
{
59-
return this;
117+
var result = new IndexSet();
118+
Iterate(i =>
119+
{
120+
if (!other.IsSet(i)) result.Set(i);
121+
});
122+
return result;
60123
}
61124

62125
public override bool Equals(object? obj)
63126
{
64-
return obj is IndexSet set &&
65-
EqualityComparer<SortedList<int, Run>>.Default.Equals(runs, set.runs);
127+
if (obj is IndexSet set)
128+
{
129+
if (set.runs.Count != runs.Count) return false;
130+
foreach (var pair in runs)
131+
{
132+
if (!set.runs.ContainsKey(pair.Key)) return false;
133+
if (set.runs[pair.Key] != pair.Value) return false;
134+
}
135+
return true;
136+
}
137+
return false;
66138
}
67139

68140
public override int GetHashCode()
69141
{
70142
return HashCode.Combine(runs);
71143
}
144+
145+
public static bool operator ==(IndexSet? obj1, IndexSet? obj2)
146+
{
147+
if (ReferenceEquals(obj1, obj2)) return true;
148+
if (ReferenceEquals(obj1, null)) return false;
149+
if (ReferenceEquals(obj2, null)) return false;
150+
return obj1.Equals(obj2);
151+
}
152+
public static bool operator !=(IndexSet? obj1, IndexSet? obj2) => !(obj1 == obj2);
72153
}
73154
}

Tests/FrameworkTests/Utils/RunLengthEncodingRunTests.cs

Lines changed: 115 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,36 @@ namespace FrameworkTests.Utils
55
[TestFixture]
66
public class RunLengthEncodingRunTests
77
{
8+
[Test]
9+
public void EqualityTest()
10+
{
11+
var runA = new Run(1, 4);
12+
var runB = new Run(1, 4);
13+
14+
Assert.That(runA, Is.EqualTo(runB));
15+
Assert.That(runA == runB);
16+
}
17+
18+
[Test]
19+
public void InequalityTest1()
20+
{
21+
var runA = new Run(1, 4);
22+
var runB = new Run(1, 5);
23+
24+
Assert.That(runA, Is.Not.EqualTo(runB));
25+
Assert.That(runA != runB);
26+
}
27+
28+
[Test]
29+
public void InequalityTest2()
30+
{
31+
var runA = new Run(1, 4);
32+
var runB = new Run(2, 4);
33+
34+
Assert.That(runA, Is.Not.EqualTo(runB));
35+
Assert.That(runA != runB);
36+
}
37+
838
[Test]
939
[Combinatorial]
1040
public void RunIncludes(
@@ -31,23 +61,58 @@ public void RunIncludes(
3161
}
3262

3363
[Test]
34-
public void RunExpandToInclude()
64+
public void RunExpandThrowsWhenIndexNotAdjacent()
3565
{
3666
var run = new Run(2, 3);
67+
Assert.That(!run.Includes(1));
3768
Assert.That(run.Includes(2));
3869
Assert.That(run.Includes(4));
3970
Assert.That(!run.Includes(5));
4071

41-
Assert.That(run.ExpandToInclude(1), Is.False);
42-
Assert.That(run.ExpandToInclude(2), Is.False);
43-
Assert.That(run.ExpandToInclude(4), Is.False);
44-
Assert.That(run.ExpandToInclude(6), Is.False);
72+
Assert.That(() => run.ExpandToInclude(0), Throws.TypeOf<Exception>());
73+
Assert.That(() => run.ExpandToInclude(6), Throws.TypeOf<Exception>());
74+
}
75+
76+
[Test]
77+
public void RunExpandThrowsWhenIndexAlreadyIncluded()
78+
{
79+
var run = new Run(2, 3);
80+
Assert.That(!run.Includes(1));
81+
Assert.That(run.Includes(2));
82+
Assert.That(run.Includes(4));
83+
Assert.That(!run.Includes(5));
4584

46-
Assert.That(run.ExpandToInclude(5), Is.True);
85+
Assert.That(() => run.ExpandToInclude(2), Throws.TypeOf<Exception>());
86+
Assert.That(() => run.ExpandToInclude(3), Throws.TypeOf<Exception>());
87+
}
88+
89+
[Test]
90+
public void RunExpandToIncludeAfter()
91+
{
92+
var run = new Run(2, 3);
93+
var update = run.ExpandToInclude(5);
94+
Assert.That(update, Is.Not.Null);
95+
Assert.That(update.NewRuns.Length, Is.EqualTo(0));
96+
Assert.That(update.RemoveRuns.Length, Is.EqualTo(0));
4797
Assert.That(run.Includes(5));
4898
Assert.That(!run.Includes(6));
4999
}
50100

101+
[Test]
102+
public void RunExpandToIncludeBefore()
103+
{
104+
var run = new Run(2, 3);
105+
var update = run.ExpandToInclude(1);
106+
107+
Assert.That(update, Is.Not.Null);
108+
Assert.That(update.NewRuns.Length, Is.EqualTo(1));
109+
Assert.That(update.RemoveRuns.Length, Is.EqualTo(1));
110+
111+
Assert.That(update.RemoveRuns[0], Is.SameAs(run));
112+
Assert.That(update.NewRuns[0].Start, Is.EqualTo(1));
113+
Assert.That(update.NewRuns[0].Length, Is.EqualTo(4));
114+
}
115+
51116
[Test]
52117
public void RunCanUnsetLastIndex()
53118
{
@@ -98,7 +163,7 @@ public void CanIterateIndices()
98163
{
99164
var run = new Run(2, 4);
100165
var seen = new List<int>();
101-
run.Iterate(i => seen.Add(i));
166+
run.Iterate(seen.Add);
102167

103168
CollectionAssert.AreEqual(new[] { 2, 3, 4, 5 }, seen);
104169
}
@@ -120,14 +185,22 @@ public bool Includes(int index)
120185
return index >= Start && index < (Start + Length);
121186
}
122187

123-
public bool ExpandToInclude(int index)
188+
public RunUpdate ExpandToInclude(int index)
124189
{
190+
if (Includes(index)) throw new Exception("Run already includes this index. Run: {ToString()} index: {index}");
125191
if (index == (Start + Length))
126192
{
127193
Length++;
128-
return true;
194+
return new RunUpdate();
129195
}
130-
return false;
196+
if (index == (Start - 1))
197+
{
198+
return new RunUpdate(
199+
newRuns: [new Run(Start - 1, Length + 1)],
200+
removeRuns: [this]
201+
);
202+
}
203+
throw new Exception($"Run cannot expand to include index. Run: {ToString()} index: {index}");
131204
}
132205

133206
public RunUpdate Unset(int index)
@@ -145,8 +218,8 @@ public RunUpdate Unset(int index)
145218
return new RunUpdate(Array.Empty<Run>(), new[] { this });
146219
}
147220
return new RunUpdate(
148-
newRuns: new[] { new Run(Start + 1, Length - 1) },
149-
removeRuns: new[] { this }
221+
newRuns: [new Run(Start + 1, Length - 1)],
222+
removeRuns: [this]
150223
);
151224
}
152225

@@ -160,7 +233,10 @@ public RunUpdate Unset(int index)
160233
// Split:
161234
var newRunLength = (Start + Length - 1) - index;
162235
Length = index - Start;
163-
return new RunUpdate(new[] { new Run(index + 1, newRunLength) }, Array.Empty<Run>());
236+
return new RunUpdate(
237+
newRuns: [new Run(index + 1, newRunLength)],
238+
removeRuns: Array.Empty<Run>()
239+
);
164240
}
165241

166242
public void Iterate(Action<int> action)
@@ -170,6 +246,32 @@ public void Iterate(Action<int> action)
170246
action(Start + i);
171247
}
172248
}
249+
250+
public override string ToString()
251+
{
252+
return $"[{Start},{Length}]";
253+
}
254+
255+
public override bool Equals(object? obj)
256+
{
257+
return obj is Run run &&
258+
Start == run.Start &&
259+
Length == run.Length;
260+
}
261+
262+
public override int GetHashCode()
263+
{
264+
return HashCode.Combine(Start, Length);
265+
}
266+
267+
public static bool operator ==(Run? obj1, Run? obj2)
268+
{
269+
if (ReferenceEquals(obj1, obj2)) return true;
270+
if (ReferenceEquals(obj1, null)) return false;
271+
if (ReferenceEquals(obj2, null)) return false;
272+
return obj1.Equals(obj2);
273+
}
274+
public static bool operator !=(Run? obj1, Run? obj2) => !(obj1 == obj2);
173275
}
174276

175277
public class RunUpdate

0 commit comments

Comments
 (0)