ARB
cache.h
Go to the documentation of this file.
1 // ================================================================ //
2 // //
3 // File : cache.h //
4 // Purpose : Cache for SmartPtrs //
5 // //
6 // Coded by Ralf Westram (coder@reallysoft.de) in November 2012 //
7 // Institute of Microbiology (Technical University Munich) //
8 // http://www.arb-home.de/ //
9 // //
10 // ================================================================ //
11 
12 #ifndef CACHE_H
13 #define CACHE_H
14 
15 #ifndef SMARTPTR_H
16 #include "smartptr.h"
17 #endif
18 #ifndef _GLIBCXX_LIST
19 #include <list>
20 #endif
21 
22 #if defined(DEBUG)
23 #define DUMP_CACHE_STAT
24 #endif
25 
26 #define ca_assert(cond) arb_assert(cond)
27 #define ca_assert_expensive(cond) // arb_assert(cond) // uncomment to enable expensive assertions
28 
29 // unittests for Cache are in ../SL/HEADERTESTS/cache.cxx@TEST_CachedPtr
30 
31 namespace cache {
32  template <typename SMARTPTR> class Cache;
33  template <typename SMARTPTR> class CacheHandle;
34 
35  template <typename SMARTPTR> class CacheEntry {
36  typedef CacheEntry<SMARTPTR>* EntryPtr;
37  typedef typename std::list< CacheEntry<SMARTPTR> >::iterator EntryIter;
38 
39  static EntryPtr& no_handle() {
40  static EntryPtr none = NULp;
41  return none;
42  }
43 
44  EntryPtr& my_handle;
45  SMARTPTR data;
46  EntryIter iter;
47 
48  CacheEntry(EntryPtr& handle)
49  : my_handle(handle)
50  {}
51  CacheEntry(EntryPtr& handle, SMARTPTR& init_data)
52  : my_handle(handle),
53  data(init_data)
54  {}
55  void setClientPtr() { my_handle = this; }
56  void clearClientPtr() { my_handle = NULp; }
57  void setData(SMARTPTR& new_data) { data = new_data; }
58 
59  EntryIter getIterator() {
60  ca_assert(data.isSet()); // otherwise iterator may be invalid
61  return iter;
62  }
63  void setIterator(EntryIter newIter) { iter = newIter; }
64 
65  friend class Cache<SMARTPTR>;
66 
67  public:
68  ~CacheEntry() { ca_assert(!my_handle); } // release before destruction
69  SMARTPTR get_data() const { return data; }
70  };
71 
72 
76  template <typename SMARTPTR> class Cache {
77  typedef CacheEntry<SMARTPTR> Entry;
78  typedef Entry* EntryPtr;
79  typedef std::list<Entry> Entries;
80 
81  typedef typename Entries::iterator EntryIter;
82 
83  Entries cached;
84 
85  size_t curr_size; // always == cached.size()
86  size_t max_size;
87 
88 #if defined(DUMP_CACHE_STAT)
89  size_t insert_count;
90  size_t access_count;
91 #endif
92 
93 #if defined(ASSERTION_USED)
94  bool curr_size_valid() const { return cached.size() == curr_size; }
95 #endif
96 
97  void keep(size_t kept_elems) {
98  ca_assert(kept_elems <= max_size);
99  size_t count = entries();
100  if (count>kept_elems) {
101  size_t toRemove = count-kept_elems;
102  EntryIter e = cached.begin();
103 
104  while (toRemove--) e++->clearClientPtr();
105  cached.erase(cached.begin(), e);
106  curr_size = kept_elems;
107  ca_assert_expensive(curr_size_valid());
108  ca_assert(entries() == kept_elems);
109  }
110  }
111 
112  EntryIter top() { return --cached.end(); }
113 
114 #if defined(ASSERTION_USED)
115  bool is_member(EntryIter iter) {
116  for (EntryIter i = cached.begin(); i != cached.end(); ++i) {
117  if (i == iter) return true;
118  }
119  return false;
120  }
121  static bool is_valid_size(size_t Size) { return Size>0; }
122 #endif
123 
124  void insert(EntryPtr& my_handle, SMARTPTR& data) {
125  ca_assert(data.isSet());
126  if (my_handle) { // re-assign
127  my_handle->setData(data);
128  touch(*my_handle);
129 #if defined(DUMP_CACHE_STAT)
130  --access_count; // do not count above touch as access
131 #endif
132  }
133  else { // initialization
134  cached.push_back(CacheEntry<SMARTPTR>(my_handle, data));
135  ++curr_size;
136  ca_assert_expensive(curr_size_valid());
137 
138  cached.back().setClientPtr();
139  ca_assert(&cached.back() == my_handle);
140 
141  my_handle->setIterator(top());
142 
143  keep(max_size);
144  ca_assert(my_handle);
145  }
146 #if defined(DUMP_CACHE_STAT)
147  ++insert_count;
148 #endif
149  }
150  void touch(Entry& entry) {
151  EntryIter iter = entry.getIterator();
152  ca_assert_expensive(is_member(iter));
153  if (iter != top()) { // not LRU entry
154  cached.splice(cached.end(), cached, iter);
155  ca_assert_expensive(is_member(iter));
156  ca_assert(iter == top());
157  }
158 #if defined(DUMP_CACHE_STAT)
159  ++access_count;
160 #endif
161  }
162  void remove(EntryPtr& my_handle) {
163  ca_assert(my_handle);
164  EntryIter iter = my_handle->getIterator();
165  ca_assert_expensive(is_member(iter));
166  my_handle->clearClientPtr();
167  cached.erase(iter);
168  --curr_size;
169  ca_assert_expensive(curr_size_valid());
170  ca_assert(!my_handle);
171  }
172 
173  friend class CacheHandle<SMARTPTR>;
174 
175  public:
176 
184  Cache(size_t Size) : curr_size(0), max_size(Size) {
185  ca_assert(is_valid_size(Size));
186 #if defined(DUMP_CACHE_STAT)
187  access_count = 0;
188  insert_count = 0;
189 #endif
190  }
196  ~Cache() {
197 #if defined(DUMP_CACHE_STAT)
198  printf("Cache-Stat: max_size=%zu inserts=%zu accesses=%zu\n", size(), insert_count, access_count);
199 #endif
200  flush();
201  }
202 
204  size_t entries() const {
205  ca_assert_expensive(curr_size_valid());
206  return curr_size;
207  }
209  size_t size() const { return max_size; }
214  void resize(size_t new_size) {
215  ca_assert(is_valid_size(new_size));
216  if (new_size<max_size) keep(new_size);
217  max_size = new_size;
218  }
220  void flush() { keep(0); }
221  };
222 
226  template <typename SMARTPTR> class CacheHandle : virtual Noncopyable {
227  CacheEntry<SMARTPTR> *entry;
228  public:
233  CacheHandle() : entry(NULp) {}
234 
240 
251  void assign(SMARTPTR data, Cache<SMARTPTR>& cache) {
252  ca_assert(data.isSet()); // use release() to set a CacheHandle to NULp
253  cache.insert(entry, data);
254  ca_assert(is_cached());
255  }
276  ca_assert(entry); // you did not check whether entry still is_cached()
277  cache.touch(*entry);
278  return entry->get_data();
279  }
289  if (entry) {
290  cache.remove(entry);
291  ca_assert(!entry); // should be NULLed by cache.remove
292  ca_assert(!is_cached());
293  }
294  }
298  bool is_cached() const { return entry; }
299  };
300 
301 };
302 
303 #else
304 #error cache.h included twice
305 #endif // CACHE_H
SMARTPTR access(Cache< SMARTPTR > &cache)
Definition: cache.h:275
void resize(size_t new_size)
Definition: cache.h:214
#define ca_assert(cond)
Definition: cache.h:26
SMARTPTR get_data() const
Definition: cache.h:69
Cache for any SmartPtr type.
Definition: cache.h:32
bool is_cached() const
Definition: cache.h:298
size_t size() const
Definition: cache.h:209
size_t entries() const
Definition: cache.h:204
void assign(SMARTPTR data, Cache< SMARTPTR > &cache)
Definition: cache.h:251
Handle for Cache entries.
Definition: cache.h:33
group_matcher none()
Definition: test_unit.h:1012
Cache(size_t Size)
Definition: cache.h:184
void release(Cache< SMARTPTR > &cache)
Definition: cache.h:288
#define NULp
Definition: cxxforward.h:116
GB_ERROR init_data(GBDATA *gb_main)
Definition: db_server.cxx:40
#define ca_assert_expensive(cond)
Definition: cache.h:27
void flush()
flush the cache, i.e. uncache all elements
Definition: cache.h:220
Definition: cache.h:31