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

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

Powered by Google App Engine
This is Rietveld 408576698