-
Notifications
You must be signed in to change notification settings - Fork 1.6k
/
Copy pathintset.dart
156 lines (131 loc) · 4 KB
/
intset.dart
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
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'dart:collection';
import 'dart:typed_data';
// The default set implementation is based on a Uint32List+List where both are
// linear in the number of entries. That means we consume on 64-bit VMs at
// least 12 bytes per entry.
//
// We should consider making a more memory efficient hash set implementation
// that uses Int32List and utilizing the fact that we never store negative
// numbers in it.
typedef IntSet = Set<int>;
/// Set of ints that can hold ints between 0 and up to (but not including)
/// [maxLength].
///
/// The memory usage of this is fixed and depend on the [maxLength], and is
/// something like ~125 kb per mio. as specified by [maxLength], e.g. a max
/// length of 50 mio should take ~6 mb.
class SpecializedIntSet extends SetBase<int> {
final Uint32List _data;
final int maxLength;
int _length = 0;
SpecializedIntSet(this.maxLength)
: _data = Uint32List((maxLength + 31) ~/ 32);
@override
Iterator<int> get iterator => _SpecializedIntSetIterator(this);
@override
int get length => _length;
@override
bool add(int value) {
if (value < 0 || value >= maxLength) {
throw RangeError.range(value, 0, maxLength - 1);
}
final int index = value >> 5;
final int offset = value & 31;
final int mask = 1 << (31 - offset);
if (_data[index] & mask != 0) return false;
_data[index] |= mask;
_length++;
return true;
}
@override
bool contains(Object? element) {
if (element is! int) return false;
if (element < 0) return false;
if (element >= maxLength) return false;
final int index = element >> 5;
final int offset = element & 31;
final int mask = 1 << (31 - offset);
return _data[index] & mask != 0;
}
String getDumpData() {
final StringBuffer sb = StringBuffer();
for (int value in _data) {
if (sb.isNotEmpty) sb.write(" ");
sb.write(value.toRadixString(2).padLeft(32, "0"));
}
return sb.toString();
}
@override
int? lookup(Object? element) {
if (contains(element)) return element as int;
return null;
}
@override
bool remove(Object? value) {
if (value is! int) return false;
if (value < 0) return false;
if (value >= maxLength) return false;
final int index = value >> 5;
final int offset = value & 31;
final int mask = 1 << (31 - offset);
if (_data[index] & mask != 0) {
_data[index] &= ~mask;
_length--;
return true;
}
return false;
}
@override
Set<int> toSet() {
final SpecializedIntSet result = SpecializedIntSet(maxLength);
result._length = _length;
result._data.setRange(0, _data.length, _data);
return result;
}
}
class _SpecializedIntSetIterator implements Iterator<int> {
int? _current;
int _nextToCheck = 0;
int _returns = 0;
final SpecializedIntSet _set;
_SpecializedIntSetIterator(this._set);
@override
int get current => _current ?? (throw StateError('No element'));
@override
bool moveNext() {
if (_returns >= _set.length) return false;
while (_nextToCheck < _set.maxLength) {
final int index = _nextToCheck >> 5;
final int dataAtIndex = _set._data[index];
if (dataAtIndex == 0) {
// Nothing in this byte.
_nextToCheck = (index + 1) << 5;
continue;
}
final int restBytes;
final int offset = _nextToCheck & 31;
{
final int maskRest = (1 << (32 - offset)) - 1;
restBytes = dataAtIndex & maskRest;
}
if (restBytes == 0) {
// No more in this byte.
_nextToCheck = (index + 1) << 5;
continue;
}
int mask = (1 << (31 - offset));
while (restBytes & mask == 0) {
_nextToCheck++;
mask >>= 1;
}
_current = _nextToCheck;
_nextToCheck++;
_returns++;
return true;
}
return false;
}
}