Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(119)

Side by Side Diff: lib/collections/helpers.dart

Issue 11274043: Move Arrays, Collections and Maps into a new library, dart:collections. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Review update. Created 8 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(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 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698