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

Side by Side 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, 4 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 | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file
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.
4
5 part of dart._internal;
6
7 class CacheAssociation<K,V> {
Ivan Posva 2014/08/06 23:05:14 Why <K,V>?
8 K key;
9 V value;
10 bool usedSinceGrowth = false;
11 }
12
13 /**
14 * A map that will grow as associations are added but will prefer to evict
15 * associations that have not been used since the last growth when needing to
16 * grow again. Implemented as an open addressing hash table.
17 */
18 class Cache<K,V> {
19 final CacheAssociation<K,V> _head;
20 List _table;
21 int _shift;
22 int _mask;
23 int _capacity; // Max number of associations before we start evicting.
24 int _size = 0; // Current number of associations.
25
26 /**
27 * Create a Cache whose capacity is 75% of 2^shift.
28 */
29 Cache.withInitialShift(int shift)
30 {
31 // The scheme used here for handling collisions relies on there always
32 // being at least one empty slot.
33 if (shift < 1) throw new Exception("Cache requires a shift >= 1");
34 _initWithShift(shift);
35 }
36
37 void _initWithShift(int shift) {
38 this._shift = shift;
39 this._mask = (1 << shift) - 1;
40 this._capacity = (1 << shift) * 3 ~/ 4;
41 this._table = new List(1 << shift);
42 assert(_table.length > _capacity);
43 }
44
45 int _scanFor(K key) {
46 var start = key.hashCode & _mask;
47 var index = start;
48 do {
49 var assoc = _table[index];
50 if (null == assoc || assoc.key == key) {
51 return index;
52 }
53 index = (index + 1) & _mask;
54 } while (index != start);
55 // Should never happen because we start evicting associations before the
56 // table is full.
57 throw new Exception("Internal error: LRUMap table full");
Ivan Posva 2014/08/06 23:05:14 LRUMap?
58 }
59
60 int _scanForEmpty(K key) {
61 var start = key.hashCode & _mask;
62 var index = start;
63 do {
64 if (null == _table[index]) {
65 return index;
66 }
67 index = (index + 1) & _mask;
68 } while (index != start);
69 // Should never happen because we start evicting associations before the
70 // table is full.
71 throw new Exception("Internal error: LRUMap table full");
Ivan Posva 2014/08/06 23:05:14 ditto
72 }
73
74 void _fixCollisionsAfter(start) {
75 var assoc;
76 var index = (start + 1) & _mask;
77 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
78 var newIndex = _scanFor(assoc.key);
79 if (newIndex != index) {
80 assert(_table[newIndex] == null);
81 _table[newIndex] = assoc;
82 _table[index] = null;
83 }
84 index = (index + 1) & _mask;
85 }
86 }
87
88 void _grow() {
89 var oldTable = _table;
90
91 _initWithShift(_shift + 1);
92
93 for (int oldIndex = 0; oldIndex < oldTable.length; oldIndex++) {
94 var assoc = oldTable[oldIndex];
95 if (assoc != null) {
96 var newIndex = _scanForEmpty(assoc.key);
97 assoc.usedSinceGrowth = false;
98 _table[newIndex] = assoc;
99 }
100 }
101 }
102
103 void _tryToShrinkOtherwiseGrow() {
104 bool needToGrow = true;
105 for (int i = 0; i < _table.length; i++) {
106 var assoc = _table[i];
107 if (null != assoc && !assoc.usedSinceGrowth) {
108 _table[i] = null;
109 _size--;
110 _fixCollisionsAfter(i);
111 needToGrow = false;
112 }
113 }
114 if (needToGrow) _grow();
115 }
116
117 operator []=(K key, V value) {
118 int index = _scanFor(key);
119 var assoc = _table[index];
120 if (null != assoc) {
121 // Existing key, replace value.
122 assert(assoc.key == key);
123 assoc.value = value;
124 assoc.usedSinceGrowth = true;
125 } else {
126 // New key.
127 var newAssoc = new CacheAssociation();
128 if (_size == _capacity) {
129 // No free slots.
130 _tryToShrinkOtherwiseGrow();
131 index = _scanFor(key);
Ivan Posva 2014/08/06 23:05:14 assert(table[index] == null);
132 }
133 newAssoc.key = key;
134 newAssoc.value = value;
135 newAssoc.usedSinceGrowth = true;
136 _table[index] = newAssoc;
137 _size++;
138 }
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
139 }
140
141 V operator [](K key) {
142 var index = _scanFor(key);
143 var assoc = _table[index];
144 if (null == assoc) return null;
145 assoc.usedSinceGrowth = true;
146 return assoc.value;
147 }
148 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698