| OLD | NEW |
| 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, 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 part of dart.core; | 5 part of dart.core; |
| 6 | 6 |
| 7 /** | 7 /** |
| 8 * A [Map] is an associative container, mapping a key to a value. | 8 * A [Map] is an associative container, mapping a key to a value. |
| 9 * Null values are supported, but null keys are not. | 9 * Null values are supported, but null keys are not. |
| 10 */ | 10 */ |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 62 * Removes all pairs from the map. | 62 * Removes all pairs from the map. |
| 63 */ | 63 */ |
| 64 void clear(); | 64 void clear(); |
| 65 | 65 |
| 66 /** | 66 /** |
| 67 * Applies [f] to each {key, value} pair of the map. | 67 * Applies [f] to each {key, value} pair of the map. |
| 68 */ | 68 */ |
| 69 void forEach(void f(K key, V value)); | 69 void forEach(void f(K key, V value)); |
| 70 | 70 |
| 71 /** | 71 /** |
| 72 * Returns a collection containing all the keys in the map. | 72 * The keys of [this]. |
| 73 */ | 73 */ |
| 74 Collection<K> get keys; | 74 // TODO(floitsch): this should return a [Set]. |
| 75 Iterable<K> get keys; |
| 75 | 76 |
| 76 /** | 77 /** |
| 77 * Returns a collection containing all the values in the map. | 78 * The values of [this]. |
| 78 */ | 79 */ |
| 79 Collection<V> get values; | 80 Iterable<V> get values; |
| 80 | 81 |
| 81 /** | 82 /** |
| 82 * The number of {key, value} pairs in the map. | 83 * The number of {key, value} pairs in the map. |
| 83 */ | 84 */ |
| 84 int get length; | 85 int get length; |
| 85 | 86 |
| 86 /** | 87 /** |
| 87 * Returns true if there is no {key, value} pair in the map. | 88 * Returns true if there is no {key, value} pair in the map. |
| 88 */ | 89 */ |
| 89 bool get isEmpty; | 90 bool get isEmpty; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 161 // The sentinel when a key is deleted from the map. | 162 // The sentinel when a key is deleted from the map. |
| 162 static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel(); | 163 static const _DeletedKeySentinel _DELETED_KEY = const _DeletedKeySentinel(); |
| 163 | 164 |
| 164 // The initial capacity of a hash map. | 165 // The initial capacity of a hash map. |
| 165 static const int _INITIAL_CAPACITY = 8; // must be power of 2 | 166 static const int _INITIAL_CAPACITY = 8; // must be power of 2 |
| 166 | 167 |
| 167 _HashMapImpl() { | 168 _HashMapImpl() { |
| 168 _numberOfEntries = 0; | 169 _numberOfEntries = 0; |
| 169 _numberOfDeleted = 0; | 170 _numberOfDeleted = 0; |
| 170 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); | 171 _loadLimit = _computeLoadLimit(_INITIAL_CAPACITY); |
| 171 _keys = new List(_INITIAL_CAPACITY); | 172 _keys = new List.fixedLength(_INITIAL_CAPACITY); |
| 172 _values = new List<V>(_INITIAL_CAPACITY); | 173 _values = new List<V>.fixedLength(_INITIAL_CAPACITY); |
| 173 } | 174 } |
| 174 | 175 |
| 175 factory _HashMapImpl.from(Map<K, V> other) { | 176 factory _HashMapImpl.from(Map<K, V> other) { |
| 176 Map<K, V> result = new _HashMapImpl<K, V>(); | 177 Map<K, V> result = new _HashMapImpl<K, V>(); |
| 177 other.forEach((K key, V value) { result[key] = value; }); | 178 other.forEach((K key, V value) { result[key] = value; }); |
| 178 return result; | 179 return result; |
| 179 } | 180 } |
| 180 | 181 |
| 181 static int _computeLoadLimit(int capacity) { | 182 static int _computeLoadLimit(int capacity) { |
| 182 return (capacity * 3) ~/ 4; | 183 return (capacity * 3) ~/ 4; |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 268 static bool _isPowerOfTwo(int x) { | 269 static bool _isPowerOfTwo(int x) { |
| 269 return ((x & (x - 1)) == 0); | 270 return ((x & (x - 1)) == 0); |
| 270 } | 271 } |
| 271 | 272 |
| 272 void _grow(int newCapacity) { | 273 void _grow(int newCapacity) { |
| 273 assert(_isPowerOfTwo(newCapacity)); | 274 assert(_isPowerOfTwo(newCapacity)); |
| 274 int capacity = _keys.length; | 275 int capacity = _keys.length; |
| 275 _loadLimit = _computeLoadLimit(newCapacity); | 276 _loadLimit = _computeLoadLimit(newCapacity); |
| 276 List oldKeys = _keys; | 277 List oldKeys = _keys; |
| 277 List<V> oldValues = _values; | 278 List<V> oldValues = _values; |
| 278 _keys = new List(newCapacity); | 279 _keys = new List.fixedLength(newCapacity); |
| 279 _values = new List<V>(newCapacity); | 280 _values = new List<V>.fixedLength(newCapacity); |
| 280 for (int i = 0; i < capacity; i++) { | 281 for (int i = 0; i < capacity; i++) { |
| 281 // [key] can be either of type [K] or [_DeletedKeySentinel]. | 282 // [key] can be either of type [K] or [_DeletedKeySentinel]. |
| 282 Object key = oldKeys[i]; | 283 Object key = oldKeys[i]; |
| 283 // If there is no key, we don't need to deal with the current slot. | 284 // If there is no key, we don't need to deal with the current slot. |
| 284 if (key == null || identical(key, _DELETED_KEY)) { | 285 if (key == null || identical(key, _DELETED_KEY)) { |
| 285 continue; | 286 continue; |
| 286 } | 287 } |
| 287 V value = oldValues[i]; | 288 V value = oldValues[i]; |
| 288 // Insert the {key, value} pair in their new slot. | 289 // Insert the {key, value} pair in their new slot. |
| 289 int newIndex = _probeForAdding(key); | 290 int newIndex = _probeForAdding(key); |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 344 | 345 |
| 345 bool get isEmpty { | 346 bool get isEmpty { |
| 346 return _numberOfEntries == 0; | 347 return _numberOfEntries == 0; |
| 347 } | 348 } |
| 348 | 349 |
| 349 int get length { | 350 int get length { |
| 350 return _numberOfEntries; | 351 return _numberOfEntries; |
| 351 } | 352 } |
| 352 | 353 |
| 353 void forEach(void f(K key, V value)) { | 354 void forEach(void f(K key, V value)) { |
| 354 int length = _keys.length; | 355 Iterator<int> it = new _HashMapImplIndexIterator(this); |
| 355 for (int i = 0; i < length; i++) { | 356 while (it.moveNext()) { |
| 356 var key = _keys[i]; | 357 f(_keys[it.current], _values[it.current]); |
| 357 if ((key != null) && (!identical(key, _DELETED_KEY))) { | |
| 358 f(key, _values[i]); | |
| 359 } | |
| 360 } | 358 } |
| 361 } | 359 } |
| 362 | 360 |
| 361 Iterable<K> get keys => new _HashMapImplKeyIterable<K>(this); |
| 363 | 362 |
| 364 Collection<K> get keys { | 363 Iterable<V> get values => new _HashMapImplValueIterable<V>(this); |
| 365 List<K> list = new List<K>(length); | |
| 366 int i = 0; | |
| 367 forEach((K key, V value) { | |
| 368 list[i++] = key; | |
| 369 }); | |
| 370 return list; | |
| 371 } | |
| 372 | |
| 373 Collection<V> get values { | |
| 374 List<V> list = new List<V>(length); | |
| 375 int i = 0; | |
| 376 forEach((K key, V value) { | |
| 377 list[i++] = value; | |
| 378 }); | |
| 379 return list; | |
| 380 } | |
| 381 | 364 |
| 382 bool containsKey(K key) { | 365 bool containsKey(K key) { |
| 383 return (_probeForLookup(key) != -1); | 366 return (_probeForLookup(key) != -1); |
| 384 } | 367 } |
| 385 | 368 |
| 386 bool containsValue(V value) { | 369 bool containsValue(V value) => values.contains(value); |
| 387 int length = _values.length; | |
| 388 for (int i = 0; i < length; i++) { | |
| 389 var key = _keys[i]; | |
| 390 if ((key != null) && (!identical(key, _DELETED_KEY))) { | |
| 391 if (_values[i] == value) return true; | |
| 392 } | |
| 393 } | |
| 394 return false; | |
| 395 } | |
| 396 | 370 |
| 397 String toString() { | 371 String toString() { |
| 398 return Maps.mapToString(this); | 372 return Maps.mapToString(this); |
| 399 } | 373 } |
| 400 } | 374 } |
| 401 | 375 |
| 376 class _HashMapImplKeyIterable<E> extends Iterable<E> { |
| 377 final _HashMapImpl _map; |
| 378 _HashMapImplKeyIterable(this._map); |
| 379 |
| 380 Iterator<E> get iterator => new _HashMapImplKeyIterator<E>(_map); |
| 381 } |
| 382 |
| 383 class _HashMapImplValueIterable<E> extends Iterable<E> { |
| 384 final _HashMapImpl _map; |
| 385 _HashMapImplValueIterable(this._map); |
| 386 |
| 387 Iterator<E> get iterator => new _HashMapImplValueIterator<E>(_map); |
| 388 } |
| 389 |
| 390 abstract class _HashMapImplIterator<E> implements Iterator<E> { |
| 391 final _HashMapImpl _map; |
| 392 int _index = -1; |
| 393 E _current; |
| 394 |
| 395 _HashMapImplIterator(this._map); |
| 396 |
| 397 E _computeCurrentFromIndex(int index, List keys, List values); |
| 398 |
| 399 bool moveNext() { |
| 400 int length = _map._keys.length; |
| 401 int newIndex = _index + 1; |
| 402 while (newIndex < length) { |
| 403 var key = _map._keys[newIndex]; |
| 404 if ((key != null) && (!identical(key, _HashMapImpl._DELETED_KEY))) { |
| 405 _current = _computeCurrentFromIndex(newIndex, _map._keys, _map._values); |
| 406 _index = newIndex; |
| 407 return true; |
| 408 } |
| 409 newIndex++; |
| 410 } |
| 411 _index = length; |
| 412 _current = null; |
| 413 return false; |
| 414 } |
| 415 |
| 416 E get current => _current; |
| 417 } |
| 418 |
| 419 class _HashMapImplKeyIterator<E> extends _HashMapImplIterator<E> { |
| 420 _HashMapImplKeyIterator(_HashMapImpl map) : super(map); |
| 421 |
| 422 E _computeCurrentFromIndex(int index, List keys, List values) { |
| 423 return keys[index]; |
| 424 } |
| 425 } |
| 426 |
| 427 class _HashMapImplValueIterator<E> extends _HashMapImplIterator<E> { |
| 428 _HashMapImplValueIterator(_HashMapImpl map) : super(map); |
| 429 |
| 430 E _computeCurrentFromIndex(int index, List keys, List values) { |
| 431 return values[index]; |
| 432 } |
| 433 } |
| 434 |
| 435 class _HashMapImplIndexIterator extends _HashMapImplIterator<int> { |
| 436 _HashMapImplIndexIterator(_HashMapImpl map) : super(map); |
| 437 |
| 438 int _computeCurrentFromIndex(int index, List keys, List values) { |
| 439 return index; |
| 440 } |
| 441 } |
| 402 | 442 |
| 403 /** | 443 /** |
| 404 * A singleton sentinel used to represent when a key is deleted from the map. | 444 * A singleton sentinel used to represent when a key is deleted from the map. |
| 405 * We can't use [: const Object() :] as a sentinel because it would end up | 445 * We can't use [: const Object() :] as a sentinel because it would end up |
| 406 * canonicalized and then we cannot distinguish the deleted key from the | 446 * canonicalized and then we cannot distinguish the deleted key from the |
| 407 * canonicalized [: Object() :]. | 447 * canonicalized [: Object() :]. |
| 408 */ | 448 */ |
| 409 class _DeletedKeySentinel { | 449 class _DeletedKeySentinel { |
| 410 const _DeletedKeySentinel(); | 450 const _DeletedKeySentinel(); |
| 411 } | 451 } |
| (...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 466 | 506 |
| 467 V putIfAbsent(K key, V ifAbsent()) { | 507 V putIfAbsent(K key, V ifAbsent()) { |
| 468 V value = this[key]; | 508 V value = this[key]; |
| 469 if ((this[key] == null) && !(containsKey(key))) { | 509 if ((this[key] == null) && !(containsKey(key))) { |
| 470 value = ifAbsent(); | 510 value = ifAbsent(); |
| 471 this[key] = value; | 511 this[key] = value; |
| 472 } | 512 } |
| 473 return value; | 513 return value; |
| 474 } | 514 } |
| 475 | 515 |
| 476 Collection<K> get keys { | 516 Iterable<K> get keys { |
| 477 List<K> list = new List<K>(length); | 517 return new MappedIterable<_KeyValuePair<K, V>, K>( |
| 478 int index = 0; | 518 _list, (_KeyValuePair<K, V> entry) => entry.key); |
| 479 _list.forEach((_KeyValuePair<K, V> entry) { | |
| 480 list[index++] = entry.key; | |
| 481 }); | |
| 482 assert(index == length); | |
| 483 return list; | |
| 484 } | 519 } |
| 485 | 520 |
| 486 | 521 |
| 487 Collection<V> get values { | 522 Iterable<V> get values { |
| 488 List<V> list = new List<V>(length); | 523 return new MappedIterable<_KeyValuePair<K, V>, V>( |
| 489 int index = 0; | 524 _list, (_KeyValuePair<K, V> entry) => entry.value); |
| 490 _list.forEach((_KeyValuePair<K, V> entry) { | |
| 491 list[index++] = entry.value; | |
| 492 }); | |
| 493 assert(index == length); | |
| 494 return list; | |
| 495 } | 525 } |
| 496 | 526 |
| 497 void forEach(void f(K key, V value)) { | 527 void forEach(void f(K key, V value)) { |
| 498 _list.forEach((_KeyValuePair<K, V> entry) { | 528 _list.forEach((_KeyValuePair<K, V> entry) { |
| 499 f(entry.key, entry.value); | 529 f(entry.key, entry.value); |
| 500 }); | 530 }); |
| 501 } | 531 } |
| 502 | 532 |
| 503 bool containsKey(K key) { | 533 bool containsKey(K key) { |
| 504 return _map.containsKey(key); | 534 return _map.containsKey(key); |
| 505 } | 535 } |
| 506 | 536 |
| 507 bool containsValue(V value) { | 537 bool containsValue(V value) { |
| 508 return _list.some((_KeyValuePair<K, V> entry) { | 538 return _list.any((_KeyValuePair<K, V> entry) { |
| 509 return (entry.value == value); | 539 return (entry.value == value); |
| 510 }); | 540 }); |
| 511 } | 541 } |
| 512 | 542 |
| 513 int get length { | 543 int get length { |
| 514 return _map.length; | 544 return _map.length; |
| 515 } | 545 } |
| 516 | 546 |
| 517 bool get isEmpty { | 547 bool get isEmpty { |
| 518 return length == 0; | 548 return length == 0; |
| 519 } | 549 } |
| 520 | 550 |
| 521 void clear() { | 551 void clear() { |
| 522 _map.clear(); | 552 _map.clear(); |
| 523 _list.clear(); | 553 _list.clear(); |
| 524 } | 554 } |
| 525 | 555 |
| 526 String toString() { | 556 String toString() { |
| 527 return Maps.mapToString(this); | 557 return Maps.mapToString(this); |
| 528 } | 558 } |
| 529 } | 559 } |
| 560 |
| OLD | NEW |