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

Side by Side 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 unified diff | 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 »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 // Patch file for dart:collection classes. 5 // Patch file for dart:collection classes.
6 import 'dart:_foreign_helper' show JS; 6 import 'dart:_foreign_helper' show JS;
7 import 'dart:_js_helper' show 7 import 'dart:_js_helper' show
8 fillLiteralMap, InternalMap, NoInline, NoSideEffects, NoThrows, patch, 8 fillLiteralMap, InternalMap, NoInline, NoSideEffects, NoThrows, patch,
9 JsLinkedHashMap, LinkedHashMapCell, LinkedHashMapKeyIterable, 9 JsLinkedHashMap, LinkedHashMapCell, LinkedHashMapKeyIterable,
10 LinkedHashMapKeyIterator; 10 LinkedHashMapKeyIterator;
11 11
12 const _USE_ES6_MAPS = const bool.fromEnvironment("dart2js.use.es6.maps");
13
12 @patch 14 @patch
13 class HashMap<K, V> { 15 class HashMap<K, V> {
14 @patch 16 @patch
15 factory HashMap({ bool equals(K key1, K key2), 17 factory HashMap({ bool equals(K key1, K key2),
16 int hashCode(K key), 18 int hashCode(K key),
17 bool isValidKey(potentialKey) }) { 19 bool isValidKey(potentialKey) }) {
18 if (isValidKey == null) { 20 if (isValidKey == null) {
19 if (hashCode == null) { 21 if (hashCode == null) {
20 if (equals == null) { 22 if (equals == null) {
21 return new _HashMap<K, V>(); 23 return new _HashMap<K, V>();
(...skipping 471 matching lines...) Expand 10 before | Expand all | Expand 10 after
493 bool isValidKey(potentialKey) }) { 495 bool isValidKey(potentialKey) }) {
494 if (isValidKey == null) { 496 if (isValidKey == null) {
495 if (hashCode == null) { 497 if (hashCode == null) {
496 if (equals == null) { 498 if (equals == null) {
497 return new JsLinkedHashMap<K, V>.es6(); 499 return new JsLinkedHashMap<K, V>.es6();
498 } 500 }
499 hashCode = _defaultHashCode; 501 hashCode = _defaultHashCode;
500 } else { 502 } else {
501 if (identical(identityHashCode, hashCode) && 503 if (identical(identityHashCode, hashCode) &&
502 identical(identical, equals)) { 504 identical(identical, equals)) {
503 return new _LinkedIdentityHashMap<K, V>(); 505 return new _LinkedIdentityHashMap<K, V>.es6();
504 } 506 }
505 if (equals == null) { 507 if (equals == null) {
506 equals = _defaultEquals; 508 equals = _defaultEquals;
507 } 509 }
508 } 510 }
509 } else { 511 } else {
510 if (hashCode == null) { 512 if (hashCode == null) {
511 hashCode = _defaultHashCode; 513 hashCode = _defaultHashCode;
512 } 514 }
513 if (equals == null) { 515 if (equals == null) {
514 equals = _defaultEquals; 516 equals = _defaultEquals;
515 } 517 }
516 } 518 }
517 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); 519 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey);
518 } 520 }
519 521
520 @patch 522 @patch
521 factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>; 523 factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>.es6;
522 524
523 // Private factory constructor called by generated code for map literals. 525 // Private factory constructor called by generated code for map literals.
524 @NoInline() 526 @NoInline()
525 factory LinkedHashMap._literal(List keyValuePairs) { 527 factory LinkedHashMap._literal(List keyValuePairs) {
526 return fillLiteralMap(keyValuePairs, new JsLinkedHashMap<K, V>.es6()); 528 return fillLiteralMap(keyValuePairs, new JsLinkedHashMap<K, V>.es6());
527 } 529 }
528 530
529 // Private factory constructor called by generated code for map literals. 531 // Private factory constructor called by generated code for map literals.
530 @NoThrows() @NoInline() @NoSideEffects() 532 @NoThrows() @NoInline() @NoSideEffects()
531 factory LinkedHashMap._empty() { 533 factory LinkedHashMap._empty() {
532 return new JsLinkedHashMap<K, V>.es6(); 534 return new JsLinkedHashMap<K, V>.es6();
533 } 535 }
534 536
535 // Private factory static function called by generated code for map literals. 537 // Private factory static function called by generated code for map literals.
536 // This version is for map literals without type parameters. 538 // This version is for map literals without type parameters.
537 @NoInline() 539 @NoInline()
538 static _makeEmpty() => new JsLinkedHashMap(); 540 static _makeEmpty() => new JsLinkedHashMap();
539 541
540 // Private factory static function called by generated code for map literals. 542 // Private factory static function called by generated code for map literals.
541 // This version is for map literals without type parameters. 543 // This version is for map literals without type parameters.
542 @NoInline() 544 @NoInline()
543 static _makeLiteral(keyValuePairs) => 545 static _makeLiteral(keyValuePairs) =>
544 fillLiteralMap(keyValuePairs, new JsLinkedHashMap()); 546 fillLiteralMap(keyValuePairs, new JsLinkedHashMap());
545 } 547 }
546 548
547 // TODO(floitsch): use ES6 Maps when available.
548 class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> { 549 class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> {
550 static bool get _supportsEs6Maps {
551 return JS('returns:bool;depends:none;effects:none;throws:never;gvn:true',
552 'typeof Map != "undefined"');
553 }
554
555 factory _LinkedIdentityHashMap.es6() {
556 return (_USE_ES6_MAPS && _LinkedIdentityHashMap._supportsEs6Maps)
557 ? new _LinkedIdentityHashMap<K, V>()
558 : new _Es6LinkedIdentityHashMap<K, V>();
559 }
560
561 _LinkedIdentityHashMap();
562
549 int internalComputeHashCode(var key) { 563 int internalComputeHashCode(var key) {
550 // We force the hash codes to be unsigned 30-bit integers to avoid 564 // We force the hash codes to be unsigned 30-bit integers to avoid
551 // issues with problematic keys like '__proto__'. Another option 565 // issues with problematic keys like '__proto__'. Another option
552 // would be to throw an exception if the hash code isn't a number. 566 // would be to throw an exception if the hash code isn't a number.
553 return JS('int', '# & 0x3ffffff', identityHashCode(key)); 567 return JS('int', '# & 0x3ffffff', identityHashCode(key));
554 } 568 }
555 569
556 int internalFindBucketIndex(var bucket, var key) { 570 int internalFindBucketIndex(var bucket, var key) {
557 if (bucket == null) return -1; 571 if (bucket == null) return -1;
558 int length = JS('int', '#.length', bucket); 572 int length = JS('int', '#.length', bucket);
559 for (int i = 0; i < length; i++) { 573 for (int i = 0; i < length; i++) {
560 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i); 574 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i);
561 if (identical(cell.hashMapCellKey, key)) return i; 575 if (identical(cell.hashMapCellKey, key)) return i;
562 } 576 }
563 return -1; 577 return -1;
564 } 578 }
565 } 579 }
566 580
581 class _Es6LinkedIdentityHashMap<K, V>
582 extends _LinkedIdentityHashMap<K, V> implements InternalMap {
583 final _map;
584 int _modifications = 0;
585
586 _Es6LinkedIdentityHashMap() : _map = JS('var', 'new Map()');
587
588 int get length => JS('int', '#.size', _map);
589 bool get isEmpty => length == 0;
590 bool get isNotEmpty => !isEmpty;
591
592 Iterable<K> get keys => new _Es6MapIterable<K>(this, true);
593
594 Iterable<V> get values =>
595 new _Es6MapIterable<V>(this, false);
596
597 bool containsKey(Object key) {
598 return JS('bool', '#.has(#)', _map, key);
599 }
600
601 bool containsValue(Object value) {
602 return values.any((each) => each == value);
603 }
604
605 void addAll(Map<K, V> other) {
606 other.forEach((K key, V value) {
607 this[key] = value;
608 });
609 }
610
611 V operator[](Object key) {
612 return JS('var', '#.get(#)', _map, key);
613 }
614
615 void operator[]=(K key, V value) {
616 JS('var', '#.set(#, #)', _map, key, value);
617 _modified();
618 }
619
620 V putIfAbsent(K key, V ifAbsent()) {
621 if (containsKey(key)) return this[key];
622 V value = ifAbsent();
623 this[key] = value;
624 return value;
625 }
626
627 V remove(Object key) {
628 V value = this[key];
629 JS('bool', '#.delete(#)', _map, key);
630 _modified();
631 return value;
632 }
633
634 void clear() {
635 JS('void', '#.clear()', _map);
636 _modified();
637 }
638
639 void forEach(void action(K key, V value)) {
640 var jsEntries = JS('var', '#.entries()', _map);
641 int modifications = _modifications;
642 while (true) {
643 var next = JS('var', '#.next()', jsEntries);
644 bool done = JS('bool', '#.done', next);
645 if (done) break;
646 var entry = JS('var', '#.value', next);
647 var key = JS('var', '#[0]', entry);
648 var value = JS('var', '#[1]', entry);
649 action(key, value);
650 if (modifications != _modifications) {
651 throw new ConcurrentModificationError(this);
652 }
653 }
654 }
655
656 void _modified() {
657 // Value cycles after 2^30 modifications so that modification counts are
658 // always unboxed (Smi) values. Modification detection will be missed if you
659 // make exactly some multiple of 2^30 modifications between advances of an
660 // iterator.
661 _modifications = (_modifications + 1) & 0x3ffffff;
662 }
663
664 String toString() => Maps.mapToString(this);
665 }
666
667 class _Es6MapIterable<E> extends Iterable<E>
668 implements EfficientLength {
669 final _map;
670 final bool _isKeys;
671
672 _Es6MapIterable(this._map, this._isKeys);
673
674 int get length => _map.length;
675 bool get isEmpty => _map.isEmpty;
676
677 Iterator<E> get iterator =>
678 new _Es6MapIterator<E>(_map, _map._modifications, _isKeys);
679
680 bool contains(Object element) => _map.containsKey(element);
681
682 void forEach(void f(E element)) {
683 var jsIterator;
684 if (_isKeys) {
685 jsIterator = JS('var', '#.keys()', _map._map);
686 } else {
687 jsIterator = JS('var', '#.values()', _map._map);
688 }
689 int modifications = _map._modifications;
690 while (true) {
691 var next = JS('var', '#.next()', jsIterator);
692 bool done = JS('bool', '#.done', next);
693 if (done) break;
694 var value = JS('var', '#.value', next);
695 f(value);
696 if (modifications != _map._modifications) {
697 throw new ConcurrentModificationError(_map);
698 }
699 }
700 }
701 }
702
703 class _Es6MapIterator<E> implements Iterator<E> {
704 final _map;
705 final int _modifications;
706 final bool _isKeys;
707 var _jsIterator;
708 var _next;
709 E _current;
710 bool _done;
711
712 _Es6MapIterator(this._map, this._modifications, this._isKeys) {
713 if (_isKeys) {
714 _jsIterator = JS('var', '#.keys()', _map._map);
715 } else {
716 _jsIterator = JS('var', '#.values()', _map._map);
717 }
718 _done = false;
719 }
720
721 E get current => _current;
722
723 bool moveNext() {
724 if (_modifications != _map._modifications) {
725 throw new ConcurrentModificationError(_map);
726 }
727 if (_done) return false;
728 _next = JS('var', '#.next()', _jsIterator);
729 bool done = JS('bool', '#.done', _next);
730 if (done) {
731 _current = null;
732 _done = true;
733 return false;
734 } else {
735 _current = JS('var', '#.value', _next);
736 return true;
737 }
738 }
739 }
740
567 // TODO(floitsch): use ES6 maps when available. 741 // TODO(floitsch): use ES6 maps when available.
568 class _LinkedCustomHashMap<K, V> extends JsLinkedHashMap<K, V> { 742 class _LinkedCustomHashMap<K, V> extends JsLinkedHashMap<K, V> {
569 final _Equality<K> _equals; 743 final _Equality<K> _equals;
570 final _Hasher<K> _hashCode; 744 final _Hasher<K> _hashCode;
571 final _Predicate _validKey; 745 final _Predicate _validKey;
572 746
573 _LinkedCustomHashMap(this._equals, this._hashCode, 747 _LinkedCustomHashMap(this._equals, this._hashCode,
574 bool validKey(potentialKey)) 748 bool validKey(potentialKey))
575 : _validKey = (validKey != null) ? validKey : ((v) => v is K); 749 : _validKey = (validKey != null) ? validKey : ((v) => v is K);
576 750
(...skipping 897 matching lines...) Expand 10 before | Expand all | Expand 10 after
1474 } else if (_cell == null) { 1648 } else if (_cell == null) {
1475 _current = null; 1649 _current = null;
1476 return false; 1650 return false;
1477 } else { 1651 } else {
1478 _current = _cell._element; 1652 _current = _cell._element;
1479 _cell = _cell._next; 1653 _cell = _cell._next;
1480 return true; 1654 return true;
1481 } 1655 }
1482 } 1656 }
1483 } 1657 }
OLDNEW
« 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