| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2014, 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 * Base implementations of [Set]. | |
| 7 */ | |
| 8 part of dart.collection; | |
| 9 | |
| 10 /** | |
| 11 * Mixin implementation of [Set]. | |
| 12 * | |
| 13 * This class provides a base implementation of a `Set` that depends only | |
| 14 * on the abstract members: [add], [contains], [lookup], [remove], | |
| 15 * [iterator], [length] and [toSet]. | |
| 16 * | |
| 17 * Some of the methods assume that `toSet` creates a modifiable set. | |
| 18 * If using this mixin for an unmodifiable set, | |
| 19 * where `toSet` should return an unmodifiable set, | |
| 20 * it's necessary to reimplement | |
| 21 * [retainAll], [union], [intersection] and [difference]. | |
| 22 * | |
| 23 * Implementations of `Set` using this mixin should consider also implementing | |
| 24 * `clear` in constant time. The default implementation works by removing every | |
| 25 * element. | |
| 26 */ | |
| 27 abstract class SetMixin<E> implements Set<E> { | |
| 28 // This class reimplements all of [IterableMixin]. | |
| 29 // If/when Dart mixins get more powerful, we should just create a single | |
| 30 // Mixin class from IterableMixin and the new methods of thisclass. | |
| 31 | |
| 32 bool add(E element); | |
| 33 | |
| 34 bool contains(Object element); | |
| 35 | |
| 36 E lookup(Object element); | |
| 37 | |
| 38 bool remove(Object element); | |
| 39 | |
| 40 Iterator<E> get iterator; | |
| 41 | |
| 42 Set<E> toSet(); | |
| 43 | |
| 44 int get length; | |
| 45 | |
| 46 bool get isEmpty => length == 0; | |
| 47 | |
| 48 bool get isNotEmpty => length != 0; | |
| 49 | |
| 50 void clear() { | |
| 51 removeAll(toList()); | |
| 52 } | |
| 53 | |
| 54 void addAll(Iterable<E> elements) { | |
| 55 for (E element in elements) add(element); | |
| 56 } | |
| 57 | |
| 58 void removeAll(Iterable<Object> elements) { | |
| 59 for (Object element in elements) remove(element); | |
| 60 } | |
| 61 | |
| 62 void retainAll(Iterable<Object> elements) { | |
| 63 // Create a copy of the set, remove all of elements from the copy, | |
| 64 // then remove all remaining elements in copy from this. | |
| 65 Set<E> toRemove = toSet(); | |
| 66 for (Object o in elements) { | |
| 67 toRemove.remove(o); | |
| 68 } | |
| 69 removeAll(toRemove); | |
| 70 } | |
| 71 | |
| 72 void removeWhere(bool test(E element)) { | |
| 73 List toRemove = []; | |
| 74 for (E element in this) { | |
| 75 if (test(element)) toRemove.add(element); | |
| 76 } | |
| 77 removeAll(toRemove); | |
| 78 } | |
| 79 | |
| 80 void retainWhere(bool test(E element)) { | |
| 81 List toRemove = []; | |
| 82 for (E element in this) { | |
| 83 if (!test(element)) toRemove.add(element); | |
| 84 } | |
| 85 removeAll(toRemove); | |
| 86 } | |
| 87 | |
| 88 bool containsAll(Iterable<Object> other) { | |
| 89 for (Object o in other) { | |
| 90 if (!contains(o)) return false; | |
| 91 } | |
| 92 return true; | |
| 93 } | |
| 94 | |
| 95 Set<E> union(Set<E> other) { | |
| 96 return toSet()..addAll(other); | |
| 97 } | |
| 98 | |
| 99 Set<E> intersection(Set<Object> other) { | |
| 100 Set<E> result = toSet(); | |
| 101 for (E element in this) { | |
| 102 if (!other.contains(element)) result.remove(element); | |
| 103 } | |
| 104 return result; | |
| 105 } | |
| 106 | |
| 107 Set<E> difference(Set<Object> other) { | |
| 108 Set<E> result = toSet(); | |
| 109 for (E element in this) { | |
| 110 if (other.contains(element)) result.remove(element); | |
| 111 } | |
| 112 return result; | |
| 113 } | |
| 114 | |
| 115 List<E> toList({bool growable: true}) { | |
| 116 List<E> result = growable ? (new List<E>()..length = length) | |
| 117 : new List<E>(length); | |
| 118 int i = 0; | |
| 119 for (E element in this) result[i++] = element; | |
| 120 return result; | |
| 121 } | |
| 122 | |
| 123 Iterable/*<T>*/ map/*<T>*/(/*=T*/f(E element)) => | |
| 124 new EfficientLengthMappedIterable<E, dynamic/*=T*/>(this, f); | |
| 125 | |
| 126 E get single { | |
| 127 if (length > 1) throw IterableElementError.tooMany(); | |
| 128 Iterator<E> it = iterator; | |
| 129 if (!it.moveNext()) throw IterableElementError.noElement(); | |
| 130 E result = it.current; | |
| 131 return result; | |
| 132 } | |
| 133 | |
| 134 String toString() => IterableBase.iterableToFullString(this, '{', '}'); | |
| 135 | |
| 136 // Copied from IterableMixin. | |
| 137 // Should be inherited if we had multi-level mixins. | |
| 138 | |
| 139 Iterable<E> where(bool f(E element)) => new WhereIterable<E>(this, f); | |
| 140 | |
| 141 Iterable/*<T>*/ expand/*<T>*/(Iterable/*<T>*/ f(E element)) => | |
| 142 new ExpandIterable<E, dynamic/*=T*/>(this, f); | |
| 143 | |
| 144 void forEach(void f(E element)) { | |
| 145 for (E element in this) f(element); | |
| 146 } | |
| 147 | |
| 148 E reduce(E combine(E value, E element)) { | |
| 149 Iterator<E> iterator = this.iterator; | |
| 150 if (!iterator.moveNext()) { | |
| 151 throw IterableElementError.noElement(); | |
| 152 } | |
| 153 E value = iterator.current; | |
| 154 while (iterator.moveNext()) { | |
| 155 value = combine(value, iterator.current); | |
| 156 } | |
| 157 return value; | |
| 158 } | |
| 159 | |
| 160 dynamic/*=T*/ fold/*<T>*/(var/*=T*/ initialValue, | |
| 161 dynamic/*=T*/ combine(var/*=T*/ previousValue, E element)) { | |
| 162 var value = initialValue; | |
| 163 for (E element in this) value = combine(value, element); | |
| 164 return value; | |
| 165 } | |
| 166 | |
| 167 bool every(bool f(E element)) { | |
| 168 for (E element in this) { | |
| 169 if (!f(element)) return false; | |
| 170 } | |
| 171 return true; | |
| 172 } | |
| 173 | |
| 174 String join([String separator = ""]) { | |
| 175 Iterator<E> iterator = this.iterator; | |
| 176 if (!iterator.moveNext()) return ""; | |
| 177 StringBuffer buffer = new StringBuffer(); | |
| 178 if (separator == null || separator == "") { | |
| 179 do { | |
| 180 buffer.write("${iterator.current}"); | |
| 181 } while (iterator.moveNext()); | |
| 182 } else { | |
| 183 buffer.write("${iterator.current}"); | |
| 184 while (iterator.moveNext()) { | |
| 185 buffer.write(separator); | |
| 186 buffer.write("${iterator.current}"); | |
| 187 } | |
| 188 } | |
| 189 return buffer.toString(); | |
| 190 } | |
| 191 | |
| 192 bool any(bool test(E element)) { | |
| 193 for (E element in this) { | |
| 194 if (test(element)) return true; | |
| 195 } | |
| 196 return false; | |
| 197 } | |
| 198 | |
| 199 Iterable<E> take(int n) { | |
| 200 return new TakeIterable<E>(this, n); | |
| 201 } | |
| 202 | |
| 203 Iterable<E> takeWhile(bool test(E value)) { | |
| 204 return new TakeWhileIterable<E>(this, test); | |
| 205 } | |
| 206 | |
| 207 Iterable<E> skip(int n) { | |
| 208 return new SkipIterable<E>(this, n); | |
| 209 } | |
| 210 | |
| 211 Iterable<E> skipWhile(bool test(E value)) { | |
| 212 return new SkipWhileIterable<E>(this, test); | |
| 213 } | |
| 214 | |
| 215 E get first { | |
| 216 Iterator<E> it = iterator; | |
| 217 if (!it.moveNext()) { | |
| 218 throw IterableElementError.noElement(); | |
| 219 } | |
| 220 return it.current; | |
| 221 } | |
| 222 | |
| 223 E get last { | |
| 224 Iterator<E> it = iterator; | |
| 225 if (!it.moveNext()) { | |
| 226 throw IterableElementError.noElement(); | |
| 227 } | |
| 228 E result; | |
| 229 do { | |
| 230 result = it.current; | |
| 231 } while(it.moveNext()); | |
| 232 return result; | |
| 233 } | |
| 234 | |
| 235 E firstWhere(bool test(E value), { E orElse() }) { | |
| 236 for (E element in this) { | |
| 237 if (test(element)) return element; | |
| 238 } | |
| 239 if (orElse != null) return orElse(); | |
| 240 throw IterableElementError.noElement(); | |
| 241 } | |
| 242 | |
| 243 E lastWhere(bool test(E value), { E orElse() }) { | |
| 244 E result = null; | |
| 245 bool foundMatching = false; | |
| 246 for (E element in this) { | |
| 247 if (test(element)) { | |
| 248 result = element; | |
| 249 foundMatching = true; | |
| 250 } | |
| 251 } | |
| 252 if (foundMatching) return result; | |
| 253 if (orElse != null) return orElse(); | |
| 254 throw IterableElementError.noElement(); | |
| 255 } | |
| 256 | |
| 257 E singleWhere(bool test(E value)) { | |
| 258 E result = null; | |
| 259 bool foundMatching = false; | |
| 260 for (E element in this) { | |
| 261 if (test(element)) { | |
| 262 if (foundMatching) { | |
| 263 throw IterableElementError.tooMany(); | |
| 264 } | |
| 265 result = element; | |
| 266 foundMatching = true; | |
| 267 } | |
| 268 } | |
| 269 if (foundMatching) return result; | |
| 270 throw IterableElementError.noElement(); | |
| 271 } | |
| 272 | |
| 273 E elementAt(int index) { | |
| 274 if (index is! int) throw new ArgumentError.notNull("index"); | |
| 275 RangeError.checkNotNegative(index, "index"); | |
| 276 int elementIndex = 0; | |
| 277 for (E element in this) { | |
| 278 if (index == elementIndex) return element; | |
| 279 elementIndex++; | |
| 280 } | |
| 281 throw new RangeError.index(index, this, "index", null, elementIndex); | |
| 282 } | |
| 283 } | |
| 284 | |
| 285 /** | |
| 286 * Base implementation of [Set]. | |
| 287 * | |
| 288 * This class provides a base implementation of a `Set` that depends only | |
| 289 * on the abstract members: [add], [contains], [lookup], [remove], | |
| 290 * [iterator], [length] and [toSet]. | |
| 291 * | |
| 292 * Some of the methods assume that `toSet` creates a modifiable set. | |
| 293 * If using this base class for an unmodifiable set, | |
| 294 * where `toSet` should return an unmodifiable set, | |
| 295 * it's necessary to reimplement | |
| 296 * [retainAll], [union], [intersection] and [difference]. | |
| 297 * | |
| 298 * Implementations of `Set` using this base should consider also implementing | |
| 299 * `clear` in constant time. The default implementation works by removing every | |
| 300 * element. | |
| 301 */ | |
| 302 abstract class SetBase<E> extends SetMixin<E> { | |
| 303 /** | |
| 304 * Convert a `Set` to a string as `{each, element, as, string}`. | |
| 305 * | |
| 306 * Handles circular references where converting one of the elements | |
| 307 * to a string ends up converting [set] to a string again. | |
| 308 */ | |
| 309 static String setToString(Set set) => | |
| 310 IterableBase.iterableToFullString(set, '{', '}'); | |
| 311 } | |
| OLD | NEW |