Index: mojo/public/dart/third_party/collection/lib/src/canonicalized_map.dart |
diff --git a/mojo/public/dart/third_party/collection/lib/src/canonicalized_map.dart b/mojo/public/dart/third_party/collection/lib/src/canonicalized_map.dart |
new file mode 100644 |
index 0000000000000000000000000000000000000000..7ee3f86c4c717ae4f7c38c72fdf789d19ee926ea |
--- /dev/null |
+++ b/mojo/public/dart/third_party/collection/lib/src/canonicalized_map.dart |
@@ -0,0 +1,115 @@ |
+// 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. |
+ |
+library dart.pkg.collection.canonicalized_map; |
+ |
+import 'dart:collection'; |
+ |
+import 'utils.dart'; |
+ |
+/** |
+ * A map whose keys are converted to canonical values of type `C`. |
+ * |
+ * This is useful for using case-insensitive String keys, for example. It's more |
+ * efficient than a [LinkedHashMap] with a custom equality operator because it |
+ * only canonicalizes each key once, rather than doing so for each comparison. |
+ * |
+ * By default, `null` is allowed as a key. It can be forbidden via the |
+ * `isValidKey` parameter. |
+ */ |
+class CanonicalizedMap<C, K, V> implements Map<K, V> { |
+ final Function _canonicalize; |
+ |
+ final Function _isValidKeyFn; |
+ |
+ final _base = new Map<C, Pair<K, V>>(); |
+ |
+ /** |
+ * Creates an empty canonicalized map. |
+ * |
+ * The [canonicalize] function should return the canonical value for the given |
+ * key. Keys with the same canonical value are considered equivalent. |
+ * |
+ * The [isValidKey] function is called before calling [canonicalize] for |
+ * methods that take arbitrary objects. It can be used to filter out keys that |
+ * can't be canonicalized. |
+ */ |
+ CanonicalizedMap(C canonicalize(K key), {bool isValidKey(Object key)}) |
+ : _canonicalize = canonicalize, |
+ _isValidKeyFn = isValidKey; |
+ |
+ /** |
+ * Creates a canonicalized map that is initialized with the key/value pairs of |
+ * [other]. |
+ * |
+ * The [canonicalize] function should return the canonical value for the given |
+ * key. Keys with the same canonical value are considered equivalent. |
+ * |
+ * The [isValidKey] function is called before calling [canonicalize] for |
+ * methods that take arbitrary objects. It can be used to filter out keys that |
+ * can't be canonicalized. |
+ */ |
+ CanonicalizedMap.from(Map<K, V> other, C canonicalize(K key), |
+ {bool isValidKey(Object key)}) |
+ : _canonicalize = canonicalize, |
+ _isValidKeyFn = isValidKey { |
+ addAll(other); |
+ } |
+ |
+ V operator [](Object key) { |
+ if (!_isValidKey(key)) return null; |
+ var pair = _base[_canonicalize(key)]; |
+ return pair == null ? null : pair.last; |
+ } |
+ |
+ void operator []=(K key, V value) { |
+ _base[_canonicalize(key)] = new Pair(key, value); |
+ } |
+ |
+ void addAll(Map<K, V> other) { |
+ other.forEach((key, value) => this[key] = value); |
+ } |
+ |
+ void clear() { |
+ _base.clear(); |
+ } |
+ |
+ bool containsKey(Object key) { |
+ if (!_isValidKey(key)) return false; |
+ return _base.containsKey(_canonicalize(key)); |
+ } |
+ |
+ bool containsValue(Object value) => |
+ _base.values.any((pair) => pair.last == value); |
+ |
+ void forEach(void f(K key, V value)) { |
+ _base.forEach((key, pair) => f(pair.first, pair.last)); |
+ } |
+ |
+ bool get isEmpty => _base.isEmpty; |
+ |
+ bool get isNotEmpty => _base.isNotEmpty; |
+ |
+ Iterable<K> get keys => _base.values.map((pair) => pair.first); |
+ |
+ int get length => _base.length; |
+ |
+ V putIfAbsent(K key, V ifAbsent()) { |
+ return _base.putIfAbsent(_canonicalize(key), |
+ () => new Pair(key, ifAbsent())).last; |
+ } |
+ |
+ V remove(Object key) { |
+ if (!_isValidKey(key)) return null; |
+ var pair = _base.remove(_canonicalize(key)); |
+ return pair == null ? null : pair.last; |
+ } |
+ |
+ Iterable<V> get values => _base.values.map((pair) => pair.last); |
+ |
+ String toString() => Maps.mapToString(this); |
+ |
+ bool _isValidKey(Object key) => (key == null || key is K) && |
+ (_isValidKeyFn == null || _isValidKeyFn(key)); |
+} |