| Index: sdk/lib/_internal/lib/collection_patch.dart
|
| diff --git a/sdk/lib/_internal/lib/collection_patch.dart b/sdk/lib/_internal/lib/collection_patch.dart
|
| index 670b4ab51d4c09cd4923f2fe11b5896ce182bfb0..3ae7dab778f86a796d70baea07aebe73c46f9bdc 100644
|
| --- a/sdk/lib/_internal/lib/collection_patch.dart
|
| +++ b/sdk/lib/_internal/lib/collection_patch.dart
|
| @@ -883,6 +883,30 @@ class LinkedHashMapKeyIterator<E> implements Iterator<E> {
|
| }
|
|
|
| patch class HashSet<E> {
|
| + patch factory HashSet({ bool equals(E e1, E e2),
|
| + int hashCode(E e),
|
| + bool isValidKey(potentialKey) }) {
|
| + if (isValidKey == null) {
|
| + if (hashCode == null) {
|
| + if (equals == null) {
|
| + return new _HashSet<E>();
|
| + }
|
| + if (identical(identical, equals)) {
|
| + return new _IdentityHashSet<E>();
|
| + }
|
| + hashCode = _defaultHashCode;
|
| + } else if (equals == null) {
|
| + equals = _defaultEquals;
|
| + }
|
| + } else {
|
| + if (hashCode == null) hashCode = _defaultHashCode;
|
| + if (equals == null) equals = _defaultEquals;
|
| + }
|
| + return new _CustomHashSet<E>(equals, hashCode, isValidKey);
|
| + }
|
| +}
|
| +
|
| +class _HashSet<E> extends _HashSetBase<E> implements HashSet<E> {
|
| int _length = 0;
|
|
|
| // The hash set contents are divided into three parts: one part for
|
| @@ -904,18 +928,20 @@ patch class HashSet<E> {
|
| // guard against concurrent modifications.
|
| List _elements;
|
|
|
| - patch HashSet();
|
| + _HashSet();
|
| +
|
| + Set<E> _newSet() => new _HashSet<E>();
|
|
|
| // Iterable.
|
| - patch Iterator<E> get iterator {
|
| + Iterator<E> get iterator {
|
| return new HashSetIterator<E>(this, _computeElements());
|
| }
|
|
|
| - patch int get length => _length;
|
| - patch bool get isEmpty => _length == 0;
|
| - patch bool get isNotEmpty => !isEmpty;
|
| + int get length => _length;
|
| + bool get isEmpty => _length == 0;
|
| + bool get isNotEmpty => !isEmpty;
|
|
|
| - patch bool contains(Object object) {
|
| + bool contains(Object object) {
|
| if (_isStringElement(object)) {
|
| var strings = _strings;
|
| return (strings == null) ? false : _hasTableEntry(strings, object);
|
| @@ -931,7 +957,7 @@ patch class HashSet<E> {
|
| }
|
|
|
| // Collection.
|
| - patch void add(E element) {
|
| + void add(E element) {
|
| if (_isStringElement(element)) {
|
| var strings = _strings;
|
| if (strings == null) _strings = strings = _newHashTable();
|
| @@ -957,13 +983,13 @@ patch class HashSet<E> {
|
| }
|
| }
|
|
|
| - patch void addAll(Iterable<E> objects) {
|
| + void addAll(Iterable<E> objects) {
|
| for (E each in objects) {
|
| add(each);
|
| }
|
| }
|
|
|
| - patch bool remove(Object object) {
|
| + bool remove(Object object) {
|
| if (_isStringElement(object)) {
|
| return _removeHashTableEntry(_strings, object);
|
| } else if (_isNumericElement(object)) {
|
| @@ -985,21 +1011,21 @@ patch class HashSet<E> {
|
| }
|
| }
|
|
|
| - patch void removeAll(Iterable<Object> objectsToRemove) {
|
| + void removeAll(Iterable<Object> objectsToRemove) {
|
| for (var each in objectsToRemove) {
|
| remove(each);
|
| }
|
| }
|
|
|
| - patch void removeWhere(bool test(E element)) {
|
| + void removeWhere(bool test(E element)) {
|
| removeAll(_computeElements().where(test));
|
| }
|
|
|
| - patch void retainWhere(bool test(E element)) {
|
| + void retainWhere(bool test(E element)) {
|
| removeAll(_computeElements().where((E element) => !test(element)));
|
| }
|
|
|
| - patch void clear() {
|
| + void clear() {
|
| if (_length > 0) {
|
| _strings = _nums = _rest = _elements = null;
|
| _length = 0;
|
| @@ -1086,7 +1112,7 @@ patch class HashSet<E> {
|
| JS('bool', '(# & 0x3ffffff) === #', element, element);
|
| }
|
|
|
| - static int _computeHashCode(var element) {
|
| + int _computeHashCode(var element) {
|
| // We force the hash codes to be unsigned 30-bit integers to avoid
|
| // issues with problematic elements like '__proto__'. Another
|
| // option would be to throw an exception if the hash code isn't a
|
| @@ -1111,12 +1137,12 @@ patch class HashSet<E> {
|
| JS('void', 'delete #[#]', table, key);
|
| }
|
|
|
| - static List _getBucket(var table, var element) {
|
| + List _getBucket(var table, var element) {
|
| var hash = _computeHashCode(element);
|
| return JS('var', '#[#]', table, hash);
|
| }
|
|
|
| - static int _findBucketIndex(var bucket, var element) {
|
| + int _findBucketIndex(var bucket, var element) {
|
| if (bucket == null) return -1;
|
| int length = JS('int', '#.length', bucket);
|
| for (int i = 0; i < length; i++) {
|
| @@ -1139,6 +1165,56 @@ patch class HashSet<E> {
|
| }
|
| }
|
|
|
| +class _IdentityHashSet<E> extends _HashSet<E> {
|
| + Set<E> _newSet() => new _IdentityHashSet<E>();
|
| +
|
| + int _findBucketIndex(var bucket, var element) {
|
| + if (bucket == null) return -1;
|
| + int length = JS('int', '#.length', bucket);
|
| + for (int i = 0; i < length; i++) {
|
| + if (identical(JS('var', '#[#]', bucket, i), element)) return i;
|
| + }
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +class _CustomHashSet<E> extends _HashSet<E> {
|
| + _Equality<E> _equality;
|
| + _Hasher<E> _hasher;
|
| + _Predicate _validKey;
|
| + _CustomHashSet(this._equality, this._hasher, bool validKey(potentialKey))
|
| + : _validKey = (validKey != null) ? validKey : ((x) => x is E);
|
| +
|
| + Set<E> _newSet() => new _CustomHashSet<E>(_equality, _hasher, _validKey);
|
| +
|
| + int _findBucketIndex(var bucket, var element) {
|
| + if (bucket == null) return -1;
|
| + int length = JS('int', '#.length', bucket);
|
| + for (int i = 0; i < length; i++) {
|
| + if (_equality(JS('var', '#[#]', bucket, i), element)) return i;
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + int _computeHashCode(var element) {
|
| + // We force the hash codes to be unsigned 30-bit integers to avoid
|
| + // issues with problematic elements like '__proto__'. Another
|
| + // option would be to throw an exception if the hash code isn't a
|
| + // number.
|
| + return JS('int', '# & 0x3ffffff', _hasher(element));
|
| + }
|
| +
|
| + bool contains(Object object) {
|
| + if (!_validKey(object)) return false;
|
| + return super.contains(object);
|
| + }
|
| +
|
| + bool remove(Object object) {
|
| + if (!_validKey(object)) return false;
|
| + return super.remove(object);
|
| + }
|
| +}
|
| +
|
| // TODO(kasperl): Share this code with HashMapKeyIterator<E>?
|
| class HashSetIterator<E> implements Iterator<E> {
|
| final _set;
|
| @@ -1169,7 +1245,31 @@ class HashSetIterator<E> implements Iterator<E> {
|
| }
|
| }
|
|
|
| -patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| +patch class LinkedHashSet<E> {
|
| + patch factory LinkedHashSet({ bool equals(E e1, E e2),
|
| + int hashCode(E e),
|
| + bool isValidKey(potentialKey) }) {
|
| + if (isValidKey == null) {
|
| + if (hashCode == null) {
|
| + if (equals == null) {
|
| + return new _LinkedHashSet<E>();
|
| + }
|
| + if (identical(identical, equals)) {
|
| + return new _LinkedIdentityHashSet<E>();
|
| + }
|
| + hashCode = _defaultHashCode;
|
| + } else if (equals == null) {
|
| + equals = _defaultEquals;
|
| + }
|
| + } else {
|
| + if (hashCode == null) hashCode = _defaultHashCode;
|
| + if (equals == null) equals = _defaultEquals;
|
| + }
|
| + return new _LinkedCustomHashSet<E>(equals, hashCode, isValidKey);
|
| + }
|
| +}
|
| +
|
| +class _LinkedHashSet<E> extends _HashSetBase<E> implements LinkedHashSet<E> {
|
| int _length = 0;
|
|
|
| // The hash set contents are divided into three parts: one part for
|
| @@ -1195,22 +1295,24 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| // over.
|
| int _modifications = 0;
|
|
|
| - patch LinkedHashSet();
|
| + _LinkedHashSet();
|
| +
|
| + Set<E> _newSet() => new _LinkedHashSet<E>();
|
|
|
| void _unsupported(String operation) {
|
| throw 'LinkedHashSet: unsupported $operation';
|
| }
|
|
|
| // Iterable.
|
| - patch Iterator<E> get iterator {
|
| + Iterator<E> get iterator {
|
| return new LinkedHashSetIterator(this, _modifications);
|
| }
|
|
|
| - patch int get length => _length;
|
| - patch bool get isEmpty => _length == 0;
|
| - patch bool get isNotEmpty => !isEmpty;
|
| + int get length => _length;
|
| + bool get isEmpty => _length == 0;
|
| + bool get isNotEmpty => !isEmpty;
|
|
|
| - patch bool contains(Object object) {
|
| + bool contains(Object object) {
|
| if (_isStringElement(object)) {
|
| var strings = _strings;
|
| if (strings == null) return false;
|
| @@ -1229,7 +1331,7 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| }
|
| }
|
|
|
| - patch void forEach(void action(E element)) {
|
| + void forEach(void action(E element)) {
|
| LinkedHashSetCell cell = _first;
|
| int modifications = _modifications;
|
| while (cell != null) {
|
| @@ -1241,18 +1343,18 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| }
|
| }
|
|
|
| - patch E get first {
|
| + E get first {
|
| if (_first == null) throw new StateError("No elements");
|
| return _first._element;
|
| }
|
|
|
| - patch E get last {
|
| + E get last {
|
| if (_last == null) throw new StateError("No elements");
|
| return _last._element;
|
| }
|
|
|
| // Collection.
|
| - patch void add(E element) {
|
| + void add(E element) {
|
| if (_isStringElement(element)) {
|
| var strings = _strings;
|
| if (strings == null) _strings = strings = _newHashTable();
|
| @@ -1278,13 +1380,13 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| }
|
| }
|
|
|
| - patch void addAll(Iterable<E> objects) {
|
| + void addAll(Iterable<E> objects) {
|
| for (E object in objects) {
|
| add(object);
|
| }
|
| }
|
|
|
| - patch bool remove(Object object) {
|
| + bool remove(Object object) {
|
| if (_isStringElement(object)) {
|
| return _removeHashTableEntry(_strings, object);
|
| } else if (_isNumericElement(object)) {
|
| @@ -1303,17 +1405,17 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| }
|
| }
|
|
|
| - patch void removeAll(Iterable objectsToRemove) {
|
| + void removeAll(Iterable objectsToRemove) {
|
| for (var each in objectsToRemove) {
|
| remove(each);
|
| }
|
| }
|
|
|
| - patch void removeWhere(bool test(E element)) {
|
| + void removeWhere(bool test(E element)) {
|
| _filterWhere(test, true);
|
| }
|
|
|
| - patch void retainWhere(bool test(E element)) {
|
| + void retainWhere(bool test(E element)) {
|
| _filterWhere(test, false);
|
| }
|
|
|
| @@ -1332,7 +1434,7 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| }
|
| }
|
|
|
| - patch void clear() {
|
| + void clear() {
|
| if (_length > 0) {
|
| _strings = _nums = _rest = _first = _last = null;
|
| _length = 0;
|
| @@ -1409,7 +1511,7 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| JS('bool', '(# & 0x3ffffff) === #', element, element);
|
| }
|
|
|
| - static int _computeHashCode(var element) {
|
| + int _computeHashCode(var element) {
|
| // We force the hash codes to be unsigned 30-bit integers to avoid
|
| // issues with problematic elements like '__proto__'. Another
|
| // option would be to throw an exception if the hash code isn't a
|
| @@ -1430,12 +1532,12 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| JS('void', 'delete #[#]', table, key);
|
| }
|
|
|
| - static List _getBucket(var table, var element) {
|
| + List _getBucket(var table, var element) {
|
| var hash = _computeHashCode(element);
|
| return JS('var', '#[#]', table, hash);
|
| }
|
|
|
| - static int _findBucketIndex(var bucket, var element) {
|
| + int _findBucketIndex(var bucket, var element) {
|
| if (bucket == null) return -1;
|
| int length = JS('int', '#.length', bucket);
|
| for (int i = 0; i < length; i++) {
|
| @@ -1459,6 +1561,60 @@ patch class LinkedHashSet<E> extends _HashSetBase<E> {
|
| }
|
| }
|
|
|
| +class _LinkedIdentityHashSet<E> extends _LinkedHashSet<E> {
|
| + Set<E> _newSet() => new _LinkedIdentityHashSet<E>();
|
| +
|
| + int _findBucketIndex(var bucket, var element) {
|
| + if (bucket == null) return -1;
|
| + int length = JS('int', '#.length', bucket);
|
| + for (int i = 0; i < length; i++) {
|
| + LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
|
| + if (identical(cell._element, element)) return i;
|
| + }
|
| + return -1;
|
| + }
|
| +}
|
| +
|
| +class _LinkedCustomHashSet<E> extends _LinkedHashSet<E> {
|
| + _Equality<E> _equality;
|
| + _Hasher<E> _hasher;
|
| + _Predicate _validKey;
|
| + _LinkedCustomHashSet(this._equality, this._hasher,
|
| + bool validKey(potentialKey))
|
| + : _validKey = (validKey != null) ? validKey : ((x) => x is E);
|
| +
|
| + Set<E> _newSet() =>
|
| + new _LinkedCustomHashSet<E>(_equality, _hasher, _validKey);
|
| +
|
| + int _findBucketIndex(var bucket, var element) {
|
| + if (bucket == null) return -1;
|
| + int length = JS('int', '#.length', bucket);
|
| + for (int i = 0; i < length; i++) {
|
| + LinkedHashSetCell cell = JS('var', '#[#]', bucket, i);
|
| + if (_equality(cell._element, element)) return i;
|
| + }
|
| + return -1;
|
| + }
|
| +
|
| + int _computeHashCode(var element) {
|
| + // We force the hash codes to be unsigned 30-bit integers to avoid
|
| + // issues with problematic elements like '__proto__'. Another
|
| + // option would be to throw an exception if the hash code isn't a
|
| + // number.
|
| + return JS('int', '# & 0x3ffffff', _hasher(element));
|
| + }
|
| +
|
| + bool contains(Object object) {
|
| + if (!_validKey(object)) return false;
|
| + return super.contains(object);
|
| + }
|
| +
|
| + bool remove(Object object) {
|
| + if (!_validKey(object)) return false;
|
| + return super.remove(object);
|
| + }
|
| +}
|
| +
|
| class LinkedHashSetCell {
|
| final _element;
|
|
|
|
|