-
Notifications
You must be signed in to change notification settings - Fork 4.6k
/
IntegerRangeSet.cs
138 lines (111 loc) · 3.62 KB
/
IntegerRangeSet.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using Xunit;
namespace System.Linq.Parallel.Tests
{
// Dummy psuedo-set for verifying we've seen all of a range of integers, and only once.
internal sealed class IntegerRangeSet : IEnumerable<KeyValuePair<int, bool>>
{
private readonly BitArray _seen;
private int _start;
private SpinLock _lock = new SpinLock(enableThreadOwnerTracking: false);
public IntegerRangeSet(int start, int count)
{
_start = start;
_seen = new BitArray(count);
}
public bool Add(int entry)
{
Assert.InRange(entry, _start, unchecked(_start + _seen.Length - 1));
bool seen;
bool lockTaken = false;
_lock.Enter(ref lockTaken);
int pos = entry - _start;
seen = _seen[pos];
_seen[pos] = true;
_lock.Exit(useMemoryBarrier: false);
Assert.False(seen);
return true;
}
public void AssertComplete()
{
Assert.All(this, kv => Assert.True(kv.Value));
}
public IEnumerator<KeyValuePair<int, bool>> GetEnumerator()
{
return new BitArrayEnumerator(_start, _seen);
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
private sealed class BitArrayEnumerator : IEnumerator<KeyValuePair<int, bool>>
{
private int _start;
private readonly BitArray _values;
private int _current = -1;
public BitArrayEnumerator(int start, BitArray values)
{
_start = start;
_values = values;
}
public KeyValuePair<int, bool> Current
{
get
{
return new KeyValuePair<int, bool>(_start + _current, _values[_current]);
}
}
object IEnumerator.Current
{
get
{
return Current;
}
}
public void Dispose()
{
Reset();
}
public bool MoveNext()
{
return (_current + 1 < _values.Length) ? ++_current >= 0 : false;
}
public void Reset()
{
_current = -1;
}
}
}
// Simple class for counting the number of times an integer in a range has occurred.
internal sealed class IntegerRangeCounter : IEnumerable<KeyValuePair<int, int>>
{
private readonly int[] _seen;
private int _start;
public IntegerRangeCounter(int start, int count)
{
_start = start;
_seen = new int[count];
}
public int Add(int entry)
{
Assert.InRange(entry, _start, _start + _seen.Length - 1);
return Interlocked.Increment(ref _seen[entry - _start]);
}
public void AssertEncountered(int count)
{
Assert.All(this, kv => Assert.Equal(count, kv.Value));
}
public IEnumerator<KeyValuePair<int, int>> GetEnumerator()
{
return _seen.Select((v, index) => new KeyValuePair<int, int>(index + _start, v)).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}