Chromium Code Reviews| 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 // 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, NoThrows, patch; | 8 fillLiteralMap, InternalMap, NoInline, NoThrows, patch, JsLinkedHashMap, |
| 9 LinkedHashMapCell, LinkedHashMapKeyIterable, LinkedHashMapKeyIterator; | |
| 9 | 10 |
| 10 @patch | 11 @patch |
| 11 class HashMap<K, V> { | 12 class HashMap<K, V> { |
| 12 @patch | 13 @patch |
| 13 factory HashMap({ bool equals(K key1, K key2), | 14 factory HashMap({ bool equals(K key1, K key2), |
| 14 int hashCode(K key), | 15 int hashCode(K key), |
| 15 bool isValidKey(potentialKey) }) { | 16 bool isValidKey(potentialKey) }) { |
| 16 if (isValidKey == null) { | 17 if (isValidKey == null) { |
| 17 if (hashCode == null) { | 18 if (hashCode == null) { |
| 18 if (equals == null) { | 19 if (equals == null) { |
| (...skipping 465 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 484 | 485 |
| 485 @patch | 486 @patch |
| 486 class LinkedHashMap<K, V> { | 487 class LinkedHashMap<K, V> { |
| 487 @patch | 488 @patch |
| 488 factory LinkedHashMap({ bool equals(K key1, K key2), | 489 factory LinkedHashMap({ bool equals(K key1, K key2), |
| 489 int hashCode(K key), | 490 int hashCode(K key), |
| 490 bool isValidKey(potentialKey) }) { | 491 bool isValidKey(potentialKey) }) { |
| 491 if (isValidKey == null) { | 492 if (isValidKey == null) { |
| 492 if (hashCode == null) { | 493 if (hashCode == null) { |
| 493 if (equals == null) { | 494 if (equals == null) { |
| 494 return new _LinkedHashMap<K, V>(); | 495 return new JsLinkedHashMap<K, V>(); |
| 495 } | 496 } |
| 496 hashCode = _defaultHashCode; | 497 hashCode = _defaultHashCode; |
| 497 } else { | 498 } else { |
| 498 if (identical(identityHashCode, hashCode) && | 499 if (identical(identityHashCode, hashCode) && |
| 499 identical(identical, equals)) { | 500 identical(identical, equals)) { |
| 500 return new _LinkedIdentityHashMap<K, V>(); | 501 return new _LinkedIdentityHashMap<K, V>(); |
| 501 } | 502 } |
| 502 if (equals == null) { | 503 if (equals == null) { |
| 503 equals = _defaultEquals; | 504 equals = _defaultEquals; |
| 504 } | 505 } |
| 505 } | 506 } |
| 506 } else { | 507 } else { |
| 507 if (hashCode == null) { | 508 if (hashCode == null) { |
| 508 hashCode = _defaultHashCode; | 509 hashCode = _defaultHashCode; |
| 509 } | 510 } |
| 510 if (equals == null) { | 511 if (equals == null) { |
| 511 equals = _defaultEquals; | 512 equals = _defaultEquals; |
| 512 } | 513 } |
| 513 } | 514 } |
| 514 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); | 515 return new _LinkedCustomHashMap<K, V>(equals, hashCode, isValidKey); |
| 515 } | 516 } |
| 516 | 517 |
| 517 @patch | 518 @patch |
| 518 factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>; | 519 factory LinkedHashMap.identity() = _LinkedIdentityHashMap<K, V>; |
| 519 | 520 |
| 520 // Private factory constructor called by generated code for map literals. | 521 // Private factory constructor called by generated code for map literals. |
| 521 @NoInline() | 522 @NoInline() |
| 522 factory LinkedHashMap._literal(List keyValuePairs) { | 523 factory LinkedHashMap._literal(List keyValuePairs) { |
| 523 return fillLiteralMap(keyValuePairs, new _LinkedHashMap<K, V>()); | 524 return fillLiteralMap(keyValuePairs, new JsLinkedHashMap<K, V>()); |
| 524 } | 525 } |
| 525 | 526 |
| 526 // Private factory constructor called by generated code for map literals. | 527 // Private factory constructor called by generated code for map literals. |
| 527 @NoThrows() @NoInline() | 528 @NoThrows() @NoInline() |
| 528 factory LinkedHashMap._empty() { | 529 factory LinkedHashMap._empty() { |
| 529 return new _LinkedHashMap<K, V>(); | 530 return new JsLinkedHashMap<K, V>(); |
| 530 } | 531 } |
| 531 } | 532 } |
| 532 | 533 |
| 533 class _LinkedHashMap<K, V> implements LinkedHashMap<K, V>, InternalMap { | 534 class _LinkedIdentityHashMap<K, V> extends JsLinkedHashMap<K, V> { |
| 534 int _length = 0; | 535 int internalComputeHashCode(var key) { |
| 535 | |
| 536 // The hash map contents are divided into three parts: one part for | |
| 537 // string keys, one for numeric keys, and one for the rest. String | |
| 538 // and numeric keys map directly to their linked cells, but the rest | |
| 539 // of the entries are stored in bucket lists of the form: | |
| 540 // | |
| 541 // [cell-0, cell-1, ...] | |
| 542 // | |
| 543 // where all keys in the same bucket share the same hash code. | |
| 544 var _strings; | |
| 545 var _nums; | |
| 546 var _rest; | |
| 547 | |
| 548 // The keys and values are stored in cells that are linked together | |
| 549 // to form a double linked list. | |
| 550 LinkedHashMapCell _first; | |
| 551 LinkedHashMapCell _last; | |
| 552 | |
| 553 // We track the number of modifications done to the key set of the | |
| 554 // hash map to be able to throw when the map is modified while being | |
| 555 // iterated over. | |
| 556 int _modifications = 0; | |
| 557 | |
| 558 _LinkedHashMap(); | |
| 559 | |
| 560 | |
| 561 int get length => _length; | |
| 562 bool get isEmpty => _length == 0; | |
| 563 bool get isNotEmpty => !isEmpty; | |
| 564 | |
| 565 Iterable<K> get keys { | |
| 566 return new LinkedHashMapKeyIterable<K>(this); | |
| 567 } | |
| 568 | |
| 569 Iterable<V> get values { | |
| 570 return new MappedIterable<K, V>(keys, (each) => this[each]); | |
| 571 } | |
| 572 | |
| 573 bool containsKey(Object key) { | |
| 574 if (_isStringKey(key)) { | |
| 575 var strings = _strings; | |
| 576 if (strings == null) return false; | |
| 577 LinkedHashMapCell cell = _getTableEntry(strings, key); | |
| 578 return cell != null; | |
| 579 } else if (_isNumericKey(key)) { | |
| 580 var nums = _nums; | |
| 581 if (nums == null) return false; | |
| 582 LinkedHashMapCell cell = _getTableEntry(nums, key); | |
| 583 return cell != null; | |
| 584 } else { | |
| 585 return _containsKey(key); | |
| 586 } | |
| 587 } | |
| 588 | |
| 589 bool _containsKey(Object key) { | |
| 590 var rest = _rest; | |
| 591 if (rest == null) return false; | |
| 592 var bucket = _getBucket(rest, key); | |
| 593 return _findBucketIndex(bucket, key) >= 0; | |
| 594 } | |
| 595 | |
| 596 bool containsValue(Object value) { | |
| 597 return keys.any((each) => this[each] == value); | |
| 598 } | |
| 599 | |
| 600 void addAll(Map<K, V> other) { | |
| 601 other.forEach((K key, V value) { | |
| 602 this[key] = value; | |
| 603 }); | |
| 604 } | |
| 605 | |
| 606 V operator[](Object key) { | |
| 607 if (_isStringKey(key)) { | |
| 608 var strings = _strings; | |
| 609 if (strings == null) return null; | |
| 610 LinkedHashMapCell cell = _getTableEntry(strings, key); | |
| 611 return (cell == null) ? null : cell._value; | |
| 612 } else if (_isNumericKey(key)) { | |
| 613 var nums = _nums; | |
| 614 if (nums == null) return null; | |
| 615 LinkedHashMapCell cell = _getTableEntry(nums, key); | |
| 616 return (cell == null) ? null : cell._value; | |
| 617 } else { | |
| 618 return _get(key); | |
| 619 } | |
| 620 } | |
| 621 | |
| 622 V _get(Object key) { | |
| 623 var rest = _rest; | |
| 624 if (rest == null) return null; | |
| 625 var bucket = _getBucket(rest, key); | |
| 626 int index = _findBucketIndex(bucket, key); | |
| 627 if (index < 0) return null; | |
| 628 LinkedHashMapCell cell = JS('var', '#[#]', bucket, index); | |
| 629 return cell._value; | |
| 630 } | |
| 631 | |
| 632 void operator[]=(K key, V value) { | |
| 633 if (_isStringKey(key)) { | |
| 634 var strings = _strings; | |
| 635 if (strings == null) _strings = strings = _newHashTable(); | |
| 636 _addHashTableEntry(strings, key, value); | |
| 637 } else if (_isNumericKey(key)) { | |
| 638 var nums = _nums; | |
| 639 if (nums == null) _nums = nums = _newHashTable(); | |
| 640 _addHashTableEntry(nums, key, value); | |
| 641 } else { | |
| 642 _set(key, value); | |
| 643 } | |
| 644 } | |
| 645 | |
| 646 void _set(K key, V value) { | |
| 647 var rest = _rest; | |
| 648 if (rest == null) _rest = rest = _newHashTable(); | |
| 649 var hash = _computeHashCode(key); | |
| 650 var bucket = JS('var', '#[#]', rest, hash); | |
| 651 if (bucket == null) { | |
| 652 LinkedHashMapCell cell = _newLinkedCell(key, value); | |
| 653 _setTableEntry(rest, hash, JS('var', '[#]', cell)); | |
| 654 } else { | |
| 655 int index = _findBucketIndex(bucket, key); | |
| 656 if (index >= 0) { | |
| 657 LinkedHashMapCell cell = JS('var', '#[#]', bucket, index); | |
| 658 cell._value = value; | |
| 659 } else { | |
| 660 LinkedHashMapCell cell = _newLinkedCell(key, value); | |
| 661 JS('void', '#.push(#)', bucket, cell); | |
| 662 } | |
| 663 } | |
| 664 } | |
| 665 | |
| 666 V putIfAbsent(K key, V ifAbsent()) { | |
| 667 if (containsKey(key)) return this[key]; | |
| 668 V value = ifAbsent(); | |
| 669 this[key] = value; | |
| 670 return value; | |
| 671 } | |
| 672 | |
| 673 V remove(Object key) { | |
| 674 if (_isStringKey(key)) { | |
| 675 return _removeHashTableEntry(_strings, key); | |
| 676 } else if (_isNumericKey(key)) { | |
| 677 return _removeHashTableEntry(_nums, key); | |
| 678 } else { | |
| 679 return _remove(key); | |
| 680 } | |
| 681 } | |
| 682 | |
| 683 V _remove(Object key) { | |
| 684 var rest = _rest; | |
| 685 if (rest == null) return null; | |
| 686 var bucket = _getBucket(rest, key); | |
| 687 int index = _findBucketIndex(bucket, key); | |
| 688 if (index < 0) return null; | |
| 689 // Use splice to remove the [cell] element at the index and | |
| 690 // unlink the cell before returning its value. | |
| 691 LinkedHashMapCell cell = JS('var', '#.splice(#, 1)[0]', bucket, index); | |
| 692 _unlinkCell(cell); | |
| 693 // TODO(kasperl): Consider getting rid of the bucket list when | |
| 694 // the length reaches zero. | |
| 695 return cell._value; | |
| 696 } | |
| 697 | |
| 698 void clear() { | |
| 699 if (_length > 0) { | |
| 700 _strings = _nums = _rest = _first = _last = null; | |
| 701 _length = 0; | |
| 702 _modified(); | |
| 703 } | |
| 704 } | |
| 705 | |
| 706 void forEach(void action(K key, V value)) { | |
| 707 LinkedHashMapCell cell = _first; | |
| 708 int modifications = _modifications; | |
| 709 while (cell != null) { | |
| 710 action(cell._key, cell._value); | |
| 711 if (modifications != _modifications) { | |
| 712 throw new ConcurrentModificationError(this); | |
| 713 } | |
| 714 cell = cell._next; | |
| 715 } | |
| 716 } | |
| 717 | |
| 718 void _addHashTableEntry(var table, K key, V value) { | |
| 719 LinkedHashMapCell cell = _getTableEntry(table, key); | |
| 720 if (cell == null) { | |
| 721 _setTableEntry(table, key, _newLinkedCell(key, value)); | |
| 722 } else { | |
| 723 cell._value = value; | |
| 724 } | |
| 725 } | |
| 726 | |
| 727 V _removeHashTableEntry(var table, Object key) { | |
| 728 if (table == null) return null; | |
| 729 LinkedHashMapCell cell = _getTableEntry(table, key); | |
| 730 if (cell == null) return null; | |
| 731 _unlinkCell(cell); | |
| 732 _deleteTableEntry(table, key); | |
| 733 return cell._value; | |
| 734 } | |
| 735 | |
| 736 void _modified() { | |
| 737 // Value cycles after 2^30 modifications. If you keep hold of an | |
| 738 // iterator for that long, you might miss a modification | |
| 739 // detection, and iteration can go sour. Don't do that. | |
| 740 _modifications = (_modifications + 1) & 0x3ffffff; | |
| 741 } | |
| 742 | |
| 743 // Create a new cell and link it in as the last one in the list. | |
| 744 LinkedHashMapCell _newLinkedCell(K key, V value) { | |
| 745 LinkedHashMapCell cell = new LinkedHashMapCell(key, value); | |
| 746 if (_first == null) { | |
| 747 _first = _last = cell; | |
| 748 } else { | |
| 749 LinkedHashMapCell last = _last; | |
| 750 cell._previous = last; | |
| 751 _last = last._next = cell; | |
| 752 } | |
| 753 _length++; | |
| 754 _modified(); | |
| 755 return cell; | |
| 756 } | |
| 757 | |
| 758 // Unlink the given cell from the linked list of cells. | |
| 759 void _unlinkCell(LinkedHashMapCell cell) { | |
| 760 LinkedHashMapCell previous = cell._previous; | |
| 761 LinkedHashMapCell next = cell._next; | |
| 762 if (previous == null) { | |
| 763 assert(cell == _first); | |
| 764 _first = next; | |
| 765 } else { | |
| 766 previous._next = next; | |
| 767 } | |
| 768 if (next == null) { | |
| 769 assert(cell == _last); | |
| 770 _last = previous; | |
| 771 } else { | |
| 772 next._previous = previous; | |
| 773 } | |
| 774 _length--; | |
| 775 _modified(); | |
| 776 } | |
| 777 | |
| 778 static bool _isStringKey(var key) { | |
| 779 return key is String && key != '__proto__'; | |
| 780 } | |
| 781 | |
| 782 static bool _isNumericKey(var key) { | |
| 783 // Only treat unsigned 30-bit integers as numeric keys. This way, | |
| 784 // we avoid converting them to strings when we use them as keys in | |
| 785 // the JavaScript hash table object. | |
| 786 return key is num && JS('bool', '(# & 0x3ffffff) === #', key, key); | |
| 787 } | |
| 788 | |
| 789 int _computeHashCode(var key) { | |
| 790 // We force the hash codes to be unsigned 30-bit integers to avoid | |
| 791 // issues with problematic keys like '__proto__'. Another option | |
| 792 // would be to throw an exception if the hash code isn't a number. | |
| 793 return JS('int', '# & 0x3ffffff', key.hashCode); | |
| 794 } | |
| 795 | |
| 796 static _getTableEntry(var table, var key) { | |
| 797 return JS('var', '#[#]', table, key); | |
| 798 } | |
| 799 | |
| 800 static void _setTableEntry(var table, var key, var value) { | |
| 801 assert(value != null); | |
| 802 JS('void', '#[#] = #', table, key, value); | |
| 803 } | |
| 804 | |
| 805 static void _deleteTableEntry(var table, var key) { | |
| 806 JS('void', 'delete #[#]', table, key); | |
| 807 } | |
| 808 | |
| 809 List _getBucket(var table, var key) { | |
| 810 var hash = _computeHashCode(key); | |
| 811 return JS('var', '#[#]', table, hash); | |
| 812 } | |
| 813 | |
| 814 int _findBucketIndex(var bucket, var key) { | |
| 815 if (bucket == null) return -1; | |
| 816 int length = JS('int', '#.length', bucket); | |
| 817 for (int i = 0; i < length; i++) { | |
| 818 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i); | |
| 819 if (cell._key == key) return i; | |
| 820 } | |
| 821 return -1; | |
| 822 } | |
| 823 | |
| 824 static _newHashTable() { | |
| 825 // Create a new JavaScript object to be used as a hash table. Use | |
| 826 // Object.create to avoid the properties on Object.prototype | |
| 827 // showing up as entries. | |
| 828 var table = JS('var', 'Object.create(null)'); | |
| 829 // Attempt to force the hash table into 'dictionary' mode by | |
| 830 // adding a property to it and deleting it again. | |
| 831 var temporaryKey = '<non-identifier-key>'; | |
| 832 _setTableEntry(table, temporaryKey, table); | |
| 833 _deleteTableEntry(table, temporaryKey); | |
| 834 return table; | |
| 835 } | |
| 836 | |
| 837 String toString() => Maps.mapToString(this); | |
| 838 } | |
| 839 | |
| 840 class _LinkedIdentityHashMap<K, V> extends _LinkedHashMap<K, V> { | |
| 841 int _computeHashCode(var key) { | |
| 842 // We force the hash codes to be unsigned 30-bit integers to avoid | 536 // We force the hash codes to be unsigned 30-bit integers to avoid |
| 843 // issues with problematic keys like '__proto__'. Another option | 537 // issues with problematic keys like '__proto__'. Another option |
| 844 // would be to throw an exception if the hash code isn't a number. | 538 // would be to throw an exception if the hash code isn't a number. |
| 845 return JS('int', '# & 0x3ffffff', identityHashCode(key)); | 539 return JS('int', '# & 0x3ffffff', identityHashCode(key)); |
| 846 } | 540 } |
| 847 | 541 |
| 848 int _findBucketIndex(var bucket, var key) { | 542 int internalFindBucketIndex(var bucket, var key) { |
|
sra1
2015/05/15 22:59:33
Can this be rewritten to avoid public names that a
Johnni Winther
2015/05/18 07:11:30
If not, maybe we should make named of injected mem
| |
| 849 if (bucket == null) return -1; | 543 if (bucket == null) return -1; |
| 850 int length = JS('int', '#.length', bucket); | 544 int length = JS('int', '#.length', bucket); |
| 851 for (int i = 0; i < length; i++) { | 545 for (int i = 0; i < length; i++) { |
| 852 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i); | 546 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i); |
| 853 if (identical(cell._key, key)) return i; | 547 if (identical(cell.key, key)) return i; |
| 854 } | 548 } |
| 855 return -1; | 549 return -1; |
| 856 } | 550 } |
| 857 } | 551 } |
| 858 | 552 |
| 859 class _LinkedCustomHashMap<K, V> extends _LinkedHashMap<K, V> { | 553 class _LinkedCustomHashMap<K, V> extends JsLinkedHashMap<K, V> { |
| 860 final _Equality<K> _equals; | 554 final _Equality<K> _equals; |
| 861 final _Hasher<K> _hashCode; | 555 final _Hasher<K> _hashCode; |
| 862 final _Predicate _validKey; | 556 final _Predicate _validKey; |
| 863 _LinkedCustomHashMap(this._equals, this._hashCode, | 557 _LinkedCustomHashMap(this._equals, this._hashCode, |
| 864 bool validKey(potentialKey)) | 558 bool validKey(potentialKey)) |
| 865 : _validKey = (validKey != null) ? validKey : ((v) => v is K); | 559 : _validKey = (validKey != null) ? validKey : ((v) => v is K); |
| 866 | 560 |
| 867 V operator[](Object key) { | 561 V operator[](Object key) { |
| 868 if (!_validKey(key)) return null; | 562 if (!_validKey(key)) return null; |
| 869 return super._get(key); | 563 return super.internalGet(key); |
| 870 } | 564 } |
| 871 | 565 |
| 872 void operator[]=(K key, V value) { | 566 void operator[]=(K key, V value) { |
| 873 super._set(key, value); | 567 super.internalSet(key, value); |
| 874 } | 568 } |
| 875 | 569 |
| 876 bool containsKey(Object key) { | 570 bool containsKey(Object key) { |
| 877 if (!_validKey(key)) return false; | 571 if (!_validKey(key)) return false; |
| 878 return super._containsKey(key); | 572 return super.internalContainsKey(key); |
| 879 } | 573 } |
| 880 | 574 |
| 881 V remove(Object key) { | 575 V remove(Object key) { |
| 882 if (!_validKey(key)) return null; | 576 if (!_validKey(key)) return null; |
| 883 return super._remove(key); | 577 return super.internalRemove(key); |
| 884 } | 578 } |
| 885 | 579 |
| 886 int _computeHashCode(var key) { | 580 int internalComputeHashCode(var key) { |
| 887 // We force the hash codes to be unsigned 30-bit integers to avoid | 581 // We force the hash codes to be unsigned 30-bit integers to avoid |
| 888 // issues with problematic keys like '__proto__'. Another option | 582 // issues with problematic keys like '__proto__'. Another option |
| 889 // would be to throw an exception if the hash code isn't a number. | 583 // would be to throw an exception if the hash code isn't a number. |
| 890 return JS('int', '# & 0x3ffffff', _hashCode(key)); | 584 return JS('int', '# & 0x3ffffff', _hashCode(key)); |
| 891 } | 585 } |
| 892 | 586 |
| 893 int _findBucketIndex(var bucket, var key) { | 587 int internalFindBucketIndex(var bucket, var key) { |
| 894 if (bucket == null) return -1; | 588 if (bucket == null) return -1; |
| 895 int length = JS('int', '#.length', bucket); | 589 int length = JS('int', '#.length', bucket); |
| 896 for (int i = 0; i < length; i++) { | 590 for (int i = 0; i < length; i++) { |
| 897 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i); | 591 LinkedHashMapCell cell = JS('var', '#[#]', bucket, i); |
| 898 if (_equals(cell._key, key)) return i; | 592 if (_equals(cell.key, key)) return i; |
| 899 } | 593 } |
| 900 return -1; | 594 return -1; |
| 901 } | 595 } |
| 902 } | 596 } |
| 903 | 597 |
| 904 class LinkedHashMapCell { | |
| 905 final _key; | |
| 906 var _value; | |
| 907 | |
| 908 LinkedHashMapCell _next; | |
| 909 LinkedHashMapCell _previous; | |
| 910 | |
| 911 LinkedHashMapCell(this._key, this._value); | |
| 912 } | |
| 913 | |
| 914 class LinkedHashMapKeyIterable<E> extends IterableBase<E> | |
| 915 implements EfficientLength { | |
| 916 final _map; | |
| 917 LinkedHashMapKeyIterable(this._map); | |
| 918 | |
| 919 int get length => _map._length; | |
| 920 bool get isEmpty => _map._length == 0; | |
| 921 | |
| 922 Iterator<E> get iterator { | |
| 923 return new LinkedHashMapKeyIterator<E>(_map, _map._modifications); | |
| 924 } | |
| 925 | |
| 926 bool contains(Object element) { | |
| 927 return _map.containsKey(element); | |
| 928 } | |
| 929 | |
| 930 void forEach(void f(E element)) { | |
| 931 LinkedHashMapCell cell = _map._first; | |
| 932 int modifications = _map._modifications; | |
| 933 while (cell != null) { | |
| 934 f(cell._key); | |
| 935 if (modifications != _map._modifications) { | |
| 936 throw new ConcurrentModificationError(_map); | |
| 937 } | |
| 938 cell = cell._next; | |
| 939 } | |
| 940 } | |
| 941 } | |
| 942 | |
| 943 class LinkedHashMapKeyIterator<E> implements Iterator<E> { | |
| 944 final _map; | |
| 945 final int _modifications; | |
| 946 LinkedHashMapCell _cell; | |
| 947 E _current; | |
| 948 | |
| 949 LinkedHashMapKeyIterator(this._map, this._modifications) { | |
| 950 _cell = _map._first; | |
| 951 } | |
| 952 | |
| 953 E get current => _current; | |
| 954 | |
| 955 bool moveNext() { | |
| 956 if (_modifications != _map._modifications) { | |
| 957 throw new ConcurrentModificationError(_map); | |
| 958 } else if (_cell == null) { | |
| 959 _current = null; | |
| 960 return false; | |
| 961 } else { | |
| 962 _current = _cell._key; | |
| 963 _cell = _cell._next; | |
| 964 return true; | |
| 965 } | |
| 966 } | |
| 967 } | |
| 968 | |
| 969 @patch | 598 @patch |
| 970 class HashSet<E> { | 599 class HashSet<E> { |
| 971 @patch | 600 @patch |
| 972 factory HashSet({ bool equals(E e1, E e2), | 601 factory HashSet({ bool equals(E e1, E e2), |
| 973 int hashCode(E e), | 602 int hashCode(E e), |
| 974 bool isValidKey(potentialKey) }) { | 603 bool isValidKey(potentialKey) }) { |
| 975 if (isValidKey == null) { | 604 if (isValidKey == null) { |
| 976 if (hashCode == null) { | 605 if (hashCode == null) { |
| 977 if (equals == null) { | 606 if (equals == null) { |
| 978 return new _HashSet<E>(); | 607 return new _HashSet<E>(); |
| (...skipping 850 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1829 } else if (_cell == null) { | 1458 } else if (_cell == null) { |
| 1830 _current = null; | 1459 _current = null; |
| 1831 return false; | 1460 return false; |
| 1832 } else { | 1461 } else { |
| 1833 _current = _cell._element; | 1462 _current = _cell._element; |
| 1834 _cell = _cell._next; | 1463 _cell = _cell._next; |
| 1835 return true; | 1464 return true; |
| 1836 } | 1465 } |
| 1837 } | 1466 } |
| 1838 } | 1467 } |
| OLD | NEW |