OLD | NEW |
---|---|
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 /** | 5 /** |
6 * This contains extra functions and classes useful for implementing | 6 * This contains extra functions and classes useful for implementing |
7 * serialiation. Some or all of these will be removed once the functionality is | 7 * serialiation. Some or all of these will be removed once the functionality is |
8 * available in the core library. | 8 * available in the core library. |
9 */ | 9 */ |
10 library serialization_helpers; | 10 library serialization_helpers; |
11 import 'polyfill_identity_set.dart'; | |
12 | 11 |
13 /** | 12 /** |
14 * A named function of one argument that just returns it. Useful for using | 13 * A named function of one argument that just returns it. Useful for using |
15 * as a default value for a function parameter or other places where you want | 14 * as a default value for a function parameter or other places where you want |
16 * to concisely provide a function that just returns its argument. | 15 * to concisely provide a function that just returns its argument. |
17 */ | 16 */ |
18 doNothing(x) => x; | 17 doNothing(x) => x; |
19 | 18 |
20 /** Concatenate two lists. Handle the case where one or both might be null. */ | 19 /** Concatenate two lists. Handle the case where one or both might be null. */ |
21 // TODO(alanknight): Remove once issue 5342 is resolved. | 20 // TODO(alanknight): Remove once issue 5342 is resolved. |
(...skipping 10 matching lines...) Expand all Loading... | |
32 /** | 31 /** |
33 * Return a sorted version of [aCollection], using the default sort criterion. | 32 * Return a sorted version of [aCollection], using the default sort criterion. |
34 * Always returns a List, regardless of the type of [aCollection]. | 33 * Always returns a List, regardless of the type of [aCollection]. |
35 */ | 34 */ |
36 List sorted(aCollection) { | 35 List sorted(aCollection) { |
37 var result = new List.from(aCollection); | 36 var result = new List.from(aCollection); |
38 result.sort(); | 37 result.sort(); |
39 return result; | 38 return result; |
40 } | 39 } |
41 | 40 |
41 /** Helper function for PrimitiveRule to tell which objects it applies to. */ | |
42 bool isPrimitive(object) { | |
43 return identical(object, null) || object is num || object is String || | |
44 identical(object, true) || identical(object, false); | |
45 } | |
46 | |
42 /** | 47 /** |
43 * Be able to iterate polymorphically between List-like and Map-like things. | 48 * Be able to iterate polymorphically between List-like and Map-like things. |
44 * For example, keysAndValues(["a", "b", "c"]).forEach((key, value) => ...); | 49 * For example, keysAndValues(["a", "b", "c"]).forEach((key, value) => ...); |
45 * will loop over the key/value pairs 1/"a", 2/"b", 3/"c", as if the argument | 50 * will loop over the key/value pairs 1/"a", 2/"b", 3/"c", as if the argument |
46 * was a Map from integer keys to string values. | 51 * was a Map from integer keys to string values. |
47 * Only supports forEach() and map() operations because that was all the code | 52 * Only supports forEach() and map() operations because that was all the code |
48 * needed for the moment. | 53 * needed for the moment. |
49 */ | 54 */ |
50 MapLikeIterable keysAndValues(x) { | 55 MapLikeIterable keysAndValues(x) { |
51 if (x is Map) return new MapLikeIterableForMap(x); | 56 if (x is Map) return new MapLikeIterableForMap(x); |
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
160 /** | 165 /** |
161 * This acts as a stand-in for some value that cannot be hashed. We can't | 166 * This acts as a stand-in for some value that cannot be hashed. We can't |
162 * just use const Object() because the compiler will fold them together. | 167 * just use const Object() because the compiler will fold them together. |
163 */ | 168 */ |
164 class _Sentinel { | 169 class _Sentinel { |
165 final _wrappedObject; | 170 final _wrappedObject; |
166 const _Sentinel(this._wrappedObject); | 171 const _Sentinel(this._wrappedObject); |
167 } | 172 } |
168 | 173 |
169 /** | 174 /** |
170 * This provides an identity map which allows true, false, and null as | 175 * This provides an identity map which also allows true, false, and null |
171 * valid keys. It does this by special casing them and using some other | 176 * as valid keys. In the interests of avoiding duplicating map code, and |
172 * known object as the key instead. | 177 * because hashCode for arbitrary objects is currently very slow on the VM, |
178 * just do a linear lookup. | |
173 */ | 179 */ |
174 class IdentityMapPlus<K, V> extends IdentityMap { | 180 class IdentityMap<K, V> implements Map<K, V> { |
175 final trueish = const _Sentinel(true); | |
176 final falseish = const _Sentinel(false); | |
177 final nullish = const _Sentinel(null); | |
178 | 181 |
179 wrap(x) { | 182 List<K> keys = <K>[]; |
180 if (x == true) return trueish; | 183 List<V> values = <V>[]; |
181 if (x == false) return falseish; | 184 |
182 if (x == null) return nullish; | 185 V operator [](K key) { |
183 return x; | 186 var index = _indexOf(key); |
187 return (index == -1) ? null : values[index]; | |
184 } | 188 } |
185 | 189 |
186 unwrap(x) { | 190 void operator []=(K key, V value) { |
187 if (x is _Sentinel) return x._wrappedObject; | 191 var index = _indexOf(key); |
188 return x; | 192 if (index == -1) { |
193 keys.add(key); | |
194 values.add(value); | |
195 } else { | |
196 values[index] = value; | |
197 } | |
189 } | 198 } |
190 | 199 |
191 operator [](key) => super[wrap(key)]; | 200 putIfAbsent(K key, Function ifAbsent) { |
192 operator []=(key, value) => super[wrap(key)] = value; | 201 var index = _indexOf(key); |
202 if (index == -1) { | |
203 keys.add(key); | |
204 values.add(ifAbsent()); | |
205 return values.last; | |
206 } else { | |
207 return values[index]; | |
208 } | |
209 } | |
193 | 210 |
194 putIfAbsent(key, ifAbsent) => super.putIfAbsent(wrap(key), ifAbsent); | 211 _indexOf(K key) { |
212 // Go backwards on the guess that we are most likely to access the most | |
213 // recently added. | |
214 // Make strings and primitives unique | |
215 var compareEquality = isPrimitive(key); | |
216 for (var i = keys.length - 1; i >= 0; i--) { | |
217 var equal = compareEquality ? key == keys[i] : identical(key, keys[i]); | |
218 if (equal) return i; | |
219 } | |
220 return -1; | |
221 } | |
195 | 222 |
196 containsKey(key) => super.containsKey(wrap(key)); | 223 bool containsKey(K key) => _indexOf(key) != -1; |
197 forEach(f) => super.forEach((key, value) => f(unwrap(key), value)); | 224 void forEach(f(K key, V value)) { |
198 remove(key) => super.remove(unwrap(key)); | 225 for (var i = 0; i < keys.length; i++) { |
199 /** | 226 f(keys[i], values[i]); |
200 * Note that keys is a very inefficient operation for this type. Don't do it. | 227 } |
201 */ | 228 } |
202 get keys => super.keys.map((x) => unwrap(x)); | |
203 } | |
204 | 229 |
230 V remove(K key) { | |
231 var index = _indexOf(key); | |
232 if (index == -1) return null; | |
233 keys.removeAt(index); | |
234 return values.removeAt(index); | |
235 } | |
205 | 236 |
237 int get length => keys.length; | |
238 void clear() { | |
239 keys = <K>[]; | |
Jennifer Messerly
2012/12/17 19:29:53
perhaps:
keys.clear();
values.clear(); ?
then ke
Alan Knight
2012/12/17 21:15:27
Nice. Done.
| |
240 values = <V>[]; | |
241 } | |
242 bool get isEmpty => keys.isEmpty; | |
243 | |
244 // Note that this is doing an equality comparison. | |
245 bool containsValue(x) => values.contains(x); | |
246 } | |
OLD | NEW |