/
map.dart
405 lines (369 loc) · 13.1 KB
/
map.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
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
// Copyright (c) 2011, 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.
part of dart.core;
/**
* A collection of key/value pairs, from which you retrieve a value
* using its associated key.
*
* There is a finite number of keys in the map,
* and each key has exactly one value associated with it.
*
* Maps, and their keys and values, can be iterated.
* The order of iteration is defined by the individual type of map.
* Examples:
*
* * The plain [HashMap] is unordered (no order is guaranteed),
* * the [LinkedHashMap] iterates in key insertion order,
* * and a sorted map like [SplayTreeMap] iterates the keys in sorted order.
*
* It is generally not allowed to modify the map (add or remove keys) while
* an operation is being performed on the map, for example in functions called
* during a [forEach] or [putIfAbsent] call.
* Modifying the map while iterating the keys or values
* may also break the iteration.
*
* It is generally not allowed to modify the equality of keys (and thus not
* their hashcode) while they are in the map. Some specialized subtypes may be
* more permissive, in which case they should document this behavior.
*/
abstract class Map<K, V> {
/**
* Creates a Map instance with the default implementation, [LinkedHashMap].
*
* This constructor is equivalent to the non-const map literal `<K,V>{}`.
*
* A `LinkedHashMap` requires the keys to implement compatible
* `operator==` and `hashCode`, and it allows null as a key.
* It iterates in key insertion order.
*/
external factory Map();
/**
* Creates a [LinkedHashMap] instance that contains all key/value pairs of
* [other].
*
* The keys must all be instances of [K] and the values of [V].
* The [other] map itself can have any type.
*
* A `LinkedHashMap` requires the keys to implement compatible
* `operator==` and `hashCode`, and it allows `null` as a key.
* It iterates in key insertion order.
*/
factory Map.from(Map other) = LinkedHashMap<K, V>.from;
/**
* Creates a [LinkedHashMap] with the same keys and values as [other].
*
* A `LinkedHashMap` requires the keys to implement compatible
* `operator==` and `hashCode`, and it allows `null` as a key.
* It iterates in key insertion order.
*/
factory Map.of(Map<K, V> other) = LinkedHashMap<K, V>.of;
/**
* Creates an unmodifiable hash based map containing the entries of [other].
*
* The keys must all be instances of [K] and the values of [V].
* The [other] map itself can have any type.
*
* The map requires the keys to implement compatible
* `operator==` and `hashCode`, and it allows `null` as a key.
* The created map iterates keys in a fixed order,
* preserving the order provided by [other].
*
* The resulting map behaves like the result of [Map.from],
* except that the map returned by this constructor is not modifiable.
*/
external factory Map.unmodifiable(Map<dynamic, dynamic> other);
/**
* Creates an identity map with the default implementation, [LinkedHashMap].
*
* An identity map uses [identical] for equality and [identityHashCode]
* for hash codes of keys instead of the intrinsic [Object.==] and
* [Object.hashCode] of the keys.
*
* The returned map allows `null` as a key.
* It iterates in key insertion order.
*/
factory Map.identity() = LinkedHashMap<K, V>.identity;
/**
* Creates a Map instance in which the keys and values are computed from the
* [iterable].
*
* The created map is a [LinkedHashMap].
* A `LinkedHashMap` requires the keys to implement compatible
* `operator==` and `hashCode`, and it allows null as a key.
* It iterates in key insertion order.
*
* For each element of the [iterable] this constructor computes a key/value
* pair, by applying [key] and [value] respectively.
*
* The example below creates a new Map from a List. The keys of `map` are
* `list` values converted to strings, and the values of the `map` are the
* squares of the `list` values:
*
* List<int> list = [1, 2, 3];
* Map<String, int> map = new Map.fromIterable(list,
* key: (item) => item.toString(),
* value: (item) => item * item);
*
* map['1'] + map['2']; // 1 + 4
* map['3'] - map['2']; // 9 - 4
*
* If no values are specified for [key] and [value] the default is the
* identity function.
*
* In the following example, the keys and corresponding values of `map`
* are `list` values:
*
* map = new Map.fromIterable(list);
* map[1] + map[2]; // 1 + 2
* map[3] - map[2]; // 3 - 2
*
* The keys computed by the source [iterable] do not need to be unique. The
* last occurrence of a key will simply overwrite any previous value.
*/
factory Map.fromIterable(Iterable iterable,
{K key(element)?, V value(element)?}) = LinkedHashMap<K, V>.fromIterable;
/**
* Creates a Map instance associating the given [keys] to [values].
*
* The created map is a [LinkedHashMap].
* A `LinkedHashMap` requires the keys to implement compatible
* `operator==` and `hashCode`, and it allows null as a key.
* It iterates in key insertion order.
*
* This constructor iterates over [keys] and [values] and maps each element of
* [keys] to the corresponding element of [values].
*
* List<String> letters = ['b', 'c'];
* List<String> words = ['bad', 'cat'];
* Map<String, String> map = new Map.fromIterables(letters, words);
* map['b'] + map['c']; // badcat
*
* If [keys] contains the same object multiple times, the last occurrence
* overwrites the previous value.
*
* The two [Iterable]s must have the same length.
*/
factory Map.fromIterables(Iterable<K> keys, Iterable<V> values) =
LinkedHashMap<K, V>.fromIterables;
/**
* Adapts [source] to be a `Map<K2, V2>`.
*
* Any time the set would produce a key or value that is not a [K2] or [V2],
* the access will throw.
*
* Any time [K2] key or [V2] value is attempted added into the adapted map,
* the store will throw unless the key is also an instance of [K] and
* the value is also an instance of [V].
*
* If all accessed entries of [source] are have [K2] keys and [V2] values
* and if all entries added to the returned map have [K] keys and [V]] values,
* then the returned map can be used as a `Map<K2, V2>`.
*/
static Map<K2, V2> castFrom<K, V, K2, V2>(Map<K, V> source) =>
CastMap<K, V, K2, V2>(source);
/**
* Creates a new map and adds all entries.
*
* Returns a new `Map<K, V>` where all entries of [entries]
* have been added in iteration order.
*
* If multiple [entries] have the same key,
* later occurrences overwrite the earlier ones.
*/
factory Map.fromEntries(Iterable<MapEntry<K, V>> entries) =>
<K, V>{}..addEntries(entries);
/**
* Provides a view of this map as having [RK] keys and [RV] instances,
* if necessary.
*
* If this map is already a `Map<RK, RV>`, it is returned unchanged.
*
* If this set contains only keys of type [RK] and values of type [RV],
* all read operations will work correctly.
* If any operation exposes a non-[RK] key or non-[RV] value,
* the operation will throw instead.
*
* Entries added to the map must be valid for both a `Map<K, V>` and a
* `Map<RK, RV>`.
*/
Map<RK, RV> cast<RK, RV>();
/**
* Returns true if this map contains the given [value].
*
* Returns true if any of the values in the map are equal to `value`
* according to the `==` operator.
*/
bool containsValue(Object? value);
/**
* Returns true if this map contains the given [key].
*
* Returns true if any of the keys in the map are equal to `key`
* according to the equality used by the map.
*/
bool containsKey(Object? key);
/**
* Returns the value for the given [key] or null if [key] is not in the map.
*
* Some maps allow keys to have `null` as a value.
* For those maps, a lookup using this operator cannot distinguish between a
* key not being in the map and the key having a `null` value.
* Methods like [containsKey] or [putIfAbsent] can be used if the distinction
* is important.
*/
V? operator [](Object? key);
/**
* Associates the [key] with the given [value].
*
* If the key was already in the map, its associated value is changed.
* Otherwise the key/value pair is added to the map.
*/
void operator []=(K key, V value);
/**
* The map entries of [this].
*/
Iterable<MapEntry<K, V>> get entries;
/**
* Returns a new map where all entries of this map are transformed by
* the given [f] function.
*/
Map<K2, V2> map<K2, V2>(MapEntry<K2, V2> f(K key, V value));
/**
* Adds all key/value pairs of [newEntries] to this map.
*
* If a key of [newEntries] is already in this map,
* the corresponding value is overwritten.
*
* The operation is equivalent to doing `this[entry.key] = entry.value`
* for each [MapEntry] of the iterable.
*/
void addEntries(Iterable<MapEntry<K, V>> newEntries);
/**
* Updates the value for the provided [key].
*
* Returns the new value of the key.
*
* If the key is present, invokes [update] with the current value and stores
* the new value in the map.
*
* If the key is not present and [ifAbsent] is provided, calls [ifAbsent]
* and adds the key with the returned value to the map.
*
* It's an error if the key is not present and [ifAbsent] is not provided.
*/
V update(K key, V update(V value), {V ifAbsent()?});
/**
* Updates all values.
*
* Iterates over all entries in the map and updates them with the result
* of invoking [update].
*/
void updateAll(V update(K key, V value));
/**
* Removes all entries of this map that satisfy the given [predicate].
*/
void removeWhere(bool predicate(K key, V value));
/**
* Look up the value of [key], or add a new value if it isn't there.
*
* Returns the value associated to [key], if there is one.
* Otherwise calls [ifAbsent] to get a new value, associates [key] to
* that value, and then returns the new value.
*
* Map<String, int> scores = {'Bob': 36};
* for (var key in ['Bob', 'Rohan', 'Sophena']) {
* scores.putIfAbsent(key, () => key.length);
* }
* scores['Bob']; // 36
* scores['Rohan']; // 5
* scores['Sophena']; // 7
*
* Calling [ifAbsent] must not add or remove keys from the map.
*/
V putIfAbsent(K key, V ifAbsent());
/**
* Adds all key/value pairs of [other] to this map.
*
* If a key of [other] is already in this map, its value is overwritten.
*
* The operation is equivalent to doing `this[key] = value` for each key
* and associated value in other. It iterates over [other], which must
* therefore not change during the iteration.
*/
void addAll(Map<K, V> other);
/**
* Removes [key] and its associated value, if present, from the map.
*
* Returns the value associated with `key` before it was removed.
* Returns `null` if `key` was not in the map.
*
* Note that values can be `null` and a returned `null` value doesn't
* always mean that the key was absent.
*/
V? remove(Object? key);
/**
* Removes all pairs from the map.
*
* After this, the map is empty.
*/
void clear();
/**
* Applies [f] to each key/value pair of the map.
*
* Calling `f` must not add or remove keys from the map.
*/
void forEach(void f(K key, V value));
/**
* The keys of [this].
*
* The returned iterable has efficient `length` and `contains` operations,
* based on [length] and [containsKey] of the map.
*
* The order of iteration is defined by the individual `Map` implementation,
* but must be consistent between changes to the map.
*
* Modifying the map while iterating the keys
* may break the iteration.
*/
Iterable<K> get keys;
/**
* The values of [this].
*
* The values are iterated in the order of their corresponding keys.
* This means that iterating [keys] and [values] in parallel will
* provide matching pairs of keys and values.
*
* The returned iterable has an efficient `length` method based on the
* [length] of the map. Its [Iterable.contains] method is based on
* `==` comparison.
*
* Modifying the map while iterating the
* values may break the iteration.
*/
Iterable<V> get values;
/**
* The number of key/value pairs in the map.
*/
int get length;
/**
* Returns true if there is no key/value pair in the map.
*/
bool get isEmpty;
/**
* Returns true if there is at least one key/value pair in the map.
*/
bool get isNotEmpty;
}
/**
* A key/value pair representing an entry in a [Map].
*/
class MapEntry<K, V> {
/** The key of the entry. */
final K key;
/** The value associated to [key] in the map. */
final V value;
/** Creates an entry with [key] and [value]. */
const factory MapEntry(K key, V value) = MapEntry<K, V>._;
const MapEntry._(this.key, this.value);
String toString() => "MapEntry(${key.toString()}: ${value.toString()})";
}