lru_cache.h
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031 #include <vector>
00032 #include <assert.h>
00033 #include "dyntypes.h"
00034
00035 #if !defined LRUCache_h_
00036 #define LRUCache_h_
00037
00038 template<class K, class V>
00039 class LRUCache {
00040 public:
00041 typedef int (*lru_hash_func)(K key);
00042 private:
00043 struct LRUCacheElement {
00044 int next;
00045 int prev;
00046 K key;
00047 V value;
00048 };
00049
00050
00051
00052 std::vector<LRUCacheElement> list_elems;
00053 std::vector<int> map_elems;
00054 int next_free;
00055 int max_size;
00056 int max_hash_size;
00057 int head;
00058 int tail;
00059 lru_hash_func hash_func;
00060
00061 int bar;
00062 static const int lru_undefined = -1;
00063 static const int lru_tombstone = -2;
00064
00065 private:
00066 void hash_reorg()
00067 {
00068 assert(next_free == max_size);
00069
00070 for (int i=0; i<max_hash_size; i++) {
00071 map_elems[i] = lru_undefined;
00072 }
00073 int cur = head;
00074 while (cur != lru_undefined) {
00075 hash_insert(list_elems[cur].key, cur);
00076 cur = list_elems[cur].next;
00077 }
00078 }
00079
00080 int hash_find(K key)
00081 {
00082 int index = ((unsigned) hash_func(key)) % max_hash_size;
00083 int start = index;
00084 for (;;) {
00085 if (map_elems[index] == lru_undefined) {
00086 return lru_undefined;
00087 }
00088 if (map_elems[index] != lru_tombstone) {
00089 int elem = map_elems[index];
00090 if (list_elems[elem].key == key)
00091 return index;
00092 }
00093 if (++index == max_hash_size)
00094 index = 0;
00095 if (start == index) {
00096 hash_reorg();
00097 }
00098 }
00099 }
00100
00101 void hash_insert(K key, int val)
00102 {
00103 int index = ((unsigned) hash_func(key)) % max_hash_size;
00104 int start = index;
00105 for (;;) {
00106 if ((map_elems[index] == lru_undefined) ||
00107 (map_elems[index] == lru_tombstone))
00108 {
00109 map_elems[index] = val;
00110 return;
00111 }
00112 if (++index == max_hash_size)
00113 index = 0;
00114 assert(start != index);
00115 }
00116 }
00117
00118 void hash_remove(K key)
00119 {
00120 int index = hash_find(key);
00121 assert(index != lru_undefined);
00122 map_elems[index] = lru_tombstone;
00123 }
00124
00125 void list_move_to_front(int index)
00126 {
00127 assert(head != lru_undefined);
00128 assert(tail != lru_undefined);
00129 assert(index < max_size);
00130
00131 if (index == head)
00132 return;
00133
00134 int prev_elem = list_elems[index].prev;
00135 int next_elem = list_elems[index].next;
00136
00137 if (prev_elem != lru_undefined)
00138 list_elems[prev_elem].next = next_elem;
00139 if (next_elem != lru_undefined)
00140 list_elems[next_elem].prev = prev_elem;
00141
00142
00143 list_elems[index].prev = lru_undefined;
00144 list_elems[index].next = head;
00145 list_elems[head].prev = index;
00146
00147
00148 head = index;
00149 if (tail == index && prev_elem != lru_undefined)
00150 tail = prev_elem;
00151 }
00152
00153 int list_delete_last() {
00154 assert(head != lru_undefined);
00155 assert(tail != lru_undefined);
00156 assert(next_free == max_size);
00157
00158 int elem_to_delete = tail;
00159 int prev_elem = list_elems[elem_to_delete].prev;
00160 if (prev_elem != lru_undefined)
00161 list_elems[prev_elem].next = lru_undefined;
00162 tail = prev_elem;
00163
00164 return elem_to_delete;
00165 }
00166
00167 void list_insert_new(int pos) {
00168 if (head == lru_undefined) {
00169 assert(tail == lru_undefined);
00170 head = pos;
00171 tail = pos;
00172 list_elems[pos].next = lru_undefined;
00173 list_elems[pos].prev = lru_undefined;
00174 return;
00175 }
00176
00177 list_elems[pos].prev = lru_undefined;
00178 list_elems[pos].next = head;
00179 list_elems[head].prev = pos;
00180 head = pos;
00181 }
00182
00183 void list_set_keyval(int pos, K key, V value) {
00184 list_elems[pos].key = key;
00185 list_elems[pos].value = value;
00186 }
00187
00188 K get_key(int index) {
00189 return list_elems[index].key;
00190 }
00191
00192 V get_value(int index) {
00193 return list_elems[index].value;
00194 }
00195
00196 public:
00197 LRUCache(int initial_size, lru_hash_func f) :
00198 next_free(0),
00199 max_size(initial_size),
00200 head(lru_undefined),
00201 tail(lru_undefined),
00202 hash_func(f)
00203 {
00204 list_elems.reserve(max_size);
00205
00206 max_hash_size = (int) (max_size * 1.5);
00207 map_elems.reserve(max_hash_size);
00208 map_elems.resize(max_hash_size);
00209 for (int i=0; i<max_hash_size; i++) {
00210 map_elems[i] = lru_undefined;
00211 }
00212 }
00213
00214 void insert(K key, V value)
00215 {
00216 int result = hash_find(key);
00217 if (result != lru_undefined) {
00218 int list_elem = map_elems[result];
00219 list_set_keyval(list_elem, key, value);
00220 list_move_to_front(list_elem);
00221 }
00222
00223 int elem_to_insert;
00224 if (next_free < max_size)
00225 elem_to_insert = next_free++;
00226 else {
00227
00228 int lru_item = list_delete_last();
00229 assert(lru_item != lru_undefined);
00230 hash_remove(get_key(lru_item));
00231 elem_to_insert = lru_item;
00232 }
00233
00234 list_insert_new(elem_to_insert);
00235 list_set_keyval(elem_to_insert, key, value);
00236 hash_insert(key, elem_to_insert);
00237 }
00238
00239 bool lookup(K key, V &value)
00240 {
00241 int result = hash_find(key);
00242 if (result == lru_undefined) {
00243 return false;
00244 }
00245 int list_elem = map_elems[result];
00246
00247 list_move_to_front(list_elem);
00248 value = get_value(list_elem);
00249 return true;
00250 }
00251 };
00252
00253 #endif