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