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

Unified Diff: sdk/lib/internal/cache.dart

Issue 420713008: Remove hard limit from mirrors accessor caches. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 5 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 side-by-side diff with in-line comments
Download patch
Index: sdk/lib/internal/cache.dart
diff --git a/sdk/lib/internal/cache.dart b/sdk/lib/internal/cache.dart
new file mode 100644
index 0000000000000000000000000000000000000000..8c98b4eaf4b70fa01e20a3bbd53f00ac7383e144
--- /dev/null
+++ b/sdk/lib/internal/cache.dart
@@ -0,0 +1,148 @@
+// Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+part of dart._internal;
+
+class CacheAssociation<K,V> {
Ivan Posva 2014/08/06 23:05:14 Why <K,V>?
+ K key;
+ V value;
+ bool usedSinceGrowth = false;
+}
+
+/**
+ * A map that will grow as associations are added but will prefer to evict
+ * associations that have not been used since the last growth when needing to
+ * grow again. Implemented as an open addressing hash table.
+ */
+class Cache<K,V> {
+ final CacheAssociation<K,V> _head;
+ List _table;
+ int _shift;
+ int _mask;
+ int _capacity; // Max number of associations before we start evicting.
+ int _size = 0; // Current number of associations.
+
+ /**
+ * Create a Cache whose capacity is 75% of 2^shift.
+ */
+ Cache.withInitialShift(int shift)
+ {
+ // The scheme used here for handling collisions relies on there always
+ // being at least one empty slot.
+ if (shift < 1) throw new Exception("Cache requires a shift >= 1");
+ _initWithShift(shift);
+ }
+
+ void _initWithShift(int shift) {
+ this._shift = shift;
+ this._mask = (1 << shift) - 1;
+ this._capacity = (1 << shift) * 3 ~/ 4;
+ this._table = new List(1 << shift);
+ assert(_table.length > _capacity);
+ }
+
+ int _scanFor(K key) {
+ var start = key.hashCode & _mask;
+ var index = start;
+ do {
+ var assoc = _table[index];
+ if (null == assoc || assoc.key == key) {
+ return index;
+ }
+ index = (index + 1) & _mask;
+ } while (index != start);
+ // Should never happen because we start evicting associations before the
+ // table is full.
+ throw new Exception("Internal error: LRUMap table full");
Ivan Posva 2014/08/06 23:05:14 LRUMap?
+ }
+
+ int _scanForEmpty(K key) {
+ var start = key.hashCode & _mask;
+ var index = start;
+ do {
+ if (null == _table[index]) {
+ return index;
+ }
+ index = (index + 1) & _mask;
+ } while (index != start);
+ // Should never happen because we start evicting associations before the
+ // table is full.
+ throw new Exception("Internal error: LRUMap table full");
Ivan Posva 2014/08/06 23:05:14 ditto
+ }
+
+ void _fixCollisionsAfter(start) {
+ var assoc;
+ var index = (start + 1) & _mask;
+ while (null != (assoc = _table[index])) {
Ivan Posva 2014/08/06 23:05:14 Assignment in condition?
rmacnak 2014/08/07 20:05:25 Yes, Dart doesn't have sequence expressions to wri
+ var newIndex = _scanFor(assoc.key);
+ if (newIndex != index) {
+ assert(_table[newIndex] == null);
+ _table[newIndex] = assoc;
+ _table[index] = null;
+ }
+ index = (index + 1) & _mask;
+ }
+ }
+
+ void _grow() {
+ var oldTable = _table;
+
+ _initWithShift(_shift + 1);
+
+ for (int oldIndex = 0; oldIndex < oldTable.length; oldIndex++) {
+ var assoc = oldTable[oldIndex];
+ if (assoc != null) {
+ var newIndex = _scanForEmpty(assoc.key);
+ assoc.usedSinceGrowth = false;
+ _table[newIndex] = assoc;
+ }
+ }
+ }
+
+ void _tryToShrinkOtherwiseGrow() {
+ bool needToGrow = true;
+ for (int i = 0; i < _table.length; i++) {
+ var assoc = _table[i];
+ if (null != assoc && !assoc.usedSinceGrowth) {
+ _table[i] = null;
+ _size--;
+ _fixCollisionsAfter(i);
+ needToGrow = false;
+ }
+ }
+ if (needToGrow) _grow();
+ }
+
+ operator []=(K key, V value) {
+ int index = _scanFor(key);
+ var assoc = _table[index];
+ if (null != assoc) {
+ // Existing key, replace value.
+ assert(assoc.key == key);
+ assoc.value = value;
+ assoc.usedSinceGrowth = true;
+ } else {
+ // New key.
+ var newAssoc = new CacheAssociation();
+ if (_size == _capacity) {
+ // No free slots.
+ _tryToShrinkOtherwiseGrow();
+ index = _scanFor(key);
Ivan Posva 2014/08/06 23:05:14 assert(table[index] == null);
+ }
+ newAssoc.key = key;
+ newAssoc.value = value;
+ newAssoc.usedSinceGrowth = true;
+ _table[index] = newAssoc;
+ _size++;
+ }
Ivan Posva 2014/08/06 23:05:14 What is missing here is the deletion of an entry i
rmacnak 2014/08/07 20:05:25 This doesn't occur in practice, but added the logi
+ }
+
+ V operator [](K key) {
+ var index = _scanFor(key);
+ var assoc = _table[index];
+ if (null == assoc) return null;
+ assoc.usedSinceGrowth = true;
+ return assoc.value;
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698