/
debug_collection.dart
337 lines (232 loc) · 9.13 KB
/
debug_collection.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
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
// Copyright (c) 2014, 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.
typedef void DebugCallback(String methodName, var arg1, var arg2);
class DebugMap<K, V> implements Map<K, V> {
final Map<K, V> map;
DebugCallback indexSetCallBack;
DebugCallback putIfAbsentCallBack;
DebugMap(this.map, {DebugCallback addCallback}) {
if (addCallback != null) {
this.addCallback = addCallback;
}
}
void set addCallback(DebugCallback value) {
indexSetCallBack = value;
putIfAbsentCallBack = value;
}
bool containsValue(Object value) {
return map.containsValue(value);
}
bool containsKey(Object key) => map.containsKey(key);
V operator [](Object key) => map[key];
void operator []=(K key, V value) {
if (indexSetCallBack != null) {
indexSetCallBack('[]=', key, value);
}
map[key] = value;
}
V putIfAbsent(K key, V ifAbsent()) {
return map.putIfAbsent(key, () {
V v = ifAbsent();
if (putIfAbsentCallBack != null) {
putIfAbsentCallBack('putIfAbsent', key, v);
}
return v;
});
}
void addAll(Map<K, V> other) => map.addAll(other);
V remove(Object key) => map.remove(key);
void clear() => map.clear();
void forEach(void f(K key, V value)) => map.forEach(f);
Iterable<K> get keys => map.keys;
Iterable<V> get values => map.values;
int get length => map.length;
bool get isEmpty => map.isEmpty;
bool get isNotEmpty => map.isNotEmpty;
}
class DebugIterable<E> implements Iterable<E> {
final Iterable<E> iterable;
DebugIterable(this.iterable);
Iterator<E> get iterator => iterable.iterator;
Iterable map(f(E element)) => iterable.map(f);
Iterable<E> where(bool test(E element)) => iterable.where(test);
Iterable expand(Iterable f(E element)) => iterable.expand(f);
bool contains(Object element) => iterable.contains(element);
void forEach(void f(E element)) => iterable.forEach(f);
E reduce(E combine(E value, E element)) => iterable.reduce(combine);
dynamic fold(
var initialValue, dynamic combine(var previousValue, E element)) {
return iterable.fold(initialValue, combine);
}
bool every(bool test(E element)) => iterable.every(test);
String join([String separator = ""]) => iterable.join(separator);
bool any(bool test(E element)) => iterable.any(test);
List<E> toList({bool growable: true}) {
return iterable.toList(growable: growable);
}
Set<E> toSet() => iterable.toSet();
int get length => iterable.length;
bool get isEmpty => iterable.isEmpty;
bool get isNotEmpty => iterable.isNotEmpty;
Iterable<E> take(int n) => iterable.take(n);
Iterable<E> takeWhile(bool test(E value)) => iterable.takeWhile(test);
Iterable<E> skip(int n) => iterable.skip(n);
Iterable<E> skipWhile(bool test(E value)) => iterable.skipWhile(test);
E get first => iterable.first;
E get last => iterable.last;
E get single => iterable.single;
E firstWhere(bool test(E element), {E orElse()}) {
return iterable.firstWhere(test, orElse: orElse);
}
E lastWhere(bool test(E element), {E orElse()}) {
return iterable.lastWhere(test, orElse: orElse);
}
E singleWhere(bool test(E element)) => iterable.singleWhere(test);
E elementAt(int index) => iterable.elementAt(index);
String toString() => iterable.toString();
}
class DebugList<E> extends DebugIterable<E> implements List<E> {
DebugCallback addCallback;
DebugCallback addAllCallback;
DebugList(List<E> list, {this.addCallback, this.addAllCallback})
: super(list);
List<E> get list => iterable;
E operator [](int index) => list[index];
void operator []=(int index, E value) {
list[index] = value;
}
int get length => list.length;
void set length(int newLength) {
list.length = newLength;
}
void add(E value) {
if (addCallback != null) {
addCallback('add', value, null);
}
list.add(value);
}
void addAll(Iterable<E> iterable) {
if (addAllCallback != null) {
addAllCallback('addAll', iterable, null);
}
list.addAll(iterable);
}
Iterable<E> get reversed => list.reversed;
void sort([int compare(E a, E b)]) => list.sort(compare);
void shuffle([random]) => list.shuffle(random);
int indexOf(E element, [int start = 0]) => list.indexOf(element, start);
int lastIndexOf(E element, [int start]) => list.lastIndexOf(element, start);
void clear() => list.clear();
void insert(int index, E element) => list.insert(index, element);
void insertAll(int index, Iterable<E> iterable) {
list.insertAll(index, iterable);
}
void setAll(int index, Iterable<E> iterable) => list.setAll(index, iterable);
bool remove(Object value) => list.remove(value);
E removeAt(int index) => list.removeAt(index);
E removeLast() => list.removeLast();
void removeWhere(bool test(E element)) => list.removeWhere(test);
void retainWhere(bool test(E element)) => list.retainWhere(test);
List<E> sublist(int start, [int end]) => list.sublist(start, end);
Iterable<E> getRange(int start, int end) => list.getRange(start, end);
void setRange(int start, int end, Iterable<E> iterable, [int skipCount = 0]) {
list.setRange(start, end, iterable, skipCount);
}
void removeRange(int start, int end) {
list.removeRange(start, end);
}
void fillRange(int start, int end, [E fillValue]) {
list.fillRange(start, end, fillValue);
}
void replaceRange(int start, int end, Iterable<E> replacement) {
list.replaceRange(start, end, replacement);
}
Map<int, E> asMap() => list.asMap();
}
class DebugSet<E> extends DebugIterable<E> implements Set<E> {
DebugCallback addCallback;
DebugSet(Set<E> set, {this.addCallback}) : super(set);
Set<E> get set => iterable;
bool contains(Object value) => set.contains(value);
bool add(E value) {
if (addCallback != null) {
addCallback('add', value, null);
}
return set.add(value);
}
void addAll(Iterable<E> elements) {
elements.forEach(add);
}
bool remove(Object value) => set.remove(value);
E lookup(Object object) => set.lookup(object);
void removeAll(Iterable<Object> elements) => set.removeAll(elements);
void retainAll(Iterable<Object> elements) => set.retainAll(elements);
void removeWhere(bool test(E element)) => set.removeWhere(test);
void retainWhere(bool test(E element)) => set.retainWhere(test);
bool containsAll(Iterable<Object> other) => set.containsAll(other);
Set<E> intersection(Set<Object> other) => set.intersection(other);
Set<E> union(Set<E> other) => set.union(other);
Set<E> difference(Set<Object> other) => set.difference(other);
void clear() => set.clear();
Set<E> toSet() => set.toSet();
}
/// Throws an exception if the runtime type of [object] is not in
/// [runtimeTypes].
///
/// Use this to gradually build the set of actual runtime values of [object]
/// at the call site by running test programs and adding to [runtimeTypes] when
/// new type are found.
void assertType(String name, List<String> runtimeTypes, var object,
{bool showObjects: false}) {
String runtimeType = '${object.runtimeType}';
if (runtimeTypes != null && runtimeTypes.contains(runtimeType)) return;
throw '$name: $runtimeType'
'${showObjects ? ' ($object)' : ''}';
}
/// Callback for the [addCallback] of [DebugMap] that throws an exception if
/// the runtime type of key/value pairs are not in [runtimeTypes].
///
/// Use this to gradually build the set of actual runtime values of key/value
/// pairs of a map by running test programs and adding to [runtimeTypes] when
/// new type are found.
class MapTypeAsserter {
final String name;
final Map<String, List<String>> runtimeTypes;
final bool showObjects;
const MapTypeAsserter(this.name, this.runtimeTypes,
{bool this.showObjects: false});
void call(String methodName, var key, var value) {
check(key, value, '$methodName: ');
}
void check(var key, var value, [String text = '']) {
String keyType = '${key.runtimeType}';
String valueType = '${value.runtimeType}';
List<String> valuesTypes = runtimeTypes[keyType];
if (valuesTypes != null && valuesTypes.contains(valueType)) return;
throw '$name: $text$keyType => $valueType'
'${showObjects ? ' ($key => $value)' : ''}';
}
}
/// Callback for the [addCallback] of [DebugSet] or [DebugList] that throws an
/// exception if the runtime type of the elements are not in [runtimeTypes].
///
/// Use this to gradually build the set of actual runtime values of the elements
/// of a collection by running test programs and adding to [runtimeTypes] when
/// new type are found.
class CollectionTypeAsserter {
final String name;
final List<String> runtimeTypes;
final bool showObjects;
const CollectionTypeAsserter(this.name, this.runtimeTypes,
{bool this.showObjects: false});
void call(String methodName, var element, _) {
check(element, '$methodName: ');
}
void check(var element, [String text = '']) {
String elementType = '${element.runtimeType}';
if (runtimeTypes.contains(elementType)) return;
throw '$name: $text$elementType'
'${showObjects ? ' ($element)' : ''}';
}
}