| 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 * The [Collections] class implements static methods useful when |
| 7 * writing a class that implements [Collection] and the [iterator] |
| 8 * method. |
| 9 */ |
| 10 class Collections { |
| 11 static bool contains(Iterable iterable, var element) { |
| 12 for (final e in iterable) { |
| 13 if (element == e) return true; |
| 14 } |
| 15 return false; |
| 16 } |
| 17 |
| 18 static void forEach(Iterable iterable, void f(o)) { |
| 19 for (final e in iterable) { |
| 20 f(e); |
| 21 } |
| 22 } |
| 23 |
| 24 static bool some(Iterable iterable, bool f(o)) { |
| 25 for (final e in iterable) { |
| 26 if (f(e)) return true; |
| 27 } |
| 28 return false; |
| 29 } |
| 30 |
| 31 static bool every(Iterable iterable, bool f(o)) { |
| 32 for (final e in iterable) { |
| 33 if (!f(e)) return false; |
| 34 } |
| 35 return true; |
| 36 } |
| 37 |
| 38 static List map(Iterable source, List destination, f(o)) { |
| 39 for (final e in source) { |
| 40 destination.add(f(e)); |
| 41 } |
| 42 return destination; |
| 43 } |
| 44 |
| 45 static Dynamic reduce(Iterable iterable, |
| 46 Dynamic initialValue, |
| 47 Dynamic combine(Dynamic previousValue, element)) { |
| 48 for (final element in iterable) { |
| 49 initialValue = combine(initialValue, element); |
| 50 } |
| 51 return initialValue; |
| 52 } |
| 53 |
| 54 static List filter(Iterable source, List destination, bool f(o)) { |
| 55 for (final e in source) { |
| 56 if (f(e)) destination.add(e); |
| 57 } |
| 58 return destination; |
| 59 } |
| 60 |
| 61 static bool isEmpty(Iterable iterable) { |
| 62 return !iterable.iterator().hasNext; |
| 63 } |
| 64 |
| 65 // TODO(jjb): visiting list should be an identityHashSet when it exists |
| 66 |
| 67 /** |
| 68 * Returns a string representing the specified collection. If the |
| 69 * collection is a [List], the returned string looks like this: |
| 70 * [:'[element0, element1, ... elementN]':]. The value returned by its |
| 71 * [toString] method is used to represent each element. If the specified |
| 72 * collection is not a list, the returned string looks like this: |
| 73 * [:{element0, element1, ... elementN}:]. In other words, the strings |
| 74 * returned for lists are surrounded by square brackets, while the strings |
| 75 * returned for other collections are surrounded by curly braces. |
| 76 * |
| 77 * If the specified collection contains a reference to itself, either |
| 78 * directly or indirectly through other collections or maps, the contained |
| 79 * reference is rendered as [:'[...]':] if it is a list, or [:'{...}':] if |
| 80 * it is not. This prevents the infinite regress that would otherwise occur. |
| 81 * So, for example, calling this method on a list whose sole element is a |
| 82 * reference to itself would return [:'[[...]]':]. |
| 83 * |
| 84 * A typical implementation of a collection's [toString] method will |
| 85 * simply return the results of this method applied to the collection. |
| 86 */ |
| 87 static String collectionToString(Collection c) { |
| 88 var result = new StringBuffer(); |
| 89 _emitCollection(c, result, new List()); |
| 90 return result.toString(); |
| 91 } |
| 92 |
| 93 /** |
| 94 * Appends a string representing the specified collection to the specified |
| 95 * string buffer. The string is formatted as per [collectionToString]. |
| 96 * The [:visiting:] list contains references to all of the enclosing |
| 97 * collections and maps (which are currently in the process of being |
| 98 * emitted into [:result:]). The [:visiting:] parameter allows this method to |
| 99 * generate a [:'[...]':] or [:'{...}':] where required. In other words, |
| 100 * it allows this method and [_emitMap] to identify recursive collections |
| 101 * and maps. |
| 102 */ |
| 103 static void _emitCollection(Collection c, |
| 104 StringBuffer result, |
| 105 List visiting) { |
| 106 visiting.add(c); |
| 107 bool isList = c is List; |
| 108 result.add(isList ? '[' : '{'); |
| 109 |
| 110 bool first = true; |
| 111 for (var e in c) { |
| 112 if (!first) { |
| 113 result.add(', '); |
| 114 } |
| 115 first = false; |
| 116 _emitObject(e, result, visiting); |
| 117 } |
| 118 |
| 119 result.add(isList ? ']' : '}'); |
| 120 visiting.removeLast(); |
| 121 } |
| 122 |
| 123 /** |
| 124 * Appends a string representing the specified object to the specified |
| 125 * string buffer. If the object is a [Collection] or [Map], it is formatted |
| 126 * as per [collectionToString] or [mapToString]; otherwise, it is formatted |
| 127 * by invoking its own [toString] method. |
| 128 * |
| 129 * The [:visiting:] list contains references to all of the enclosing |
| 130 * collections and maps (which are currently in the process of being |
| 131 * emitted into [:result:]). The [:visiting:] parameter allows this method |
| 132 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, |
| 133 * it allows this method and [_emitCollection] to identify recursive maps |
| 134 * and collections. |
| 135 */ |
| 136 static void _emitObject(Object o, StringBuffer result, List visiting) { |
| 137 if (o is Collection) { |
| 138 if (_containsRef(visiting, o)) { |
| 139 result.add(o is List ? '[...]' : '{...}'); |
| 140 } else { |
| 141 _emitCollection(o, result, visiting); |
| 142 } |
| 143 } else if (o is Map) { |
| 144 if (_containsRef(visiting, o)) { |
| 145 result.add('{...}'); |
| 146 } else { |
| 147 Maps._emitMap(o, result, visiting); |
| 148 } |
| 149 } else { // o is neither a collection nor a map |
| 150 result.add(o); |
| 151 } |
| 152 } |
| 153 |
| 154 /** |
| 155 * Returns true if the specified collection contains the specified object |
| 156 * reference. |
| 157 */ |
| 158 static _containsRef(Collection c, Object ref) { |
| 159 for (var e in c) { |
| 160 if (e === ref) return true; |
| 161 } |
| 162 return false; |
| 163 } |
| 164 } |
| 165 |
| 166 |
| 167 // TODO(ngeoffray): Rename to Lists. |
| 168 class Arrays { |
| 169 static void copy(List src, int srcStart, |
| 170 List dst, int dstStart, int count) { |
| 171 if (srcStart === null) srcStart = 0; |
| 172 if (dstStart === null) dstStart = 0; |
| 173 |
| 174 if (srcStart < dstStart) { |
| 175 for (int i = srcStart + count - 1, j = dstStart + count - 1; |
| 176 i >= srcStart; i--, j--) { |
| 177 dst[j] = src[i]; |
| 178 } |
| 179 } else { |
| 180 for (int i = srcStart, j = dstStart; i < srcStart + count; i++, j++) { |
| 181 dst[j] = src[i]; |
| 182 } |
| 183 } |
| 184 } |
| 185 |
| 186 static bool areEqual(List a, Object b) { |
| 187 if (a === b) return true; |
| 188 if (!(b is List)) return false; |
| 189 int length = a.length; |
| 190 if (length != b.length) return false; |
| 191 |
| 192 for (int i = 0; i < length; i++) { |
| 193 if (a[i] !== b[i]) return false; |
| 194 } |
| 195 return true; |
| 196 } |
| 197 |
| 198 /** |
| 199 * Returns the index in the list [a] of the given [element], starting |
| 200 * the search at index [startIndex] to [endIndex] (exclusive). |
| 201 * Returns -1 if [element] is not found. |
| 202 */ |
| 203 static int indexOf(List a, |
| 204 Object element, |
| 205 int startIndex, |
| 206 int endIndex) { |
| 207 if (startIndex >= a.length) { |
| 208 return -1; |
| 209 } |
| 210 if (startIndex < 0) { |
| 211 startIndex = 0; |
| 212 } |
| 213 for (int i = startIndex; i < endIndex; i++) { |
| 214 if (a[i] == element) { |
| 215 return i; |
| 216 } |
| 217 } |
| 218 return -1; |
| 219 } |
| 220 |
| 221 /** |
| 222 * Returns the last index in the list [a] of the given [element], starting |
| 223 * the search at index [startIndex] to 0. |
| 224 * Returns -1 if [element] is not found. |
| 225 */ |
| 226 static int lastIndexOf(List a, Object element, int startIndex) { |
| 227 if (startIndex < 0) { |
| 228 return -1; |
| 229 } |
| 230 if (startIndex >= a.length) { |
| 231 startIndex = a.length - 1; |
| 232 } |
| 233 for (int i = startIndex; i >= 0; i--) { |
| 234 if (a[i] == element) { |
| 235 return i; |
| 236 } |
| 237 } |
| 238 return -1; |
| 239 } |
| 240 |
| 241 static void rangeCheck(List a, int start, int length) { |
| 242 if (length < 0) { |
| 243 throw new ArgumentError("negative length $length"); |
| 244 } |
| 245 if (start < 0 ) { |
| 246 String message = "$start must be greater than or equal to 0"; |
| 247 throw new IndexOutOfRangeException(message); |
| 248 } |
| 249 if (start + length > a.length) { |
| 250 String message = "$start + $length must be in the range [0..${a.length})"; |
| 251 throw new IndexOutOfRangeException(message); |
| 252 } |
| 253 } |
| 254 } |
| 255 |
| 256 |
| 257 /* |
| 258 * Helper class which implements complex [Map] operations |
| 259 * in term of basic ones ([Map.getKeys], [Map.operator []], |
| 260 * [Map.operator []=] and [Map.remove].) Not all methods are |
| 261 * necessary to implement each particular operation. |
| 262 */ |
| 263 class Maps { |
| 264 static bool containsValue(Map map, value) { |
| 265 for (final v in map.getValues()) { |
| 266 if (value == v) { |
| 267 return true; |
| 268 } |
| 269 } |
| 270 return false; |
| 271 } |
| 272 |
| 273 static bool containsKey(Map map, key) { |
| 274 for (final k in map.getKeys()) { |
| 275 if (key == k) { |
| 276 return true; |
| 277 } |
| 278 } |
| 279 return false; |
| 280 } |
| 281 |
| 282 static putIfAbsent(Map map, key, ifAbsent()) { |
| 283 if (map.containsKey(key)) { |
| 284 return map[key]; |
| 285 } |
| 286 final v = ifAbsent(); |
| 287 map[key] = v; |
| 288 return v; |
| 289 } |
| 290 |
| 291 static clear(Map map) { |
| 292 for (final k in map.getKeys()) { |
| 293 map.remove(k); |
| 294 } |
| 295 } |
| 296 |
| 297 static forEach(Map map, void f(key, value)) { |
| 298 for (final k in map.getKeys()) { |
| 299 f(k, map[k]); |
| 300 } |
| 301 } |
| 302 |
| 303 static Collection getValues(Map map) { |
| 304 final result = []; |
| 305 for (final k in map.getKeys()) { |
| 306 result.add(map[k]); |
| 307 } |
| 308 return result; |
| 309 } |
| 310 |
| 311 static int length(Map map) => map.getKeys().length; |
| 312 |
| 313 static bool isEmpty(Map map) => length(map) == 0; |
| 314 |
| 315 /** |
| 316 * Returns a string representing the specified map. The returned string |
| 317 * looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':]. |
| 318 * The value returned by its [toString] method is used to represent each |
| 319 * key or value. |
| 320 * |
| 321 * If the map collection contains a reference to itself, either |
| 322 * directly as a key or value, or indirectly through other collections |
| 323 * or maps, the contained reference is rendered as [:'{...}':]. This |
| 324 * prevents the infinite regress that would otherwise occur. So, for example, |
| 325 * calling this method on a map whose sole entry maps the string key 'me' |
| 326 * to a reference to the map would return [:'{me: {...}}':]. |
| 327 * |
| 328 * A typical implementation of a map's [toString] method will |
| 329 * simply return the results of this method applied to the collection. |
| 330 */ |
| 331 static String mapToString(Map m) { |
| 332 var result = new StringBuffer(); |
| 333 _emitMap(m, result, new List()); |
| 334 return result.toString(); |
| 335 } |
| 336 |
| 337 /** |
| 338 * Appends a string representing the specified map to the specified |
| 339 * string buffer. The string is formatted as per [mapToString]. |
| 340 * The [:visiting:] list contains references to all of the enclosing |
| 341 * collections and maps (which are currently in the process of being |
| 342 * emitted into [:result:]). The [:visiting:] parameter allows this method |
| 343 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, |
| 344 * it allows this method and [_emitCollection] to identify recursive maps |
| 345 * and collections. |
| 346 */ |
| 347 static void _emitMap(Map m, StringBuffer result, List visiting) { |
| 348 visiting.add(m); |
| 349 result.add('{'); |
| 350 |
| 351 bool first = true; |
| 352 m.forEach((k, v) { |
| 353 if (!first) { |
| 354 result.add(', '); |
| 355 } |
| 356 first = false; |
| 357 Collections._emitObject(k, result, visiting); |
| 358 result.add(': '); |
| 359 Collections._emitObject(v, result, visiting); |
| 360 }); |
| 361 |
| 362 result.add('}'); |
| 363 visiting.removeLast(); |
| 364 } |
| 365 } |
| OLD | NEW |