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

Unified Diff: sdk/lib/_internal/compiler/js_lib/collection_patch.dart

Issue 1188713005: Use an ES6 map for a linked identity hash map. (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: Created 5 years, 6 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
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/js_lib/foreign_helper.dart » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: sdk/lib/_internal/compiler/js_lib/collection_patch.dart
diff --git a/sdk/lib/_internal/compiler/js_lib/collection_patch.dart b/sdk/lib/_internal/compiler/js_lib/collection_patch.dart
index 9df7c993393011693306552cfbee61454f19a616..55af330c55d4a1a489eb0bbb2bdf92ecd8808080 100644
--- a/sdk/lib/_internal/compiler/js_lib/collection_patch.dart
+++ b/sdk/lib/_internal/compiler/js_lib/collection_patch.dart
@@ -9,6 +9,8 @@ import 'dart:_js_helper' show
JsLinkedHashMap, LinkedHashMapCell, LinkedHashMapKeyIterable,
LinkedHashMapKeyIterator;
+const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
+
@patch
class HashMap<K, V> {
@patch
@@ -500,7 +502,7 @@ class LinkedHashMap<K, V> {
} else {
if (identical(identityHashCode, hashCode) &&
identical(identical, equals)) {
- return new _LinkedIdentityHashMap<K, V>();
+ return new _LinkedIdentityHashMap<K, V>.es6();
}
if (equals == null) {
equals = _defaultEquals;
@@ -518,7 +520,7 @@ class LinkedHashMap<K, V> {
}
@patch
- factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>;
+ factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>.es6;
// Private factory constructor called by generated code for map literals.
@NoInline()
@@ -544,8 +546,20 @@ class LinkedHashMap<K, V> {
fillLiteralMap(keyValuePairs, new JsLinkedHashMap());
}
-// TODO(floitsch): use ES6 Maps when available.
class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> {
+ static bool get _supportsEs6Maps {
+ return JS('returns:bool;depends:none;effects:none;throws:never;gvn:true',
+ 'typeof Map != "undefined"');
+ }
+
+ factory _LinkedIdentityHashMap.es6() {
+ return (_USE_ES6_MAPS && _LinkedIdentityHashMap._supportsEs6Maps)
+ ? new _LinkedIdentityHashMap<K, V>()
+ : new _Es6LinkedIdentityHashMap<K, V>();
+ }
+
+ _LinkedIdentityHashMap();
+
int internalComputeHashCode(var key) {
// We force the hash codes to be unsigned 30-bit integers to avoid
// issues with problematic keys like '__proto__'. Another option
@@ -564,6 +578,166 @@ class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> {
}
}
+class _Es6LinkedIdentityHashMap<K, V>
+ extends _LinkedIdentityHashMap<K, V> implements InternalMap {
+ final _map;
+ int _modifications = 0;
+
+ _Es6LinkedIdentityHashMap() : _map = JS('var', 'new Map()');
+
+ int get length => JS('int', '#.size', _map);
+ bool get isEmpty => length == 0;
+ bool get isNotEmpty => !isEmpty;
+
+ Iterable<K> get keys => new _Es6MapIterable<K>(this, true);
+
+ Iterable<V> get values =>
+ new _Es6MapIterable<V>(this, false);
+
+ bool containsKey(Object key) {
+ return JS('bool', '#.has(#)', _map, key);
+ }
+
+ bool containsValue(Object value) {
+ return values.any((each) => each == value);
+ }
+
+ void addAll(Map<K, V> other) {
+ other.forEach((K key, V value) {
+ this[key] = value;
+ });
+ }
+
+ V operator[](Object key) {
+ return JS('var', '#.get(#)', _map, key);
+ }
+
+ void operator[]=(K key, V value) {
+ JS('var', '#.set(#, #)', _map, key, value);
+ _modified();
+ }
+
+ V putIfAbsent(K key, V ifAbsent()) {
+ if (containsKey(key)) return this[key];
+ V value = ifAbsent();
+ this[key] = value;
+ return value;
+ }
+
+ V remove(Object key) {
+ V value = this[key];
+ JS('bool', '#.delete(#)', _map, key);
+ _modified();
+ return value;
+ }
+
+ void clear() {
+ JS('void', '#.clear()', _map);
+ _modified();
+ }
+
+ void forEach(void action(K key, V value)) {
+ var jsEntries = JS('var', '#.entries()', _map);
+ int modifications = _modifications;
+ while (true) {
+ var next = JS('var', '#.next()', jsEntries);
+ bool done = JS('bool', '#.done', next);
+ if (done) break;
+ var entry = JS('var', '#.value', next);
+ var key = JS('var', '#[0]', entry);
+ var value = JS('var', '#[1]', entry);
+ action(key, value);
+ if (modifications != _modifications) {
+ throw new ConcurrentModificationError(this);
+ }
+ }
+ }
+
+ void _modified() {
+ // 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.
+ _modifications = (_modifications + 1) & 0x3ffffff;
+ }
+
+ String toString() => Maps.mapToString(this);
+}
+
+class _Es6MapIterable<E> extends Iterable<E>
+ implements EfficientLength {
+ final _map;
+ final bool _isKeys;
+
+ _Es6MapIterable(this._map, this._isKeys);
+
+ int get length => _map.length;
+ bool get isEmpty => _map.isEmpty;
+
+ Iterator<E> get iterator =>
+ new _Es6MapIterator<E>(_map, _map._modifications, _isKeys);
+
+ bool contains(Object element) => _map.containsKey(element);
+
+ void forEach(void f(E element)) {
+ var jsIterator;
+ if (_isKeys) {
+ jsIterator = JS('var', '#.keys()', _map._map);
+ } else {
+ jsIterator = JS('var', '#.values()', _map._map);
+ }
+ int modifications = _map._modifications;
+ while (true) {
+ var next = JS('var', '#.next()', jsIterator);
+ bool done = JS('bool', '#.done', next);
+ if (done) break;
+ var value = JS('var', '#.value', next);
+ f(value);
+ if (modifications != _map._modifications) {
+ throw new ConcurrentModificationError(_map);
+ }
+ }
+ }
+}
+
+class _Es6MapIterator<E> implements Iterator<E> {
+ final _map;
+ final int _modifications;
+ final bool _isKeys;
+ var _jsIterator;
+ var _next;
+ E _current;
+ bool _done;
+
+ _Es6MapIterator(this._map, this._modifications, this._isKeys) {
+ if (_isKeys) {
+ _jsIterator = JS('var', '#.keys()', _map._map);
+ } else {
+ _jsIterator = JS('var', '#.values()', _map._map);
+ }
+ _done = false;
+ }
+
+ E get current => _current;
+
+ bool moveNext() {
+ if (_modifications != _map._modifications) {
+ throw new ConcurrentModificationError(_map);
+ }
+ if (_done) return false;
+ _next = JS('var', '#.next()', _jsIterator);
+ bool done = JS('bool', '#.done', _next);
+ if (done) {
+ _current = null;
+ _done = true;
+ return false;
+ } else {
+ _current = JS('var', '#.value', _next);
+ return true;
+ }
+ }
+}
+
// TODO(floitsch): use ES6 maps when available.
class _LinkedCustomHashMap<K, V> extends JsLinkedHashMap<K, V> {
final _Equality<K> _equals;
« no previous file with comments | « no previous file | sdk/lib/_internal/compiler/js_lib/foreign_helper.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698