1ef4399df0
This uses optional new/const and `=` in named argument defaults. All changes are automated, except for: - utils/dartdevc/BUILD.gn: run DDC build scripts with --preview-dart-2 - pkg/dev_compiler/tool/patch_sdk.dart: add a TODO that Analyzer doesn't supporting implicit const in libraries.dart - pkg/dev_compiler/tool/input_sdk/libraries.dart: was not formatted due to the aforementioned Analyzer bug - tools/bots/test_matrix.json: run DDC sourcemap suite in Dart 2 mode - pkg/pkg.status: skip pkg/dev_compiler if running in Dart 1 mode Change-Id: I9b80ccba0c2cc7b66efc662a0b16562e3660aee3 Reviewed-on: https://dart-review.googlesource.com/60402 Commit-Queue: Jenny Messerly <jmesserly@google.com> Reviewed-by: Bob Nystrom <rnystrom@google.com>
551 lines
16 KiB
Dart
551 lines
16 KiB
Dart
// Copyright (c) 2013, 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.
|
|
|
|
// Patch file for dart:collection classes.
|
|
import 'dart:_foreign_helper' show JS, JSExportName;
|
|
import 'dart:_runtime' as dart;
|
|
import 'dart:_js_helper'
|
|
show
|
|
NoInline,
|
|
NoSideEffects,
|
|
NoThrows,
|
|
patch,
|
|
LinkedMap,
|
|
IdentityMap,
|
|
CustomHashMap,
|
|
CustomKeyHashMap,
|
|
DartIterator,
|
|
notNull,
|
|
putLinkedMapKey;
|
|
|
|
@patch
|
|
class HashMap<K, V> {
|
|
@patch
|
|
factory HashMap(
|
|
{bool equals(K key1, K key2),
|
|
int hashCode(K key),
|
|
bool isValidKey(Object potentialKey)}) {
|
|
if (isValidKey == null) {
|
|
if (hashCode == null) {
|
|
if (equals == null) {
|
|
if (identical(K, String) || identical(K, int)) {
|
|
return IdentityMap<K, V>();
|
|
}
|
|
return LinkedMap<K, V>();
|
|
}
|
|
hashCode = dart.hashCode;
|
|
} else if (identical(identityHashCode, hashCode) &&
|
|
identical(identical, equals)) {
|
|
return IdentityMap<K, V>();
|
|
}
|
|
return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
|
|
}
|
|
return CustomKeyHashMap<K, V>(
|
|
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
|
|
}
|
|
|
|
@patch
|
|
factory HashMap.identity() = IdentityMap<K, V>;
|
|
}
|
|
|
|
@patch
|
|
class LinkedHashMap<K, V> {
|
|
@patch
|
|
factory LinkedHashMap(
|
|
{bool equals(K key1, K key2),
|
|
int hashCode(K key),
|
|
bool isValidKey(Object potentialKey)}) {
|
|
if (isValidKey == null) {
|
|
if (hashCode == null) {
|
|
if (equals == null) {
|
|
if (identical(K, String) || identical(K, int)) {
|
|
return IdentityMap<K, V>();
|
|
}
|
|
return LinkedMap<K, V>();
|
|
}
|
|
hashCode = dart.hashCode;
|
|
} else if (identical(identityHashCode, hashCode) &&
|
|
identical(identical, equals)) {
|
|
return IdentityMap<K, V>();
|
|
}
|
|
return CustomHashMap<K, V>(equals ?? dart.equals, hashCode);
|
|
}
|
|
return CustomKeyHashMap<K, V>(
|
|
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
|
|
}
|
|
|
|
@patch
|
|
factory LinkedHashMap.identity() = IdentityMap<K, V>;
|
|
}
|
|
|
|
@patch
|
|
class HashSet<E> {
|
|
@patch
|
|
factory HashSet(
|
|
{bool equals(E e1, E e2),
|
|
int hashCode(E e),
|
|
bool isValidKey(Object potentialKey)}) {
|
|
if (isValidKey == null) {
|
|
if (hashCode == null) {
|
|
if (equals == null) {
|
|
if (identical(E, String) || identical(E, int)) {
|
|
return _IdentityHashSet<E>();
|
|
}
|
|
return _HashSet<E>();
|
|
}
|
|
hashCode = dart.hashCode;
|
|
} else if (identical(identityHashCode, hashCode) &&
|
|
identical(identical, equals)) {
|
|
return _IdentityHashSet<E>();
|
|
}
|
|
return _CustomHashSet<E>(
|
|
equals ?? dart.equals, hashCode ?? dart.hashCode);
|
|
}
|
|
return _CustomKeyHashSet<E>(
|
|
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
|
|
}
|
|
|
|
@patch
|
|
factory HashSet.identity() = _IdentityHashSet<E>;
|
|
}
|
|
|
|
@patch
|
|
class LinkedHashSet<E> {
|
|
@patch
|
|
factory LinkedHashSet(
|
|
{bool equals(E e1, E e2),
|
|
int hashCode(E e),
|
|
bool isValidKey(Object potentialKey)}) {
|
|
if (isValidKey == null) {
|
|
if (hashCode == null) {
|
|
if (equals == null) {
|
|
if (identical(E, String) || identical(E, int)) {
|
|
return _IdentityHashSet<E>();
|
|
}
|
|
return _HashSet<E>();
|
|
}
|
|
hashCode = dart.hashCode;
|
|
} else if (identical(identityHashCode, hashCode) &&
|
|
identical(identical, equals)) {
|
|
return _IdentityHashSet<E>();
|
|
}
|
|
return _CustomHashSet<E>(
|
|
equals ?? dart.equals, hashCode ?? dart.hashCode);
|
|
}
|
|
return _CustomKeyHashSet<E>(
|
|
equals ?? dart.equals, hashCode ?? dart.hashCode, isValidKey);
|
|
}
|
|
|
|
@patch
|
|
factory LinkedHashSet.identity() = _IdentityHashSet<E>;
|
|
}
|
|
|
|
class _HashSet<E> extends _InternalSet<E>
|
|
implements HashSet<E>, LinkedHashSet<E> {
|
|
/// The backing store for this set.
|
|
///
|
|
/// Keys that use identity equality are stored directly. For other types of
|
|
/// keys, we first look them up (by hashCode) in the [_keyMap] map, then
|
|
/// we lookup the key in this map.
|
|
@notNull
|
|
final _map = JS('', 'new Set()');
|
|
|
|
/// Items that use custom equality semantics.
|
|
///
|
|
/// This maps from the item's hashCode to the canonical key, which is then
|
|
/// used to lookup the item in [_map]. Keeping the data in our primary backing
|
|
/// map gives us the ordering semantics requred by [LinkedHashMap], while
|
|
/// also providing convenient access to keys/values.
|
|
@notNull
|
|
final _keyMap = JS('', 'new Map()');
|
|
|
|
// We track the number of modifications done to the key set of the
|
|
// hash map to be able to throw when the map is modified while being
|
|
// iterated over.
|
|
//
|
|
// Value cycles after 2^30 modifications so that modification counts are
|
|
// always unboxed (Smi) values. Modification detection will be missed if you
|
|
// make exactly some multiple of 2^30 modifications between advances of an
|
|
// iterator.
|
|
@notNull
|
|
int _modifications = 0;
|
|
|
|
_HashSet();
|
|
|
|
Set<E> _newSet() => _HashSet<E>();
|
|
|
|
Set<R> _newSimilarSet<R>() => _HashSet<R>();
|
|
|
|
bool contains(Object key) {
|
|
if (key == null) {
|
|
key = null;
|
|
} else if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
|
|
dart.identityEquals)) {
|
|
@notNull
|
|
var k = key;
|
|
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
|
|
if (buckets != null) {
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
k = JS('', '#[#]', buckets, i);
|
|
if (k == key) return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
return JS('bool', '#.has(#)', _map, key);
|
|
}
|
|
|
|
E lookup(Object key) {
|
|
if (key == null) return null;
|
|
if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
|
|
dart.identityEquals)) {
|
|
@notNull
|
|
var k = key;
|
|
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, k.hashCode);
|
|
if (buckets != null) {
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
k = JS('', '#[#]', buckets, i);
|
|
if (k == key) return JS('', '#', k);
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
return JS('', '#.has(#) ? # : null', _map, key, key);
|
|
}
|
|
|
|
bool add(E key) {
|
|
var map = _map;
|
|
if (key == null) {
|
|
if (JS('', '#.has(null)', map)) return false;
|
|
key = null;
|
|
} else if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
|
|
dart.identityEquals)) {
|
|
var keyMap = _keyMap;
|
|
@notNull
|
|
var k = key;
|
|
int hash = JS('!', '# & 0x3ffffff', k.hashCode);
|
|
var buckets = JS('', '#.get(#)', keyMap, hash);
|
|
if (buckets == null) {
|
|
JS('', '#.set(#, [#])', keyMap, hash, key);
|
|
} else {
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
k = JS('', '#[#]', buckets, i);
|
|
if (k == key) return false;
|
|
}
|
|
JS('', '#.push(#)', buckets, key);
|
|
}
|
|
} else if (JS('', '#.has(#)', map, key)) {
|
|
return false;
|
|
}
|
|
JS('', '#.add(#)', map, key);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
return true;
|
|
}
|
|
|
|
void addAll(Iterable<E> objects) {
|
|
var map = _map;
|
|
int length = JS('', '#.size', map);
|
|
for (E key in objects) {
|
|
if (key == null) {
|
|
key = null;
|
|
} else if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
|
|
dart.identityEquals)) {
|
|
key = putLinkedMapKey(key, _keyMap);
|
|
}
|
|
JS('', '#.add(#)', map, key);
|
|
}
|
|
if (length != JS<int>('!', '#.size', map)) {
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
}
|
|
}
|
|
|
|
bool remove(Object key) {
|
|
if (key == null) {
|
|
key = null;
|
|
} else if (JS('bool', '#[#] !== #', key, dart.extensionSymbol('_equals'),
|
|
dart.identityEquals)) {
|
|
@notNull
|
|
var k = key;
|
|
int hash = JS('!', '# & 0x3ffffff', k.hashCode);
|
|
var buckets = JS('', '#.get(#)', _keyMap, hash);
|
|
if (buckets == null) return false; // not found
|
|
for (int i = 0, n = JS('!', '#.length', buckets);;) {
|
|
k = JS('', '#[#]', buckets, i);
|
|
if (k == key) {
|
|
key = k;
|
|
if (n == 1) {
|
|
JS('', '#.delete(#)', _keyMap, hash);
|
|
} else {
|
|
JS('', '#.splice(#, 1)', buckets, i);
|
|
}
|
|
break;
|
|
}
|
|
if (++i >= n) return false; // not found
|
|
}
|
|
}
|
|
var map = _map;
|
|
if (JS('bool', '#.delete(#)', map, key)) {
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void clear() {
|
|
var map = _map;
|
|
if (JS<int>('!', '#.size', map) > 0) {
|
|
JS('', '#.clear()', map);
|
|
JS('', '#.clear()', _keyMap);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
class _IdentityHashSet<E> extends _InternalSet<E>
|
|
implements HashSet<E>, LinkedHashSet<E> {
|
|
/// The backing store for this set.
|
|
@notNull
|
|
final _map = JS('', 'new Set()');
|
|
|
|
@notNull
|
|
int _modifications = 0;
|
|
|
|
_IdentityHashSet();
|
|
|
|
Set<E> _newSet() => _IdentityHashSet<E>();
|
|
|
|
Set<R> _newSimilarSet<R>() => _IdentityHashSet<R>();
|
|
|
|
bool contains(Object element) {
|
|
return JS('', '#.has(#)', _map, element);
|
|
}
|
|
|
|
E lookup(Object element) {
|
|
return JS('', '#.has(#)', _map, element) ? element : null;
|
|
}
|
|
|
|
bool add(E element) {
|
|
var map = _map;
|
|
if (JS('bool', '#.has(#)', map, element)) return false;
|
|
JS('', '#.add(#)', map, element);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
return true;
|
|
}
|
|
|
|
void addAll(Iterable<E> objects) {
|
|
var map = _map;
|
|
int length = JS('', '#.size', map);
|
|
for (E key in objects) {
|
|
JS('', '#.add(#)', map, key);
|
|
}
|
|
if (length != JS<int>('!', '#.size', map)) {
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
}
|
|
}
|
|
|
|
bool remove(Object element) {
|
|
if (JS('bool', '#.delete(#)', _map, element)) {
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void clear() {
|
|
var map = _map;
|
|
if (JS<int>('!', '#.size', map) > 0) {
|
|
JS('', '#.clear()', map);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
class _CustomKeyHashSet<E> extends _CustomHashSet<E> {
|
|
_Predicate<Object> _validKey;
|
|
_CustomKeyHashSet(_Equality<E> equals, _Hasher<E> hashCode, this._validKey)
|
|
: super(equals, hashCode);
|
|
|
|
Set<E> _newSet() => _CustomKeyHashSet<E>(_equals, _hashCode, _validKey);
|
|
|
|
Set<R> _newSimilarSet<R>() => _HashSet<R>();
|
|
|
|
bool contains(Object element) {
|
|
// TODO(jmesserly): there is a subtle difference here compared to Dart 1.
|
|
// See the comment on CustomKeyHashMap.containsKey for more information.
|
|
// Treatment of `null` is different due to strong mode's requirement to
|
|
// perform an `element is E` check before calling equals/hashCode.
|
|
if (!_validKey(element)) return false;
|
|
return super.contains(element);
|
|
}
|
|
|
|
E lookup(Object element) {
|
|
if (!_validKey(element)) return null;
|
|
return super.lookup(element);
|
|
}
|
|
|
|
bool remove(Object element) {
|
|
if (!_validKey(element)) return false;
|
|
return super.remove(element);
|
|
}
|
|
}
|
|
|
|
class _CustomHashSet<E> extends _InternalSet<E>
|
|
implements HashSet<E>, LinkedHashSet<E> {
|
|
_Equality<E> _equals;
|
|
_Hasher<E> _hashCode;
|
|
|
|
// We track the number of modifications done to the key set of the
|
|
// hash map to be able to throw when the map is modified while being
|
|
// iterated over.
|
|
//
|
|
// Value cycles after 2^30 modifications so that modification counts are
|
|
// always unboxed (Smi) values. Modification detection will be missed if you
|
|
// make exactly some multiple of 2^30 modifications between advances of an
|
|
// iterator.
|
|
@notNull
|
|
int _modifications = 0;
|
|
|
|
/// The backing store for this set, used to handle ordering.
|
|
// TODO(jmesserly): a non-linked custom hash set could skip this.
|
|
@notNull
|
|
final _map = JS('', 'new Set()');
|
|
|
|
/// Our map used to map keys onto the canonical key that is stored in [_map].
|
|
@notNull
|
|
final _keyMap = JS('', 'new Map()');
|
|
|
|
_CustomHashSet(this._equals, this._hashCode);
|
|
|
|
Set<E> _newSet() => _CustomHashSet<E>(_equals, _hashCode);
|
|
Set<R> _newSimilarSet<R>() => _HashSet<R>();
|
|
|
|
bool contains(Object key) {
|
|
if (key is E) {
|
|
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
|
|
if (buckets != null) {
|
|
var equals = _equals;
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
E k = JS('', '#[#]', buckets, i);
|
|
if (equals(k, key)) return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
E lookup(Object key) {
|
|
if (key is E) {
|
|
var buckets = JS('', '#.get(# & 0x3ffffff)', _keyMap, _hashCode(key));
|
|
if (buckets != null) {
|
|
var equals = _equals;
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
E k = JS('', '#[#]', buckets, i);
|
|
if (equals(k, key)) return JS('', '#', k);
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
|
|
bool add(E key) {
|
|
var keyMap = _keyMap;
|
|
var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
|
|
var buckets = JS('', '#.get(#)', keyMap, hash);
|
|
if (buckets == null) {
|
|
JS('', '#.set(#, [#])', keyMap, hash, key);
|
|
} else {
|
|
var equals = _equals;
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
E k = JS('', '#[#]', buckets, i);
|
|
if (equals(k, key)) return false;
|
|
}
|
|
JS('', '#.push(#)', buckets, key);
|
|
}
|
|
JS('', '#.add(#)', _map, key);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
return true;
|
|
}
|
|
|
|
void addAll(Iterable<E> objects) {
|
|
// TODO(jmesserly): it'd be nice to skip the covariance check here.
|
|
for (E element in objects) add(element);
|
|
}
|
|
|
|
bool remove(Object key) {
|
|
if (key is E) {
|
|
var hash = JS<int>('!', '# & 0x3ffffff', _hashCode(key));
|
|
var keyMap = _keyMap;
|
|
var buckets = JS('', '#.get(#)', keyMap, hash);
|
|
if (buckets == null) return false; // not found
|
|
var equals = _equals;
|
|
for (int i = 0, n = JS('!', '#.length', buckets); i < n; i++) {
|
|
E k = JS('', '#[#]', buckets, i);
|
|
if (equals(k, key)) {
|
|
if (n == 1) {
|
|
JS('', '#.delete(#)', keyMap, hash);
|
|
} else {
|
|
JS('', '#.splice(#, 1)', buckets, i);
|
|
}
|
|
JS('', '#.delete(#)', _map, k);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void clear() {
|
|
var map = _map;
|
|
if (JS<int>('!', '#.size', map) > 0) {
|
|
JS('', '#.clear()', map);
|
|
JS('', '#.clear()', _keyMap);
|
|
_modifications = (_modifications + 1) & 0x3ffffff;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// Base class for our internal [LinkedHashSet]/[HashSet] implementations.
|
|
///
|
|
/// This implements the common functionality.
|
|
abstract class _InternalSet<E> extends _HashSetBase<E> {
|
|
@notNull
|
|
get _map;
|
|
|
|
@notNull
|
|
int get _modifications;
|
|
|
|
@notNull
|
|
int get length => JS<int>('!', '#.size', _map);
|
|
|
|
@notNull
|
|
bool get isEmpty => JS('bool', '#.size == 0', _map);
|
|
|
|
@notNull
|
|
bool get isNotEmpty => JS('bool', '#.size != 0', _map);
|
|
|
|
Iterator<E> get iterator => DartIterator<E>(_jsIterator());
|
|
|
|
@JSExportName('Symbol.iterator')
|
|
_jsIterator() {
|
|
var self = this;
|
|
var iterator = JS('', '#.values()', self._map);
|
|
int modifications = self._modifications;
|
|
return JS(
|
|
'',
|
|
'''{
|
|
next() {
|
|
if (# != #) {
|
|
throw #;
|
|
}
|
|
return #.next();
|
|
}
|
|
}''',
|
|
modifications,
|
|
self._modifications,
|
|
ConcurrentModificationError(self),
|
|
iterator);
|
|
}
|
|
}
|