| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2011, 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 typedef num NumericValueSelector<T>(T value); | |
| 6 | |
| 7 /** | |
| 8 * General purpose collection utilities. | |
| 9 * TODO(jmesserly): make these top level functions? | |
| 10 */ | |
| 11 class CollectionUtils { | |
| 12 | |
| 13 static void insertAt(List arr, int pos, value) { | |
| 14 assert (pos >= 0); | |
| 15 assert (pos <= arr.length); | |
| 16 | |
| 17 if (pos == arr.length) { | |
| 18 arr.add(value); | |
| 19 } else { | |
| 20 // TODO(sigmund): replace this push with a call that ensures capacity | |
| 21 // (currently not supported in the JS implementation of list). E.g. | |
| 22 // [: arr.length = arr.length + 1; :] | |
| 23 arr.add(null); | |
| 24 | |
| 25 // shift elements from [pos] (note: arr already has null @ length - 1) | |
| 26 for (int i = arr.length - 2; i >= pos; i--) { | |
| 27 arr[i + 1] = arr[i]; | |
| 28 } | |
| 29 arr[pos] = value; | |
| 30 | |
| 31 // TODO(jmesserly): we won't need to do this once List | |
| 32 // implements insertAt | |
| 33 if (arr is ObservableList) { | |
| 34 // TODO(jmesserly): shouldn't need to cast after testing instanceof | |
| 35 ObservableList obs = arr; | |
| 36 obs.recordListInsert(pos, value); | |
| 37 } | |
| 38 } | |
| 39 } | |
| 40 | |
| 41 // Collection<T> supports most of the ES 5 list methods, but it's missing | |
| 42 // map. | |
| 43 | |
| 44 // TODO(jmesserly): we might want a version of this that return an iterable, | |
| 45 // however JS, Python and Ruby versions are all eager. | |
| 46 static List map(Iterable source, var mapper) { | |
| 47 // TODO(jmesserly): I was trying to set the capacity here, but instead it | |
| 48 // seems to create a fixed list. Hence assigning by index below. | |
| 49 List result = new List(source is List ? source.dynamic.length : null); | |
| 50 int i = 0; | |
| 51 for (final item in source) { | |
| 52 result[i++] = mapper(item); | |
| 53 } | |
| 54 return result; | |
| 55 } | |
| 56 | |
| 57 /** | |
| 58 * Finds the item in [source] that matches [test]. Returns null if | |
| 59 * no item matches. The typing should be: | |
| 60 * T find(Iterable<T> source, bool test(T item)), but we don't have generic | |
| 61 * functions. | |
| 62 */ | |
| 63 static find(Iterable source, bool test(item)) { | |
| 64 for (final item in source) { | |
| 65 if (test(item)) return item; | |
| 66 } | |
| 67 | |
| 68 return null; | |
| 69 } | |
| 70 | |
| 71 /** Compute the minimum of an iterable. Returns null if empty. */ | |
| 72 static num min(Iterable source) { | |
| 73 final iter = source.iterator(); | |
| 74 if (!iter.hasNext()) { | |
| 75 return null; | |
| 76 } | |
| 77 num best = iter.next(); | |
| 78 while (iter.hasNext()) { | |
| 79 best = Math.min(best, iter.next()); | |
| 80 } | |
| 81 return best; | |
| 82 } | |
| 83 | |
| 84 /** Compute the maximum of an iterable. Returns null if empty. */ | |
| 85 static num max(Iterable source) { | |
| 86 final iter = source.iterator(); | |
| 87 if (!iter.hasNext()) { | |
| 88 return null; | |
| 89 } | |
| 90 num best = iter.next(); | |
| 91 while (iter.hasNext()) { | |
| 92 best = Math.max(best, iter.next()); | |
| 93 } | |
| 94 return best; | |
| 95 } | |
| 96 | |
| 97 /** Orders an iterable by its values, or by a key selector. */ | |
| 98 static List orderBy(Iterable source, [NumericValueSelector selector = null]) { | |
| 99 final result = new List.from(source); | |
| 100 sortBy(result, selector); | |
| 101 return result; | |
| 102 } | |
| 103 | |
| 104 /** Sorts a list by its values, or by a key selector. */ | |
| 105 // TODO(jmesserly): we probably don't want to call the key selector more than | |
| 106 // once for a given element. This would improve performance and the API | |
| 107 // contract could be stronger. | |
| 108 static void sortBy(List list, [NumericValueSelector selector = null]) { | |
| 109 if (selector != null) { | |
| 110 list.sort((x, y) => selector(x) - selector(y)); | |
| 111 } else { | |
| 112 list.sort((x, y) => x - y); | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 /** Compute the sum of an iterable. An empty iterable is an error. */ | |
| 117 static num sum(Iterable source, [NumericValueSelector selector = null]) { | |
| 118 final iter = source.iterator(); | |
| 119 num total = 0; | |
| 120 if (selector != null) { | |
| 121 do { | |
| 122 total += selector(iter.next()); | |
| 123 } while (iter.hasNext()); | |
| 124 } else { | |
| 125 do { | |
| 126 total += iter.next(); | |
| 127 } while (iter.hasNext()); | |
| 128 } | |
| 129 return total; | |
| 130 } | |
| 131 | |
| 132 // TODO(jmesserly): something like should exist on Map, either a method or a | |
| 133 // constructor, see bug #5340679 | |
| 134 static void copyMap(Map dest, Map source) { | |
| 135 for (final k in source.getKeys()) { | |
| 136 dest[k] = source[k]; | |
| 137 } | |
| 138 } | |
| 139 } | |
| OLD | NEW |