lru_cache.h

Go to the documentation of this file.
00001 /*
00002  * See the dyninst/COPYRIGHT file for copyright information.
00003  * 
00004  * We provide the Paradyn Tools (below described as "Paradyn")
00005  * on an AS IS basis, and do not warrant its validity or performance.
00006  * We reserve the right to update, modify, or discontinue this
00007  * software at any time.  We shall have no obligation to supply such
00008  * updates or modifications or any other form of support to you.
00009  * 
00010  * By your use of Paradyn, you understand and agree that we (or any
00011  * other person or entity with proprietary rights in Paradyn) are
00012  * under no obligation to provide either maintenance services,
00013  * update services, notices of latent defects, or correction of
00014  * defects for Paradyn.
00015  * 
00016  * This library is free software; you can redistribute it and/or
00017  * modify it under the terms of the GNU Lesser General Public
00018  * License as published by the Free Software Foundation; either
00019  * version 2.1 of the License, or (at your option) any later version.
00020  * 
00021  * This library is distributed in the hope that it will be useful,
00022  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00023  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00024  * Lesser General Public License for more details.
00025  * 
00026  * You should have received a copy of the GNU Lesser General Public
00027  * License along with this library; if not, write to the Free Software
00028  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
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    //Using vectors for storage so that we can have tight
00050    // control over the memory used.  We don't want unnecessary
00051    // dynamic allocation, as this may be used under a signal handler.
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       //Clear out tombstone values for faster searches
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       //Disconnect from current place
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       //Move to front
00143       list_elems[index].prev = lru_undefined;
00144       list_elems[index].next = head;
00145       list_elems[head].prev = index;
00146 
00147       //Update head and tail
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       //Leave some empty space for better hash performance
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          //We have to delete an old item.
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
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated on 12 Jul 2013 for SymtabAPI by  doxygen 1.6.1