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

Unified 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: Created 8 years, 2 months 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 side-by-side diff with in-line comments
Download patch
Index: lib/collections/helpers.dart
diff --git a/lib/collections/helpers.dart b/lib/collections/helpers.dart
new file mode 100644
index 0000000000000000000000000000000000000000..747cd4aabe96f19f90366210ea0c94253c61c97e
--- /dev/null
+++ b/lib/collections/helpers.dart
@@ -0,0 +1,363 @@
+// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/**
+ * The [Collections] class implements static methods useful when
+ * writing a class that implements [Collection] and the [iterator]
+ * method.
+ */
+class Collections {
+ static bool contains(Iterable iterable, var element) {
+ for (final e in iterable) {
+ if (element == e) return true;
+ }
+ return false;
+ }
+
+ static void forEach(Iterable iterable, void f(o)) {
+ for (final e in iterable) {
+ f(e);
+ }
+ }
+
+ static bool some(Iterable iterable, bool f(o)) {
+ for (final e in iterable) {
+ if (f(e)) return true;
+ }
+ return false;
+ }
+
+ static bool every(Iterable iterable, bool f(o)) {
+ for (final e in iterable) {
+ if (!f(e)) return false;
+ }
+ return true;
+ }
+
+ static List map(Iterable source, List destination, f(o)) {
+ for (final e in source) {
+ destination.add(f(e));
+ }
+ return destination;
+ }
+
+ static Dynamic reduce(Iterable iterable,
+ Dynamic initialValue,
+ Dynamic combine(Dynamic previousValue, element)) {
+ for (final element in iterable) {
+ initialValue = combine(initialValue, element);
+ }
+ return initialValue;
+ }
+
+ static List filter(Iterable source, List destination, bool f(o)) {
+ for (final e in source) {
+ if (f(e)) destination.add(e);
+ }
+ return destination;
+ }
+
+ static bool isEmpty(Iterable iterable) {
+ return !iterable.iterator().hasNext;
+ }
+
+ // TODO(jjb): visiting list should be an identityHashSet when it exists
+
+ /**
+ * Returns a string representing the specified collection. If the
+ * collection is a [List], the returned string looks like this:
+ * [:'[element0, element1, ... elementN]':]. The value returned by its
+ * [toString] method is used to represent each element. If the specified
+ * collection is not a list, the returned string looks like this:
+ * [:{element0, element1, ... elementN}:]. In other words, the strings
+ * returned for lists are surrounded by square brackets, while the strings
+ * returned for other collections are surrounded by curly braces.
+ *
+ * If the specified collection contains a reference to itself, either
+ * directly or indirectly through other collections or maps, the contained
+ * reference is rendered as [:'[...]':] if it is a list, or [:'{...}':] if
+ * it is not. This prevents the infinite regress that would otherwise occur.
+ * So, for example, calling this method on a list whose sole element is a
+ * reference to itself would return [:'[[...]]':].
+ *
+ * A typical implementation of a collection's [toString] method will
+ * simply return the results of this method applied to the collection.
+ */
+ static String collectionToString(Collection c) {
+ var result = new StringBuffer();
+ _emitCollection(c, result, new List());
+ return result.toString();
+ }
+
+ /**
+ * Appends a string representing the specified collection to the specified
+ * string buffer. The string is formatted as per [collectionToString].
+ * The [:visiting:] list contains references to all of the enclosing
+ * collections and maps (which are currently in the process of being
+ * emitted into [:result:]). The [:visiting:] parameter allows this method to
+ * generate a [:'[...]':] or [:'{...}':] where required. In other words,
+ * it allows this method and [_emitMap] to identify recursive collections
+ * and maps.
+ */
+ 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.
+ visiting.add(c);
+ bool isList = c is List;
+ result.add(isList ? '[' : '{');
+
+ bool first = true;
+ for (var e in c) {
+ if (!first) {
+ result.add(', ');
+ }
+ first = false;
+ _emitObject(e, result, visiting);
+ }
+
+ result.add(isList ? ']' : '}');
+ visiting.removeLast();
+ }
+
+ /**
+ * Appends a string representing the specified object to the specified
+ * string buffer. If the object is a [Collection] or [Map], it is formatted
+ * as per [collectionToString] or [mapToString]; otherwise, it is formatted
+ * by invoking its own [toString] method.
+ *
+ * The [:visiting:] list contains references to all of the enclosing
+ * collections and maps (which are currently in the process of being
+ * emitted into [:result:]). The [:visiting:] parameter allows this method
+ * to generate a [:'[...]':] or [:'{...}':] where required. In other words,
+ * it allows this method and [_emitCollection] to identify recursive maps
+ * and collections.
+ */
+ static void _emitObject(Object o, StringBuffer result, List visiting) {
+ if (o is Collection) {
+ if (_containsRef(visiting, o)) {
+ result.add(o is List ? '[...]' : '{...}');
+ } else {
+ _emitCollection(o, result, visiting);
+ }
+ } else if (o is Map) {
+ if (_containsRef(visiting, o)) {
+ result.add('{...}');
+ } else {
+ Maps._emitMap(o, result, visiting);
+ }
+ } else { // o is neither a collection nor a map
+ result.add(o);
+ }
+ }
+
+ /**
+ * Returns true if the specified collection contains the specified object
+ * reference.
+ */
+ static _containsRef(Collection c, Object ref) {
+ for (var e in c) {
+ if (e === ref) return true;
+ }
+ return false;
+ }
+}
+
+
+// TODO(ngeoffray): Rename to Lists.
+class Arrays {
+ static void copy(List src, int srcStart,
+ List dst, int dstStart, int count) {
+ if (srcStart === null) srcStart = 0;
+ if (dstStart === null) dstStart = 0;
+
+ if (srcStart < dstStart) {
+ for (int i = srcStart + count - 1, j = dstStart + count - 1;
+ i >= srcStart; i--, j--) {
+ dst[j] = src[i];
+ }
+ } else {
+ for (int i = srcStart, j = dstStart; i < srcStart + count; i++, j++) {
+ dst[j] = src[i];
+ }
+ }
+ }
+
+ static bool areEqual(List a, Object b) {
+ if (a === b) return true;
+ if (!(b is List)) return false;
+ int length = a.length;
+ if (length != b.length) return false;
+
+ for (int i = 0; i < length; i++) {
+ if (a[i] !== b[i]) return false;
+ }
+ return true;
+ }
+
+ /**
+ * Returns the index in the list [a] of the given [element], starting
+ * the search at index [startIndex] to [endIndex] (exclusive).
+ * Returns -1 if [element] is not found.
+ */
+ static int indexOf(List a,
+ Object element,
+ int startIndex,
+ int endIndex) {
+ if (startIndex >= a.length) {
+ return -1;
+ }
+ if (startIndex < 0) {
+ startIndex = 0;
+ }
+ for (int i = startIndex; i < endIndex; i++) {
+ if (a[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ /**
+ * Returns the last index in the list [a] of the given [element], starting
+ * the search at index [startIndex] to 0.
+ * Returns -1 if [element] is not found.
+ */
+ static int lastIndexOf(List a, Object element, int startIndex) {
+ if (startIndex < 0) {
+ return -1;
+ }
+ if (startIndex >= a.length) {
+ startIndex = a.length - 1;
+ }
+ for (int i = startIndex; i >= 0; i--) {
+ if (a[i] == element) {
+ return i;
+ }
+ }
+ return -1;
+ }
+
+ static void rangeCheck(List a, int start, int length) {
+ if (length < 0) {
+ throw new ArgumentError("negative length $length");
+ }
+ if (start < 0 ) {
+ String message = "$start must be greater than or equal to 0";
+ throw new IndexOutOfRangeException(message);
+ }
+ if (start + length > a.length) {
+ String message = "$start + $length must be in the range [0..${a.length})";
+ throw new IndexOutOfRangeException(message);
+ }
+ }
+}
+
+
+/*
+ * Helper class which implements complex [Map] operations
+ * in term of basic ones ([Map.getKeys], [Map.operator []],
+ * [Map.operator []=] and [Map.remove].) Not all methods are
+ * necessary to implement each particular operation.
+ */
+class Maps {
+ static bool containsValue(Map map, value) {
+ for (final v in map.getValues()) {
+ if (value == v) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static bool containsKey(Map map, key) {
+ for (final k in map.getKeys()) {
+ if (key == k) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ static putIfAbsent(Map map, key, ifAbsent()) {
+ if (map.containsKey(key)) {
+ return map[key];
+ }
+ final v = ifAbsent();
+ map[key] = v;
+ return v;
+ }
+
+ static clear(Map map) {
+ for (final k in map.getKeys()) {
+ map.remove(k);
+ }
+ }
+
+ static forEach(Map map, void f(key, value)) {
+ for (final k in map.getKeys()) {
+ f(k, map[k]);
+ }
+ }
+
+ static Collection getValues(Map map) {
+ final result = [];
+ for (final k in map.getKeys()) {
+ result.add(map[k]);
+ }
+ return result;
+ }
+
+ static int length(Map map) => map.getKeys().length;
+
+ static bool isEmpty(Map map) => length(map) == 0;
+
+ /**
+ * Returns a string representing the specified map. The returned string
+ * looks like this: [:'{key0: value0, key1: value1, ... keyN: valueN}':].
+ * The value returned by its [toString] method is used to represent each
+ * key or value.
+ *
+ * If the map collection contains a reference to itself, either
+ * directly as a key or value, or indirectly through other collections
+ * or maps, the contained reference is rendered as [:'{...}':]. This
+ * prevents the infinite regress that would otherwise occur. So, for example,
+ * calling this method on a map whose sole entry maps the string key 'me'
+ * to a reference to the map would return [:'{me: {...}}':].
+ *
+ * A typical implementation of a map's [toString] method will
+ * simply return the results of this method applied to the collection.
+ */
+ static String mapToString(Map m) {
+ var result = new StringBuffer();
+ _emitMap(m, result, new List());
+ return result.toString();
+ }
+
+ /**
+ * Appends a string representing the specified map to the specified
+ * string buffer. The string is formatted as per [mapToString].
+ * The [:visiting:] list contains references to all of the enclosing
+ * collections and maps (which are currently in the process of being
+ * emitted into [:result:]). The [:visiting:] parameter allows this method
+ * to generate a [:'[...]':] or [:'{...}':] where required. In other words,
+ * it allows this method and [_emitCollection] to identify recursive maps
+ * and collections.
+ */
+ static void _emitMap(Map m, StringBuffer result, List visiting) {
+ visiting.add(m);
+ result.add('{');
+
+ bool first = true;
+ m.forEach((k, v) {
+ if (!first) {
+ result.add(', ');
+ }
+ first = false;
+ Collections._emitObject(k, result, visiting);
+ result.add(': ');
+ Collections._emitObject(v, result, visiting);
+ });
+
+ result.add('}');
+ visiting.removeLast();
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698