Chromium Code Reviews| 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, StringBuffer result, List visiting) { | |
|
floitsch
2012/10/25 12:11:28
nyc: 80chars.
Anders Johnsen
2012/10/25 12:24:30
Done.
| |
| 104 visiting.add(c); | |
| 105 bool isList = c is List; | |
| 106 result.add(isList ? '[' : '{'); | |
| 107 | |
| 108 bool first = true; | |
| 109 for (var e in c) { | |
| 110 if (!first) { | |
| 111 result.add(', '); | |
| 112 } | |
| 113 first = false; | |
| 114 _emitObject(e, result, visiting); | |
| 115 } | |
| 116 | |
| 117 result.add(isList ? ']' : '}'); | |
| 118 visiting.removeLast(); | |
| 119 } | |
| 120 | |
| 121 /** | |
| 122 * Appends a string representing the specified object to the specified | |
| 123 * string buffer. If the object is a [Collection] or [Map], it is formatted | |
| 124 * as per [collectionToString] or [mapToString]; otherwise, it is formatted | |
| 125 * by invoking its own [toString] method. | |
| 126 * | |
| 127 * The [:visiting:] list contains references to all of the enclosing | |
| 128 * collections and maps (which are currently in the process of being | |
| 129 * emitted into [:result:]). The [:visiting:] parameter allows this method | |
| 130 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, | |
| 131 * it allows this method and [_emitCollection] to identify recursive maps | |
| 132 * and collections. | |
| 133 */ | |
| 134 static void _emitObject(Object o, StringBuffer result, List visiting) { | |
| 135 if (o is Collection) { | |
| 136 if (_containsRef(visiting, o)) { | |
| 137 result.add(o is List ? '[...]' : '{...}'); | |
| 138 } else { | |
| 139 _emitCollection(o, result, visiting); | |
| 140 } | |
| 141 } else if (o is Map) { | |
| 142 if (_containsRef(visiting, o)) { | |
| 143 result.add('{...}'); | |
| 144 } else { | |
| 145 Maps._emitMap(o, result, visiting); | |
| 146 } | |
| 147 } else { // o is neither a collection nor a map | |
| 148 result.add(o); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 /** | |
| 153 * Returns true if the specified collection contains the specified object | |
| 154 * reference. | |
| 155 */ | |
| 156 static _containsRef(Collection c, Object ref) { | |
| 157 for (var e in c) { | |
| 158 if (e === ref) return true; | |
| 159 } | |
| 160 return false; | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 | |
| 165 // TODO(ngeoffray): Rename to Lists. | |
| 166 class Arrays { | |
| 167 static void copy(List src, int srcStart, | |
| 168 List dst, int dstStart, int count) { | |
| 169 if (srcStart === null) srcStart = 0; | |
| 170 if (dstStart === null) dstStart = 0; | |
| 171 | |
| 172 if (srcStart < dstStart) { | |
| 173 for (int i = srcStart + count - 1, j = dstStart + count - 1; | |
| 174 i >= srcStart; i--, j--) { | |
| 175 dst[j] = src[i]; | |
| 176 } | |
| 177 } else { | |
| 178 for (int i = srcStart, j = dstStart; i < srcStart + count; i++, j++) { | |
| 179 dst[j] = src[i]; | |
| 180 } | |
| 181 } | |
| 182 } | |
| 183 | |
| 184 static bool areEqual(List a, Object b) { | |
| 185 if (a === b) return true; | |
| 186 if (!(b is List)) return false; | |
| 187 int length = a.length; | |
| 188 if (length != b.length) return false; | |
| 189 | |
| 190 for (int i = 0; i < length; i++) { | |
| 191 if (a[i] !== b[i]) return false; | |
| 192 } | |
| 193 return true; | |
| 194 } | |
| 195 | |
| 196 /** | |
| 197 * Returns the index in the list [a] of the given [element], starting | |
| 198 * the search at index [startIndex] to [endIndex] (exclusive). | |
| 199 * Returns -1 if [element] is not found. | |
| 200 */ | |
| 201 static int indexOf(List a, | |
| 202 Object element, | |
| 203 int startIndex, | |
| 204 int endIndex) { | |
| 205 if (startIndex >= a.length) { | |
| 206 return -1; | |
| 207 } | |
| 208 if (startIndex < 0) { | |
| 209 startIndex = 0; | |
| 210 } | |
| 211 for (int i = startIndex; i < endIndex; i++) { | |
| 212 if (a[i] == element) { | |
| 213 return i; | |
| 214 } | |
| 215 } | |
| 216 return -1; | |
| 217 } | |
| 218 | |
| 219 /** | |
| 220 * Returns the last index in the list [a] of the given [element], starting | |
| 221 * the search at index [startIndex] to 0. | |
| 222 * Returns -1 if [element] is not found. | |
| 223 */ | |
| 224 static int lastIndexOf(List a, Object element, int startIndex) { | |
| 225 if (startIndex < 0) { | |
| 226 return -1; | |
| 227 } | |
| 228 if (startIndex >= a.length) { | |
| 229 startIndex = a.length - 1; | |
| 230 } | |
| 231 for (int i = startIndex; i >= 0; i--) { | |
| 232 if (a[i] == element) { | |
| 233 return i; | |
| 234 } | |
| 235 } | |
| 236 return -1; | |
| 237 } | |
| 238 | |
| 239 static void rangeCheck(List a, int start, int length) { | |
| 240 if (length < 0) { | |
| 241 throw new ArgumentError("negative length $length"); | |
| 242 } | |
| 243 if (start < 0 ) { | |
| 244 String message = "$start must be greater than or equal to 0"; | |
| 245 throw new IndexOutOfRangeException(message); | |
| 246 } | |
| 247 if (start + length > a.length) { | |
| 248 String message = "$start + $length must be in the range [0..${a.length})"; | |
| 249 throw new IndexOutOfRangeException(message); | |
| 250 } | |
| 251 } | |
| 252 } | |
| 253 | |
| 254 | |
| 255 /* | |
| 256 * Helper class which implements complex [Map] operations | |
| 257 * in term of basic ones ([Map.getKeys], [Map.operator []], | |
| 258 * [Map.operator []=] and [Map.remove].) Not all methods are | |
| 259 * necessary to implement each particular operation. | |
| 260 */ | |
| 261 class Maps { | |
| 262 static bool containsValue(Map map, value) { | |
| 263 for (final v in map.getValues()) { | |
| 264 if (value == v) { | |
| 265 return true; | |
| 266 } | |
| 267 } | |
| 268 return false; | |
| 269 } | |
| 270 | |
| 271 static bool containsKey(Map map, key) { | |
| 272 for (final k in map.getKeys()) { | |
| 273 if (key == k) { | |
| 274 return true; | |
| 275 } | |
| 276 } | |
| 277 return false; | |
| 278 } | |
| 279 | |
| 280 static putIfAbsent(Map map, key, ifAbsent()) { | |
| 281 if (map.containsKey(key)) { | |
| 282 return map[key]; | |
| 283 } | |
| 284 final v = ifAbsent(); | |
| 285 map[key] = v; | |
| 286 return v; | |
| 287 } | |
| 288 | |
| 289 static clear(Map map) { | |
| 290 for (final k in map.getKeys()) { | |
| 291 map.remove(k); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 static forEach(Map map, void f(key, value)) { | |
| 296 for (final k in map.getKeys()) { | |
| 297 f(k, map[k]); | |
| 298 } | |
| 299 } | |
| 300 | |
| 301 static Collection getValues(Map map) { | |
| 302 final result = []; | |
| 303 for (final k in map.getKeys()) { | |
| 304 result.add(map[k]); | |
| 305 } | |
| 306 return result; | |
| 307 } | |
| 308 | |
| 309 static int length(Map map) => map.getKeys().length; | |
| 310 | |
| 311 static bool isEmpty(Map map) => length(map) == 0; | |
| 312 | |
| 313 /** | |
| 314 * Returns a string representing the specified map. The returned string | |
| 315 * looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':]. | |
| 316 * The value returned by its [toString] method is used to represent each | |
| 317 * key or value. | |
| 318 * | |
| 319 * If the map collection contains a reference to itself, either | |
| 320 * directly as a key or value, or indirectly through other collections | |
| 321 * or maps, the contained reference is rendered as [:'{...}':]. This | |
| 322 * prevents the infinite regress that would otherwise occur. So, for example, | |
| 323 * calling this method on a map whose sole entry maps the string key 'me' | |
| 324 * to a reference to the map would return [:'{me: {...}}':]. | |
| 325 * | |
| 326 * A typical implementation of a map's [toString] method will | |
| 327 * simply return the results of this method applied to the collection. | |
| 328 */ | |
| 329 static String mapToString(Map m) { | |
| 330 var result = new StringBuffer(); | |
| 331 _emitMap(m, result, new List()); | |
| 332 return result.toString(); | |
| 333 } | |
| 334 | |
| 335 /** | |
| 336 * Appends a string representing the specified map to the specified | |
| 337 * string buffer. The string is formatted as per [mapToString]. | |
| 338 * The [:visiting:] list contains references to all of the enclosing | |
| 339 * collections and maps (which are currently in the process of being | |
| 340 * emitted into [:result:]). The [:visiting:] parameter allows this method | |
| 341 * to generate a [:'[...]':] or [:'{...}':] where required. In other words, | |
| 342 * it allows this method and [_emitCollection] to identify recursive maps | |
| 343 * and collections. | |
| 344 */ | |
| 345 static void _emitMap(Map m, StringBuffer result, List visiting) { | |
| 346 visiting.add(m); | |
| 347 result.add('{'); | |
| 348 | |
| 349 bool first = true; | |
| 350 m.forEach((k, v) { | |
| 351 if (!first) { | |
| 352 result.add(', '); | |
| 353 } | |
| 354 first = false; | |
| 355 Collections._emitObject(k, result, visiting); | |
| 356 result.add(': '); | |
| 357 Collections._emitObject(v, result, visiting); | |
| 358 }); | |
| 359 | |
| 360 result.add('}'); | |
| 361 visiting.removeLast(); | |
| 362 } | |
| 363 } | |
| OLD | NEW |