| OLD | NEW |
| 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 part of dart.collection; | 5 part of dart.collection; |
| 6 | 6 |
| 7 /** Common parts of [HashSet] and [LinkedHashSet] implementations. */ | 7 /** Common parts of [HashSet] and [LinkedHashSet] implementations. */ |
| 8 abstract class _HashSetBase<E> extends IterableBase<E> implements Set<E> { | 8 abstract class _HashSetBase<E> extends IterableBase<E> implements Set<E> { |
| 9 | 9 |
| 10 // Set. | 10 // Set. |
| 11 bool containsAll(Iterable<Object> other) { | 11 bool containsAll(Iterable<Object> other) { |
| 12 for (Object object in other) { | 12 for (Object object in other) { |
| 13 if (!this.contains(object)) return false; | 13 if (!this.contains(object)) return false; |
| 14 } | 14 } |
| 15 return true; | 15 return true; |
| 16 } | 16 } |
| 17 | 17 |
| 18 /** Create a new Set of the same type as this. */ | 18 /** Create a new Set of the same type as this. */ |
| 19 Set _newSet(); | 19 HashSet<E> _newSet(); |
| 20 | 20 |
| 21 Set<E> intersection(Set<Object> other) { | 21 Set<E> intersection(Set<Object> other) { |
| 22 Set<E> result = _newSet(); | 22 Set<E> result = _newSet(); |
| 23 if (other.length < this.length) { | 23 if (other.length < this.length) { |
| 24 for (var element in other) { | 24 for (var element in other) { |
| 25 if (this.contains(element)) result.add(element); | 25 if (this.contains(element)) result.add(element); |
| 26 } | 26 } |
| 27 } else { | 27 } else { |
| 28 for (E element in this) { | 28 for (E element in this) { |
| 29 if (other.contains(element)) result.add(element); | 29 if (other.contains(element)) result.add(element); |
| 30 } | 30 } |
| 31 } | 31 } |
| 32 return result; | 32 return result; |
| 33 } | 33 } |
| 34 | 34 |
| 35 Set<E> union(Set<E> other) { | 35 Set<E> union(Set<E> other) { |
| 36 return _newSet()..addAll(this)..addAll(other); | 36 return _newSet()..addAll(this)..addAll(other); |
| 37 } | 37 } |
| 38 | 38 |
| 39 Set<E> difference(Set<E> other) { | 39 Set<E> difference(Set<E> other) { |
| 40 HashSet<E> result = _newSet(); | 40 HashSet<E> result = _newSet(); |
| 41 for (E element in this) { | 41 for (E element in this) { |
| 42 if (!other.contains(element)) result.add(element); | 42 if (!other.contains(element)) result.add(element); |
| 43 } | 43 } |
| 44 return result; | 44 return result; |
| 45 } | 45 } |
| 46 | 46 |
| 47 void retainAll(Iterable objectsToRetain) { | 47 void retainAll(Iterable objectsToRetain) { |
| 48 Set retainSet; | 48 // TODO(lrn): Consider optimizing table based versions by |
| 49 if (objectsToRetain is Set) { | 49 // building a new table of the entries to retain. |
| 50 retainSet = objectsToRetain; | 50 Set retainSet = _newSet()..addAll(objectsToRetain); |
| 51 } else { | |
| 52 retainSet = objectsToRetain.toSet(); | |
| 53 } | |
| 54 retainWhere(retainSet.contains); | 51 retainWhere(retainSet.contains); |
| 55 } | 52 } |
| 56 | 53 |
| 54 List<E> toList({bool growable: true}) { |
| 55 List<E> result = new List<E>()..length = this.length; |
| 56 int i = 0; |
| 57 for (E element in this) result[i++] = element; |
| 58 return result; |
| 59 } |
| 60 |
| 61 Set<E> toSet() => _newSet()..addAll(this); |
| 62 |
| 57 // TODO(zarah) Remove this, and let it be inherited by IterableBase | 63 // TODO(zarah) Remove this, and let it be inherited by IterableBase |
| 58 String toString() => IterableMixinWorkaround.toStringIterable(this, '{', '}'); | 64 String toString() => IterableMixinWorkaround.toStringIterable(this, '{', '}'); |
| 59 } | 65 } |
| 60 | 66 |
| 61 /** | 67 /** |
| 62 * A [HashSet] is a hash-table based [Set] implementation. | 68 * A [HashSet] is a hash-table based [Set] implementation. |
| 63 * | 69 * |
| 64 * The elements of a `HashSet` must have consistent [Object.operator==] | 70 * The elements of a `HashSet` must have consistent equality |
| 65 * and [Object.hashCode] implementations. This means that the `==` operator | 71 * and hashCode implementations. This means that the equals operation |
| 66 * must define a stable equivalence relation on the elements (reflexive, | 72 * must define a stable equivalence relation on the elements (reflexive, |
| 67 * anti-symmetric, transitive, and consistent over time), and that `hashCode` | 73 * anti-symmetric, transitive, and consistent over time), and that the hashCode |
| 68 * must be the same for objects that are considered equal by `==`. | 74 * must consistent with equality, so that the same for objects that are |
| 75 * considered equal. |
| 69 * | 76 * |
| 70 * The set allows `null` as an element. | 77 * The set allows `null` as an element. |
| 71 * | 78 * |
| 72 * Most simple operations on `HashSet` are done in constant time: [add], | 79 * Most simple operations on `HashSet` are done in constant time: [add], |
| 73 * [contains], [remove], and [length]. | 80 * [contains], [remove], and [length]. |
| 74 */ | 81 */ |
| 75 class HashSet<E> extends _HashSetBase<E> { | 82 class HashSet<E> implements Set<E> { |
| 76 external HashSet(); | 83 /** |
| 84 * Create a hash set using the provided [equals] as equality. |
| 85 * |
| 86 * The provided [equals] must define a stable equivalence relation, and |
| 87 * [hashCode] must be consistent with [equals]. If the [equals] or [hashCode] |
| 88 * methods won't work on all objects, but only to instances of E, the |
| 89 * [isValidKey] predicate can be used to restrict the keys that they are |
| 90 * applied to. Any key for which [isValidKey] returns false is automatically |
| 91 * assumed to not be in the set. |
| 92 * |
| 93 * If [equals], [hashCode] and [isValidKey] are omitted, the set uses |
| 94 * the objects' intrinsic [Object.operator==] and [Object.hashCode]. |
| 95 * |
| 96 * If [isValidKey] is omitted, it defaults to testing if the object is an |
| 97 * [E] instance. |
| 98 * |
| 99 * If [equals] is [identical], this creates an identity set. Any hashCode |
| 100 * is compatible with [identical], and it applies to all objects, so |
| 101 * [hashCode] and [isValidKey] can safely be omitted. |
| 102 */ |
| 103 external factory HashSet({ bool equals(E e1, E e2), |
| 104 int hashCode(E e), |
| 105 bool isValidKey(potentialKey) }); |
| 77 | 106 |
| 107 /** |
| 108 * Create a hash set containing the elements of [iterable]. |
| 109 * |
| 110 * Creates a hash set as by `new HashSet<E>()` and adds each element of |
| 111 * `iterable` to this set in the order they are iterated. |
| 112 */ |
| 78 factory HashSet.from(Iterable<E> iterable) { | 113 factory HashSet.from(Iterable<E> iterable) { |
| 79 return new HashSet<E>()..addAll(iterable); | 114 return new HashSet<E>()..addAll(iterable); |
| 80 } | 115 } |
| 81 | |
| 82 // Iterable. | |
| 83 external Iterator<E> get iterator; | |
| 84 | |
| 85 external int get length; | |
| 86 | |
| 87 external bool get isEmpty; | |
| 88 | |
| 89 external bool get isNotEmpty; | |
| 90 | |
| 91 external bool contains(Object object); | |
| 92 | |
| 93 // Set. | |
| 94 external void add(E element); | |
| 95 | |
| 96 external void addAll(Iterable<E> objects); | |
| 97 | |
| 98 external bool remove(Object object); | |
| 99 | |
| 100 external void removeAll(Iterable<Object> objectsToRemove); | |
| 101 | |
| 102 external void removeWhere(bool test(E element)); | |
| 103 | |
| 104 external void retainWhere(bool test(E element)); | |
| 105 | |
| 106 external void clear(); | |
| 107 | |
| 108 Set<E> _newSet() => new HashSet<E>(); | |
| 109 } | 116 } |
| OLD | NEW |