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

Side by Side Diff: runtime/lib/compact_hash.dart

Issue 1151523002: VM-internalize the default Map implementation. (Closed) Base URL: https://github.com/dart-lang/sdk.git@master
Patch Set: Ready for review. Created 5 years, 7 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
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, 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 import 'dart:typed_data'; 5 import 'dart:typed_data';
6 import 'dart:_internal' as internal; 6 import 'dart:_internal' as internal;
7 7
8 // Hash table with open addressing that separates the index from keys/values. 8 // Hash table with open addressing that separates the index from keys/values.
9 // This mixin can be applied to _HashFieldBase or _HashVMBase (for
10 // normal and VM-internalized classes, respectivley), which provide the
11 // actual fields/accessors that this mixin assumes.
12 // TODO(koda): Consider moving field comments to _HashFieldBase.
9 abstract class _HashBase { 13 abstract class _HashBase {
10 // Each occupied entry in _index is a fixed-size integer that encodes a pair: 14 // Each occupied entry in _index is a fixed-size integer that encodes a pair:
11 // [ hash pattern for key | index of entry in _data ] 15 // [ hash pattern for key | index of entry in _data ]
12 // The hash pattern is based on hashCode, but is guaranteed to be non-zero. 16 // The hash pattern is based on hashCode, but is guaranteed to be non-zero.
13 // The length of _index is always a power of two, and there is always at 17 // The length of _index is always a power of two, and there is always at
14 // least one unoccupied entry. 18 // least one unoccupied entry.
15 Uint32List _index; 19 /* _index */
16 20
17 // The number of bits used for each component is determined by table size. 21 // The number of bits used for each component is determined by table size.
18 // The length of _index is twice the number of entries in _data, and both 22 // The length of _index is twice the number of entries in _data, and both
19 // are doubled when _data is full. Thus, _index will have a max load factor 23 // are doubled when _data is full. Thus, _index will have a max load factor
20 // of 1/2, which enables one more bit to be used for the hash. 24 // of 1/2, which enables one more bit to be used for the hash.
21 // TODO(koda): Consider growing _data by factor sqrt(2), twice as often. 25 // TODO(koda): Consider growing _data by factor sqrt(2), twice as often.
22 static const int _INITIAL_INDEX_BITS = 3; 26 static const int _INITIAL_INDEX_BITS = 3;
23 static const int _INITIAL_INDEX_SIZE = 1 << (_INITIAL_INDEX_BITS + 1); 27 static const int _INITIAL_INDEX_SIZE = 1 << (_INITIAL_INDEX_BITS + 1);
24 28
25 // Unused and deleted entries are marked by 0 and 1, respectively. 29 // Unused and deleted entries are marked by 0 and 1, respectively.
26 static const int _UNUSED_PAIR = 0; 30 static const int _UNUSED_PAIR = 0;
27 static const int _DELETED_PAIR = 1; 31 static const int _DELETED_PAIR = 1;
28 32
29 // Cached in-place mask for the hash pattern component. On 32-bit, the top 33 // Cached in-place mask for the hash pattern component. On 32-bit, the top
30 // bits are wasted to avoid Mint allocation. 34 // bits are wasted to avoid Mint allocation.
31 // TODO(koda): Reclaim the bits by making the compiler treat hash patterns 35 // TODO(koda): Reclaim the bits by making the compiler treat hash patterns
32 // as unsigned words. 36 // as unsigned words.
33 int _hashMask = internal.is64Bit ? 37 /* _hashMask */
34 (1 << (32 - _INITIAL_INDEX_BITS)) - 1 :
35 (1 << (30 - _INITIAL_INDEX_BITS)) - 1;
36 38
37 static int _hashPattern(int fullHash, int hashMask, int size) { 39 static int _hashPattern(int fullHash, int hashMask, int size) {
38 final int maskedHash = fullHash & hashMask; 40 final int maskedHash = fullHash & hashMask;
39 // TODO(koda): Consider keeping bit length and use left shift. 41 // TODO(koda): Consider keeping bit length and use left shift.
40 return (maskedHash == 0) ? (size >> 1) : maskedHash * (size >> 1); 42 return (maskedHash == 0) ? (size >> 1) : maskedHash * (size >> 1);
41 } 43 }
42 44
43 // Linear probing. 45 // Linear probing.
44 static int _firstProbe(int fullHash, int sizeMask) { 46 static int _firstProbe(int fullHash, int sizeMask) {
45 final int i = fullHash & sizeMask; 47 final int i = fullHash & sizeMask;
46 // Light, fast shuffle to mitigate bad hashCode (e.g., sequential). 48 // Light, fast shuffle to mitigate bad hashCode (e.g., sequential).
47 return ((i << 1) + i) & sizeMask; 49 return ((i << 1) + i) & sizeMask;
48 } 50 }
49 static int _nextProbe(int i, int sizeMask) => (i + 1) & sizeMask; 51 static int _nextProbe(int i, int sizeMask) => (i + 1) & sizeMask;
52
53 // Fixed-length list of keys (set) or key/value at even/odd indices (map).
54 /* _data */
50 55
51 // Fixed-length list of keys (set) or key/value at even/odd indices (map).
52 List _data;
53 // Length of _data that is used (i.e., keys + values for a map). 56 // Length of _data that is used (i.e., keys + values for a map).
54 int _usedData = 0; 57 /* _usedData */
58
55 // Number of deleted keys. 59 // Number of deleted keys.
56 int _deletedKeys = 0; 60 /* _deletedKeys */
57 61
58 // A self-loop is used to mark a deleted key or value. 62 // A self-loop is used to mark a deleted key or value.
59 static bool _isDeleted(List data, Object keyOrValue) => 63 static bool _isDeleted(List data, Object keyOrValue) =>
60 identical(keyOrValue, data); 64 identical(keyOrValue, data);
61 static void _setDeletedAt(List data, int d) { 65 static void _setDeletedAt(List data, int d) {
62 data[d] = data; 66 data[d] = data;
63 } 67 }
64 68
65 // Concurrent modification detection relies on this checksum monotonically 69 // Concurrent modification detection relies on this checksum monotonically
66 // increasing between reallocations of _data. 70 // increasing between reallocations of _data.
67 int get _checkSum => _usedData + _deletedKeys; 71 int get _checkSum => _usedData + _deletedKeys;
68 bool _isModifiedSince(List oldData, int oldCheckSum) => 72 bool _isModifiedSince(List oldData, int oldCheckSum) =>
69 !identical(_data, oldData) || (_checkSum != oldCheckSum); 73 !identical(_data, oldData) || (_checkSum != oldCheckSum);
70 } 74 }
siva 2015/05/22 16:27:11 I think leaving the fields in here commented out i
koda 2015/05/26 12:22:04 Done.
71 75
76 abstract class _HashFieldBase {
77 Uint32List _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE);
78 int _hashMask = internal.is64Bit ?
79 (1 << (32 - _HashBase._INITIAL_INDEX_BITS)) - 1 :
80 (1 << (30 - _HashBase._INITIAL_INDEX_BITS)) - 1;
81 List _data = new List(_HashBase._INITIAL_INDEX_SIZE);
82 int _usedData = 0;
83 int _deletedKeys = 0;
84 }
85
86 // Base class for VM-internal classes; keep in sync with _HashFieldBase.
87 abstract class _HashVMBase {
88 Uint32List get _index native "LinkedHashMap_getIndex";
89 void set _index(Uint32List value) native "LinkedHashMap_setIndex";
90
91 int get _hashMask native "LinkedHashMap_getHashMask";
92 void set _hashMask(int value) native "LinkedHashMap_setHashMask";
93
94 List get _data native "LinkedHashMap_getData";
95 void set _data(List value) native "LinkedHashMap_setData";
96
97 int get _usedData native "LinkedHashMap_getUsedData";
98 void set _usedData(int value) native "LinkedHashMap_setUsedData";
99
100 int get _deletedKeys native "LinkedHashMap_getDeletedKeys";
101 void set _deletedKeys(int value) native "LinkedHashMap_setDeletedKeys";
102 }
103
72 class _OperatorEqualsAndHashCode { 104 class _OperatorEqualsAndHashCode {
73 int _hashCode(e) => e.hashCode; 105 int _hashCode(e) => e.hashCode;
74 bool _equals(e1, e2) => e1 == e2; 106 bool _equals(e1, e2) => e1 == e2;
75 } 107 }
76 108
77 class _IdenticalAndIdentityHashCode { 109 class _IdenticalAndIdentityHashCode {
78 int _hashCode(e) => identityHashCode(e); 110 int _hashCode(e) => identityHashCode(e);
79 bool _equals(e1, e2) => identical(e1, e2); 111 bool _equals(e1, e2) => identical(e1, e2);
80 } 112 }
81 113
82 // Map with iteration in insertion order (hence "Linked"). New keys are simply 114 // VM-internalized implementation of a default-constructed LinkedHashMap.
83 // appended to _data. 115 class _InternalLinkedHashMap<K, V> extends _HashVMBase
84 class _CompactLinkedHashMap<K, V> 116 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase,
85 extends MapBase<K, V> with _HashBase, _OperatorEqualsAndHashCode 117 _OperatorEqualsAndHashCode
86 implements LinkedHashMap<K, V> { 118 implements LinkedHashMap<K, V> {
119 factory _InternalLinkedHashMap() native "LinkedHashMap_allocate";
120 }
87 121
88 _CompactLinkedHashMap() { 122 class _LinkedHashMapMixin<K, V> {
89 assert(_HashBase._UNUSED_PAIR == 0);
90 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE);
91 _data = new List(_HashBase._INITIAL_INDEX_SIZE);
92 }
93
94 int get length => (_usedData >> 1) - _deletedKeys; 123 int get length => (_usedData >> 1) - _deletedKeys;
95 bool get isEmpty => length == 0; 124 bool get isEmpty => length == 0;
96 bool get isNotEmpty => !isEmpty; 125 bool get isNotEmpty => !isEmpty;
97 126
98 void _rehash() { 127 void _rehash() {
99 if ((_deletedKeys << 2) > _usedData) { 128 if ((_deletedKeys << 2) > _usedData) {
100 // TODO(koda): Consider shrinking. 129 // TODO(koda): Consider shrinking.
101 // TODO(koda): Consider in-place compaction and more costly CME check. 130 // TODO(koda): Consider in-place compaction and more costly CME check.
102 _init(_index.length, _hashMask, _data, _usedData); 131 _init(_index.length, _hashMask, _data, _usedData);
103 } else { 132 } else {
104 // TODO(koda): Support 32->64 bit transition (and adjust _hashMask). 133 // TODO(koda): Support 32->64 bit transition (and adjust _hashMask).
105 _init(_index.length << 1, _hashMask >> 1, _data, _usedData); 134 _init(_index.length << 1, _hashMask >> 1, _data, _usedData);
106 } 135 }
107 } 136 }
108 137
109 void clear() { 138 void clear() {
110 if (!isEmpty) { 139 if (!isEmpty) {
111 _init(_index.length, _hashMask); 140 _init(_index.length, _hashMask);
112 } 141 }
113 } 142 }
114 143
115 // Allocate new _index and _data, and optionally copy existing contents. 144 // Allocate new _index and _data, and optionally copy existing contents.
116 void _init(int size, int hashMask, [List oldData, int oldUsed]) { 145 void _init(int size, int hashMask, [List oldData, int oldUsed]) {
117 assert(size & (size - 1) == 0); 146 assert(size & (size - 1) == 0);
118 assert(_HashBase._UNUSED_PAIR == 0); 147 assert(_HashBase._UNUSED_PAIR == 0);
119 _index = new Uint32List(size); 148 _index = new Uint32List(size);
120 _hashMask = hashMask; 149 _hashMask = hashMask;
121 _data = new List(size); 150 _data = new List(size);
122 _usedData = 0; 151 _usedData = 0;
123 _deletedKeys = 0; 152 _deletedKeys = 0;
124 if (oldData != null) { 153 if (oldData != null) {
125 for (int i = 0; i < oldUsed; i += 2) { 154 for (int i = 0; i < oldUsed; i += 2) {
126 var key = oldData[i]; 155 var key = oldData[i];
127 if (!_HashBase._isDeleted(oldData, key)) { 156 if (!_HashBase._isDeleted(oldData, key)) {
128 // TODO(koda): While there are enough hash bits, avoid hashCode calls. 157 // TODO(koda): While there are enough hash bits, avoid hashCode calls.
129 this[key] = oldData[i + 1]; 158 this[key] = oldData[i + 1];
130 } 159 }
131 } 160 }
132 } 161 }
133 } 162 }
134 163
135 void _insert(K key, V value, int hashPattern, int i) { 164 void _insert(K key, V value, int hashPattern, int i) {
136 if (_usedData == _data.length) { 165 if (_usedData == _data.length) {
137 _rehash(); 166 _rehash();
138 this[key] = value; 167 this[key] = value;
139 } else { 168 } else {
140 assert(1 <= hashPattern && hashPattern < (1 << 32)); 169 assert(1 <= hashPattern && hashPattern < (1 << 32));
141 final int index = _usedData >> 1; 170 final int index = _usedData >> 1;
142 assert((index & hashPattern) == 0); 171 assert((index & hashPattern) == 0);
143 _index[i] = hashPattern | index; 172 _index[i] = hashPattern | index;
144 _data[_usedData++] = key; 173 _data[_usedData++] = key;
145 _data[_usedData++] = value; 174 _data[_usedData++] = value;
146 } 175 }
147 } 176 }
148 177
149 // If key is present, returns the index of the value in _data, else returns 178 // If key is present, returns the index of the value in _data, else returns
150 // the negated insertion point in _index. 179 // the negated insertion point in _index.
151 int _findValueOrInsertPoint(K key, int fullHash, int hashPattern, int size) { 180 int _findValueOrInsertPoint(K key, int fullHash, int hashPattern, int size) {
152 final int sizeMask = size - 1; 181 final int sizeMask = size - 1;
153 final int maxEntries = size >> 1; 182 final int maxEntries = size >> 1;
154 int i = _HashBase._firstProbe(fullHash, sizeMask); 183 int i = _HashBase._firstProbe(fullHash, sizeMask);
155 int firstDeleted = -1; 184 int firstDeleted = -1;
156 int pair = _index[i]; 185 int pair = _index[i];
157 while (pair != _HashBase._UNUSED_PAIR) { 186 while (pair != _HashBase._UNUSED_PAIR) {
158 if (pair == _HashBase._DELETED_PAIR) { 187 if (pair == _HashBase._DELETED_PAIR) {
159 if (firstDeleted < 0){ 188 if (firstDeleted < 0){
160 firstDeleted = i; 189 firstDeleted = i;
161 } 190 }
162 } else { 191 } else {
163 final int entry = hashPattern ^ pair; 192 final int entry = hashPattern ^ pair;
164 if (entry < maxEntries) { 193 if (entry < maxEntries) {
165 final int d = entry << 1; 194 final int d = entry << 1;
166 if (_equals(key, _data[d])) { 195 if (_equals(key, _data[d])) {
167 return d + 1; 196 return d + 1;
168 } 197 }
169 } 198 }
170 } 199 }
171 i = _HashBase._nextProbe(i, sizeMask); 200 i = _HashBase._nextProbe(i, sizeMask);
172 pair = _index[i]; 201 pair = _index[i];
173 } 202 }
174 return firstDeleted >= 0 ? -firstDeleted : -i; 203 return firstDeleted >= 0 ? -firstDeleted : -i;
175 } 204 }
176 205
177 void operator[]=(K key, V value) { 206 void operator[]=(K key, V value) {
178 final int size = _index.length; 207 final int size = _index.length;
179 final int sizeMask = size - 1; 208 final int sizeMask = size - 1;
180 final int fullHash = _hashCode(key); 209 final int fullHash = _hashCode(key);
181 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); 210 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size);
182 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); 211 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size);
183 if (d > 0) { 212 if (d > 0) {
184 _data[d] = value; 213 _data[d] = value;
185 } else { 214 } else {
186 final int i = -d; 215 final int i = -d;
187 _insert(key, value, hashPattern, i); 216 _insert(key, value, hashPattern, i);
188 } 217 }
189 } 218 }
190 219
191 V putIfAbsent(K key, V ifAbsent()) { 220 V putIfAbsent(K key, V ifAbsent()) {
192 final int size = _index.length; 221 final int size = _index.length;
193 final int sizeMask = size - 1; 222 final int sizeMask = size - 1;
194 final int maxEntries = size >> 1; 223 final int maxEntries = size >> 1;
195 final int fullHash = _hashCode(key); 224 final int fullHash = _hashCode(key);
196 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); 225 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size);
197 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size); 226 final int d = _findValueOrInsertPoint(key, fullHash, hashPattern, size);
198 if (d > 0) { 227 if (d > 0) {
199 return _data[d]; 228 return _data[d];
200 } 229 }
201 // 'ifAbsent' is allowed to modify the map. 230 // 'ifAbsent' is allowed to modify the map.
202 List oldData = _data; 231 List oldData = _data;
203 int oldCheckSum = _checkSum; 232 int oldCheckSum = _checkSum;
204 V value = ifAbsent(); 233 V value = ifAbsent();
205 if (_isModifiedSince(oldData, oldCheckSum)) { 234 if (_isModifiedSince(oldData, oldCheckSum)) {
206 this[key] = value; 235 this[key] = value;
207 } else { 236 } else {
208 final int i = -d; 237 final int i = -d;
209 _insert(key, value, hashPattern, i); 238 _insert(key, value, hashPattern, i);
210 } 239 }
211 return value; 240 return value;
212 } 241 }
213 242
214 V remove(Object key) { 243 V remove(Object key) {
215 final int size = _index.length; 244 final int size = _index.length;
216 final int sizeMask = size - 1; 245 final int sizeMask = size - 1;
217 final int maxEntries = size >> 1; 246 final int maxEntries = size >> 1;
218 final int fullHash = _hashCode(key); 247 final int fullHash = _hashCode(key);
219 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); 248 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size);
220 int i = _HashBase._firstProbe(fullHash, sizeMask); 249 int i = _HashBase._firstProbe(fullHash, sizeMask);
221 int pair = _index[i]; 250 int pair = _index[i];
222 while (pair != _HashBase._UNUSED_PAIR) { 251 while (pair != _HashBase._UNUSED_PAIR) {
223 if (pair != _HashBase._DELETED_PAIR) { 252 if (pair != _HashBase._DELETED_PAIR) {
224 final int entry = hashPattern ^ pair; 253 final int entry = hashPattern ^ pair;
225 if (entry < maxEntries) { 254 if (entry < maxEntries) {
226 final int d = entry << 1; 255 final int d = entry << 1;
227 if (_equals(key, _data[d])) { 256 if (_equals(key, _data[d])) {
228 _index[i] = _HashBase._DELETED_PAIR; 257 _index[i] = _HashBase._DELETED_PAIR;
229 _HashBase._setDeletedAt(_data, d); 258 _HashBase._setDeletedAt(_data, d);
230 V value = _data[d + 1]; 259 V value = _data[d + 1];
231 _HashBase._setDeletedAt(_data, d + 1); 260 _HashBase._setDeletedAt(_data, d + 1);
232 ++_deletedKeys; 261 ++_deletedKeys;
233 return value; 262 return value;
234 } 263 }
235 } 264 }
236 } 265 }
237 i = _HashBase._nextProbe(i, sizeMask); 266 i = _HashBase._nextProbe(i, sizeMask);
238 pair = _index[i]; 267 pair = _index[i];
239 } 268 }
240 return null; 269 return null;
241 } 270 }
242 271
243 // If key is absent, return _data (which is never a value). 272 // If key is absent, return _data (which is never a value).
244 Object _getValueOrData(Object key) { 273 Object _getValueOrData(Object key) {
245 final int size = _index.length; 274 final int size = _index.length;
246 final int sizeMask = size - 1; 275 final int sizeMask = size - 1;
247 final int maxEntries = size >> 1; 276 final int maxEntries = size >> 1;
248 final int fullHash = _hashCode(key); 277 final int fullHash = _hashCode(key);
249 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size); 278 final int hashPattern = _HashBase._hashPattern(fullHash, _hashMask, size);
250 int i = _HashBase._firstProbe(fullHash, sizeMask); 279 int i = _HashBase._firstProbe(fullHash, sizeMask);
251 int pair = _index[i]; 280 int pair = _index[i];
252 while (pair != _HashBase._UNUSED_PAIR) { 281 while (pair != _HashBase._UNUSED_PAIR) {
253 if (pair != _HashBase._DELETED_PAIR) { 282 if (pair != _HashBase._DELETED_PAIR) {
254 final int entry = hashPattern ^ pair; 283 final int entry = hashPattern ^ pair;
255 if (entry < maxEntries) { 284 if (entry < maxEntries) {
256 final int d = entry << 1; 285 final int d = entry << 1;
257 if (_equals(key, _data[d])) { 286 if (_equals(key, _data[d])) {
258 return _data[d + 1]; 287 return _data[d + 1];
259 } 288 }
260 } 289 }
261 } 290 }
262 i = _HashBase._nextProbe(i, sizeMask); 291 i = _HashBase._nextProbe(i, sizeMask);
263 pair = _index[i]; 292 pair = _index[i];
264 } 293 }
265 return _data; 294 return _data;
266 } 295 }
267 296
268 bool containsKey(Object key) => !identical(_data, _getValueOrData(key)); 297 bool containsKey(Object key) => !identical(_data, _getValueOrData(key));
269 298
270 V operator[](Object key) { 299 V operator[](Object key) {
271 var v = _getValueOrData(key); 300 var v = _getValueOrData(key);
272 return identical(_data, v) ? null : v; 301 return identical(_data, v) ? null : v;
273 } 302 }
274 303
275 bool containsValue(Object value) { 304 bool containsValue(Object value) {
276 for (var v in values) { 305 for (var v in values) {
277 // Spec. says this should always use "==", also for identity maps, etc. 306 // Spec. says this should always use "==", also for identity maps, etc.
278 if (v == value) { 307 if (v == value) {
279 return true; 308 return true;
280 } 309 }
281 } 310 }
282 return false; 311 return false;
283 } 312 }
284 313
285 void forEach(void f(K key, V value)) { 314 void forEach(void f(K key, V value)) {
286 var ki = keys.iterator; 315 var ki = keys.iterator;
287 var vi = values.iterator; 316 var vi = values.iterator;
288 while (ki.moveNext()) { 317 while (ki.moveNext()) {
289 vi.moveNext(); 318 vi.moveNext();
290 f(ki.current, vi.current); 319 f(ki.current, vi.current);
291 } 320 }
292 } 321 }
293 322
294 Iterable<K> get keys => 323 Iterable<K> get keys =>
295 new _CompactIterable<K>(this, _data, _usedData, -2, 2); 324 new _CompactIterable<K>(this, _data, _usedData, -2, 2);
296 Iterable<V> get values => 325 Iterable<V> get values =>
297 new _CompactIterable<V>(this, _data, _usedData, -1, 2); 326 new _CompactIterable<V>(this, _data, _usedData, -1, 2);
298 } 327 }
299 328
300 class _CompactLinkedIdentityHashMap<K, V> 329 class _CompactLinkedIdentityHashMap<K, V> extends _HashFieldBase
301 extends _CompactLinkedHashMap<K, V> with _IdenticalAndIdentityHashCode { 330 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase,
331 _IdenticalAndIdentityHashCode
332 implements LinkedHashMap<K, V> {
302 } 333 }
303 334
304 class _CompactLinkedCustomHashMap<K, V> 335 class _CompactLinkedCustomHashMap<K, V> extends _HashFieldBase
305 extends _CompactLinkedHashMap<K, V> { 336 with MapMixin<K, V>, _LinkedHashMapMixin<K, V>, _HashBase
337 implements LinkedHashMap<K, V> {
306 final _equality; 338 final _equality;
307 final _hasher; 339 final _hasher;
308 final _validKey; 340 final _validKey;
309 341
310 // TODO(koda): Ask gbracha why I cannot have fields _equals/_hashCode. 342 // TODO(koda): Ask gbracha why I cannot have fields _equals/_hashCode.
311 int _hashCode(e) => _hasher(e); 343 int _hashCode(e) => _hasher(e);
312 bool _equals(e1, e2) => _equality(e1, e2); 344 bool _equals(e1, e2) => _equality(e1, e2);
313 345
314 bool containsKey(Object o) => _validKey(o) ? super.containsKey(o) : false; 346 bool containsKey(Object o) => _validKey(o) ? super.containsKey(o) : false;
315 V operator[](Object o) => _validKey(o) ? super[o] : null; 347 V operator[](Object o) => _validKey(o) ? super[o] : null;
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
362 current = _data[_offset]; 394 current = _data[_offset];
363 return true; 395 return true;
364 } else { 396 } else {
365 current = null; 397 current = null;
366 return false; 398 return false;
367 } 399 }
368 } 400 }
369 } 401 }
370 402
371 // Set implementation, analogous to _CompactLinkedHashMap. 403 // Set implementation, analogous to _CompactLinkedHashMap.
372 class _CompactLinkedHashSet<E> 404 class _CompactLinkedHashSet<E> extends _HashFieldBase
373 extends SetBase<E> with _HashBase, _OperatorEqualsAndHashCode 405 with _HashBase, _OperatorEqualsAndHashCode, SetMixin<E>
374 implements LinkedHashSet<E> { 406 implements LinkedHashSet<E> {
375 407
376 _CompactLinkedHashSet() { 408 _CompactLinkedHashSet() {
377 assert(_HashBase._UNUSED_PAIR == 0); 409 assert(_HashBase._UNUSED_PAIR == 0);
378 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE); 410 _index = new Uint32List(_HashBase._INITIAL_INDEX_SIZE);
379 _data = new List(_HashBase._INITIAL_INDEX_SIZE >> 1); 411 _data = new List(_HashBase._INITIAL_INDEX_SIZE >> 1);
380 } 412 }
381 413
382 int get length => _usedData - _deletedKeys; 414 int get length => _usedData - _deletedKeys;
383 415
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
527 E lookup(Object o) => _validKey(o) ? super.lookup(o) : null; 559 E lookup(Object o) => _validKey(o) ? super.lookup(o) : null;
528 bool remove(Object o) => _validKey(o) ? super.remove(o) : false; 560 bool remove(Object o) => _validKey(o) ? super.remove(o) : false;
529 561
530 _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey) 562 _CompactLinkedCustomHashSet(this._equality, this._hasher, validKey)
531 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test; 563 : _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test;
532 564
533 Set<E> toSet() => 565 Set<E> toSet() =>
534 new _CompactLinkedCustomHashSet<E>(_equality, _hasher, _validKey) 566 new _CompactLinkedCustomHashSet<E>(_equality, _hasher, _validKey)
535 ..addAll(this); 567 ..addAll(this);
536 } 568 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698