| 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 | 11 |
| 12 import 'dart:collection'; |
| 13 |
| 12 /** | 14 /** |
| 13 * A named function of one argument that just returns it. Useful for using | 15 * A named function of one argument that just returns it. Useful for using |
| 14 * as a default value for a function parameter or other places where you want | 16 * as a default value for a function parameter or other places where you want |
| 15 * to concisely provide a function that just returns its argument. | 17 * to concisely provide a function that just returns its argument. |
| 16 */ | 18 */ |
| 17 doNothing(x) => x; | 19 doNothing(x) => x; |
| 18 | 20 |
| 19 /** Concatenate two lists. Handle the case where one or both might be null. */ | 21 /** Concatenate two lists. Handle the case where one or both might be null. */ |
| 20 // TODO(alanknight): Remove once issue 5342 is resolved. | 22 // TODO(alanknight): Remove once issue 5342 is resolved. |
| 21 Iterable append(Iterable a, Iterable b) { | 23 Iterable append(Iterable a, Iterable b) { |
| (...skipping 151 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 173 /** | 175 /** |
| 174 * This acts as a stand-in for some value that cannot be hashed. We can't | 176 * This acts as a stand-in for some value that cannot be hashed. We can't |
| 175 * just use const Object() because the compiler will fold them together. | 177 * just use const Object() because the compiler will fold them together. |
| 176 */ | 178 */ |
| 177 class _Sentinel { | 179 class _Sentinel { |
| 178 final _wrappedObject; | 180 final _wrappedObject; |
| 179 const _Sentinel(this._wrappedObject); | 181 const _Sentinel(this._wrappedObject); |
| 180 } | 182 } |
| 181 | 183 |
| 182 /** | 184 /** |
| 183 * This provides an identity map which also allows true, false, and null | 185 * This is used in the implementation of [IdentityMap]. We wrap all the keys |
| 184 * as valid keys. In the interests of avoiding duplicating map code, and | 186 * in an [_IdentityMapKey] that compares using the identity of the wrapped |
| 185 * because hashCode for arbitrary objects is currently very slow on the VM, | 187 * objects. It also treats equal primitive values as identical |
| 186 * just do a linear lookup. | 188 * to conserve space. |
| 187 */ | 189 */ |
| 188 class IdentityMap<K, V> implements Map<K, V> { | 190 class _IdentityMapKey { |
| 191 _IdentityMapKey(this._value); |
| 192 var _value; |
| 189 | 193 |
| 190 final List<K> keys = <K>[]; | 194 /** |
| 191 final List<V> values = <V>[]; | 195 * Check if an object is primitive to know if we should compare it using |
| 196 * equality or identity. We don't test null/true/false where it's the same. |
| 197 */ |
| 198 _isPrimitive(x) => x is String || x is num; |
| 192 | 199 |
| 193 V operator [](Object key) { | 200 operator ==(_IdentityMapKey w) => |
| 194 var index = _indexOf(key); | 201 _isPrimitive(_value) ? _value == w._value : identical(_value, w._value); |
| 195 return (index == -1) ? null : values[index]; | 202 get hashCode => _value.hashCode; |
| 203 get object => _value; |
| 204 } |
| 205 |
| 206 /** |
| 207 * This provides an identity map. We wrap all the objects in |
| 208 * an [_IdentityMapKey] that compares using the identity of the |
| 209 * wrapped objects. It also treats equal primitive values as identical |
| 210 * to conserve space. |
| 211 */ |
| 212 class IdentityMap<K, V> extends HashMap<K, V> { |
| 213 // TODO(alanknight): Replace with a system identity-based map once |
| 214 // one is available. Issue 4161. |
| 215 |
| 216 // Check before wrapping because some methods may call others, e.g. on |
| 217 // dart2js putIfAbsent calls containsKey, so without this we wrap forever. |
| 218 _wrap(Object key) => |
| 219 (key is _IdentityMapKey) ? key : new _IdentityMapKey(key); |
| 220 _unwrap(_IdentityMapKey wrapper) => wrapper.object; |
| 221 |
| 222 Iterable<K> get keys => super.keys.map((x) => _unwrap(x)); |
| 223 Iterable<V> get values => super.values; |
| 224 |
| 225 void forEach(void f(K key, V value)) { |
| 226 super.forEach((k, v) => f(_unwrap(k), v)); |
| 196 } | 227 } |
| 197 | 228 |
| 229 V operator [](K key) => super[_wrap(key)]; |
| 230 |
| 198 void operator []=(K key, V value) { | 231 void operator []=(K key, V value) { |
| 199 var index = _indexOf(key); | 232 super[_wrap(key)] = value; |
| 200 if (index == -1) { | |
| 201 keys.add(key); | |
| 202 values.add(value); | |
| 203 } else { | |
| 204 values[index] = value; | |
| 205 } | |
| 206 } | 233 } |
| 207 | 234 |
| 208 V putIfAbsent(K key, Function ifAbsent) { | 235 V putIfAbsent(K key, Function ifAbsent) => |
| 209 var index = _indexOf(key); | 236 super.putIfAbsent(_wrap(key), ifAbsent); |
| 210 if (index == -1) { | |
| 211 keys.add(key); | |
| 212 values.add(ifAbsent()); | |
| 213 return values.last; | |
| 214 } else { | |
| 215 return values[index]; | |
| 216 } | |
| 217 } | |
| 218 | 237 |
| 219 int _indexOf(Object key) { | 238 bool containsKey(Object key) => super.containsKey(_wrap(key)); |
| 220 // Go backwards on the guess that we are most likely to access the most | |
| 221 // recently added. | |
| 222 // Make strings and primitives unique | |
| 223 var compareEquality = isPrimitive(key); | |
| 224 for (var i = keys.length - 1; i >= 0; i--) { | |
| 225 var equal = compareEquality ? key == keys[i] : identical(key, keys[i]); | |
| 226 if (equal) return i; | |
| 227 } | |
| 228 return -1; | |
| 229 } | |
| 230 | 239 |
| 231 bool containsKey(Object key) => _indexOf(key) != -1; | 240 V remove(Object key) => super.remove(_wrap(key)); |
| 232 void forEach(f(K key, V value)) { | |
| 233 for (var i = 0; i < keys.length; i++) { | |
| 234 f(keys[i], values[i]); | |
| 235 } | |
| 236 } | |
| 237 | |
| 238 V remove(Object key) { | |
| 239 var index = _indexOf(key); | |
| 240 if (index == -1) return null; | |
| 241 keys.removeAt(index); | |
| 242 return values.removeAt(index); | |
| 243 } | |
| 244 | |
| 245 int get length => keys.length; | |
| 246 void clear() { | |
| 247 keys.clear(); | |
| 248 values.clear(); | |
| 249 } | |
| 250 bool get isEmpty => keys.isEmpty; | |
| 251 bool get isNotEmpty => !isEmpty; | |
| 252 | |
| 253 // Note that this is doing an equality comparison. | |
| 254 bool containsValue(Object x) => values.contains(x); | |
| 255 | |
| 256 void addAll(Map<K, V> other) { | |
| 257 other.forEach((K key, V value) { | |
| 258 this[key] = value; | |
| 259 }); | |
| 260 } | |
| 261 } | 241 } |
| OLD | NEW |