| OLD | NEW |
| (Empty) | |
| 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 |
| 3 // BSD-style license that can be found in the LICENSE file. |
| 4 |
| 5 /** |
| 6 * This contains extra functions and classes useful for implementing |
| 7 * serialiation. Some or all of these will be removed once the functionality is |
| 8 * available in the core library. |
| 9 */ |
| 10 library serialization_helpers; |
| 11 import 'polyfill_identity_set.dart'; |
| 12 |
| 13 /** |
| 14 * 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 |
| 16 * to concisely provide a function that just returns its argument. |
| 17 */ |
| 18 doNothing(x) => x; |
| 19 |
| 20 /** Concatenate two lists. Handle the case where one or both might be null. */ |
| 21 // TODO(alanknight): Remove once issue 5342 is resolved. |
| 22 List append(List a, List b) { |
| 23 if (a == null) { |
| 24 return (b == null) ? [] : new List.from(b); |
| 25 } |
| 26 if (b == null) return new List.from(a); |
| 27 var result = new List.from(a); |
| 28 result.addAll(b); |
| 29 return result; |
| 30 } |
| 31 |
| 32 /** |
| 33 * Return a sorted version of [aCollection], using the default sort criterion. |
| 34 * Always returns a List, regardless of the type of [aCollection]. |
| 35 */ |
| 36 List sorted(aCollection) { |
| 37 var result = new List.from(aCollection); |
| 38 result.sort(); |
| 39 return result; |
| 40 } |
| 41 |
| 42 /** |
| 43 * Be able to iterate polymorphically between List-like and Map-like things. |
| 44 * 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 |
| 46 * was a Map from integer keys to string values. |
| 47 * Only supports forEach() and map() operations because that was all the code |
| 48 * needed for the moment. |
| 49 */ |
| 50 MapLikeIterable keysAndValues(x) { |
| 51 if (x is Map) return new MapLikeIterableForMap(x); |
| 52 if (x is Iterable) return new MapLikeIterableForList(x); |
| 53 throw new ArgumentError("Invalid argument"); |
| 54 } |
| 55 |
| 56 /** |
| 57 * A class for iterating over things as if they were Maps, which primarily |
| 58 * means that forEach() and map() pass two arguments, and map() returns a new |
| 59 * Map with the same keys as [collection] and values which have been transformed |
| 60 * by the argument to map(). |
| 61 */ |
| 62 abstract class MapLikeIterable { |
| 63 MapLikeIterable(this.collection); |
| 64 final collection; |
| 65 |
| 66 /** Iterate over the collection, passing both key and value parameters. */ |
| 67 void forEach(Function f); |
| 68 |
| 69 /** |
| 70 * Return a new collection whose keys are the same as [collection], but whose |
| 71 * values are the result of applying [f] to the key/value pairs. So, if |
| 72 * [collection] is a List, it will be the same as the map() method if the |
| 73 * [key] parameter wasn't passed. |
| 74 */ |
| 75 map(Function f) { |
| 76 var result = copyEmpty(); |
| 77 forEach((key, value) { |
| 78 result[key] = f(key, value); |
| 79 }); |
| 80 return result; |
| 81 } |
| 82 |
| 83 /** |
| 84 * Return an empty copy of our collection. Very limited, only knows enough |
| 85 * to return a Map or List as appropriate. |
| 86 */ |
| 87 copyEmpty(); |
| 88 } |
| 89 |
| 90 |
| 91 |
| 92 class MapLikeIterableForMap extends MapLikeIterable { |
| 93 MapLikeIterableForMap(collection) : super(collection); |
| 94 |
| 95 void forEach(Function f) { collection.forEach(f);} |
| 96 Map copyEmpty() => new Map(); |
| 97 } |
| 98 |
| 99 class MapLikeIterableForList extends MapLikeIterable { |
| 100 MapLikeIterableForList(collection) : super(collection); |
| 101 |
| 102 void forEach(f) { |
| 103 Iterator iterator = collection.iterator(); |
| 104 for (var i = 0; i < collection.length; i++) { |
| 105 f(i, iterator.next()); |
| 106 } |
| 107 } |
| 108 |
| 109 List copyEmpty() => new List(collection.length); |
| 110 } |
| 111 |
| 112 /** |
| 113 * An inverse of MapLikeIterable. Lets you iterate polymorphically between |
| 114 * List-like and Map-like things, but making them behave like Lists, instead |
| 115 * of behaving like Maps. |
| 116 * So values(["a", "b", "c"]).forEach((value) => ...); |
| 117 * will loop over the values "a", "b", "c", as if it were a List of values. |
| 118 * Only supports forEach() and map() operations because that was all I needed |
| 119 * for the moment. |
| 120 */ |
| 121 values(x) { |
| 122 if (x is Iterable) return x; |
| 123 if (x is Map) return new ListLikeIterable(x); |
| 124 throw new ArgumentError("Invalid argument"); |
| 125 } |
| 126 |
| 127 /** |
| 128 * A class for iterating over things as if they were Lists, which primarily |
| 129 * means that forEach passes one argument, and map() returns a new Map |
| 130 * with the same keys as [collection] and values which haev been transformed |
| 131 * by the argument to map(). |
| 132 */ |
| 133 class ListLikeIterable { |
| 134 ListLikeIterable(this.collection); |
| 135 final Map collection; |
| 136 |
| 137 /** Iterate over the collection, passing just the value parameters. */ |
| 138 forEach(f) { |
| 139 collection.forEach((key, value) => f(value)); |
| 140 } |
| 141 |
| 142 /** |
| 143 * Return a new collection whose keys are the same as [collection], but whose |
| 144 * values are the result of applying [f] to the key/value pairs. So, if |
| 145 * [collection] is a List, it will be the same as if map() had been called |
| 146 * directly on [collection]. |
| 147 */ |
| 148 map(Function f) { |
| 149 var result = new Map(); |
| 150 collection.forEach((key, value) => result[key] = f(value)); |
| 151 return result; |
| 152 } |
| 153 |
| 154 /** |
| 155 * Return an iterator that behaves like a List iterator, taking one parameter. |
| 156 */ |
| 157 Iterator iterator() => collection.values.iterator(); |
| 158 } |
| 159 |
| 160 /** |
| 161 * 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. |
| 163 */ |
| 164 class _Sentinel { |
| 165 final _wrappedObject; |
| 166 const _Sentinel(this._wrappedObject); |
| 167 } |
| 168 |
| 169 /** |
| 170 * This provides an identity map which allows true, false, and null as |
| 171 * valid keys. It does this by special casing them and using some other |
| 172 * known object as the key instead. |
| 173 */ |
| 174 class IdentityMapPlus<K, V> extends IdentityMap { |
| 175 final trueish = const _Sentinel(true); |
| 176 final falseish = const _Sentinel(false); |
| 177 final nullish = const _Sentinel(null); |
| 178 |
| 179 wrap(x) { |
| 180 if (x == true) return trueish; |
| 181 if (x == false) return falseish; |
| 182 if (x == null) return nullish; |
| 183 return x; |
| 184 } |
| 185 |
| 186 unwrap(x) { |
| 187 if (x is _Sentinel) return x._wrappedObject; |
| 188 return x; |
| 189 } |
| 190 |
| 191 operator [](key) => super[wrap(key)]; |
| 192 operator []=(key, value) => super[wrap(key)] = value; |
| 193 |
| 194 putIfAbsent(key, ifAbsent) => super.putIfAbsent(wrap(key), ifAbsent); |
| 195 |
| 196 containsKey(key) => super.containsKey(wrap(key)); |
| 197 forEach(f) => super.forEach((key, value) => f(unwrap(key), value)); |
| 198 remove(key) => super.remove(unwrap(key)); |
| 199 /** |
| 200 * Note that keys is a very inefficient operation for this type. Don't do it. |
| 201 */ |
| 202 get keys => super.keys.map((x) => unwrap(x)); |
| 203 } |
| 204 |
| 205 |
| OLD | NEW |