Pyrogenesis  trunk
cache_adt.h
Go to the documentation of this file.
1 /* Copyright (c) 2010 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * Customizable cache data structure.
25  */
26 
27 #ifndef INCLUDED_CACHE_ADT
28 #define INCLUDED_CACHE_ADT
29 
30 #include <cfloat>
31 
32 #include <list>
33 #include <map>
34 #include <queue> // std::priority_queue
35 
36 #if CONFIG_ENABLE_BOOST
37 # include <boost/unordered_map.hpp>
38 # define MAP boost::unordered_map
39 #else
40 # define MAP stdext::hash_map
41 #endif
42 
43 /*
44 Cache for items of variable size and value/"cost".
45 underlying displacement algorithm is pluggable; default is "Landlord".
46 
47 template reference:
48 Entry provides size, cost, credit and credit_density().
49  rationale:
50  - made a template instead of exposing Cache::Entry because
51  that would drag a lot of stuff out of Cache.
52  - calculates its own density since that entails a Divider functor,
53  which requires storage inside Entry.
54 Entries is a collection with iterator and begin()/end() and
55  "static Entry& entry_from_it(iterator)".
56  rationale:
57  - STL map has pair<key, item> as its value_type, so this
58  function would return it->second. however, we want to support
59  other container types (where we'd just return *it).
60 Manager is a template parameterized on typename Key and class Entry.
61  its interface is as follows:
62 
63  // is the cache empty?
64  bool empty() const;
65 
66  // add (key, entry) to cache.
67  void add(const Key& key, const Entry& entry);
68 
69  // if the entry identified by <key> is not in cache, return false;
70  // otherwise return true and pass back a pointer to it.
71  bool find(const Key& key, const Entry** pentry) const;
72 
73  // remove an entry from cache, which is assumed to exist!
74  // this makes sense because callers will typically first use find() to
75  // return info about the entry; this also checks if present.
76  void remove(const Key& key);
77 
78  // mark <entry> as just accessed for purpose of cache management.
79  // it will tend to be kept in cache longer.
80  void on_access(Entry& entry);
81 
82  // caller's intent is to remove the least valuable entry.
83  // in implementing this, you have the latitude to "shake loose"
84  // several entries (e.g. because their 'value' is equal).
85  // they must all be push_back-ed into the list; Cache will dole
86  // them out one at a time in FIFO order to callers.
87  //
88  // rationale:
89  // - it is necessary for callers to receive a copy of the
90  // Entry being evicted - e.g. file_cache owns its items and
91  // they must be passed back to allocator when evicted.
92  // - e.g. Landlord can potentially see several entries become
93  // evictable in one call to remove_least_valuable. there are
94  // several ways to deal with this:
95  // 1) generator interface: we return one of { empty, nevermind,
96  // removed, remove-and-call-again }. this greatly complicates
97  // the call site.
98  // 2) return immediately after finding an item to evict.
99  // this changes cache behavior - entries stored at the
100  // beginning would be charged more often (unfair).
101  // resuming charging at the next entry doesn't work - this
102  // would have to be flushed when adding, at which time there
103  // is no provision for returning any items that may be evicted.
104  // 3) return list of all entries "shaken loose". this incurs
105  // frequent mem allocs, which can be alleviated via suballocator.
106  // note: an intrusive linked-list doesn't make sense because
107  // entries to be returned need to be copied anyway (they are
108  // removed from the manager's storage).
109  void remove_least_valuable(std::list<Entry>& entry_list)
110 */
111 
112 
113 //
114 // functors to calculate minimum credit density (MCD)
115 //
116 
117 // MCD is required for the Landlord algorithm's evict logic.
118 // [Young02] calls it '\delta'.
119 
120 // scan over all entries and return MCD.
121 template<class Entries> float ll_calc_min_credit_density(const Entries& entries)
122 {
123  float min_credit_density = FLT_MAX;
124  for(typename Entries::const_iterator it = entries.begin(); it != entries.end(); ++it)
125  {
126  const float credit_density = Entries::entry_from_it(it).credit_density();
127  min_credit_density = std::min(min_credit_density, credit_density);
128  }
129  return min_credit_density;
130 }
131 
132 // note: no warning is given that the MCD entry is being removed!
133 // (reduces overhead in remove_least_valuable)
134 // these functors must account for that themselves (e.g. by resetting
135 // their state directly after returning MCD).
136 
137 // determine MCD by scanning over all entries.
138 // tradeoff: O(N) time complexity, but all notify* calls are no-ops.
139 template<class Entry, class Entries>
141 {
142 public:
143  void notify_added(const Entry&) const {}
144  void notify_decreased(const Entry&) const {}
146  void notify_increased_or_removed(const Entry&) const {}
147  float operator()(const Entries& entries) const
148  {
149  const float mcd = ll_calc_min_credit_density(entries);
150  return mcd;
151  }
152 };
153 
154 // cache previous MCD and update it incrementally (when possible).
155 // tradeoff: amortized O(1) time complexity, but notify* calls must
156 // perform work whenever something in the cache changes.
157 template<class Entry, class Entries>
159 {
160 public:
161  McdCalc_Cached() : min_credit_density(FLT_MAX), min_valid(false) {}
162 
163  void notify_added(const Entry& entry)
164  {
165  // when adding a new item, the minimum credit density can only
166  // decrease or remain the same; acting as if entry's credit had
167  // been decreased covers both cases.
168  notify_decreased(entry);
169  }
170 
171  void notify_decreased(const Entry& entry)
172  {
173  min_credit_density = std::min(min_credit_density, entry.credit_density());
174  }
175 
177  {
178  // remember if this entry had the smallest density
179  is_min_entry = feq(min_credit_density, entry.credit_density());
180  }
181 
183  {
184  // .. it did and was increased or removed. we must invalidate
185  // MCD and recalculate it next time.
186  if(is_min_entry)
187  {
188  min_valid = false;
189  min_credit_density = -1.0f;
190  }
191  }
192 
193  float operator()(const Entries& entries)
194  {
195  if(min_valid)
196  {
197  // the entry that has MCD will be removed anyway by caller;
198  // we need to invalidate here because they don't call
199  // notify_increased_or_removed.
200  min_valid = false;
201  return min_credit_density;
202  }
203 
204  // this is somewhat counterintuitive. since we're calculating
205  // MCD directly, why not mark our cached version of it valid
206  // afterwards? reason is that our caller will remove the entry with
207  // MCD, so it'll be invalidated anyway.
208  // instead, our intent is to calculate MCD for the *next time*.
209  const float ret = ll_calc_min_credit_density(entries);
210  min_valid = true;
211  min_credit_density = FLT_MAX;
212  return ret;
213  }
214 
215 private:
217  bool min_valid;
218 
219  // temporary flag set by notify_impending_increase_or_remove
221 };
222 
223 
224 //
225 // Landlord cache management policy: see [Young02].
226 //
227 
228 // in short, each entry has credit initially set to cost. when wanting to
229 // remove an item, all are charged according to MCD and their size;
230 // entries are evicted if their credit is exhausted. accessing an entry
231 // restores "some" of its credit.
232 template<typename Key, typename Entry, template<class Entry_, class Entries> class McdCalc = McdCalc_Cached>
233 class Landlord
234 {
235 public:
236  bool empty() const
237  {
238  return map.empty();
239  }
240 
241  void add(const Key& key, const Entry& entry)
242  {
243  // adapter for add_ (which returns an iterator)
244  (void)add_(key, entry);
245  }
246 
247  bool find(const Key& key, const Entry** pentry) const
248  {
249  MapCIt it = map.find(key);
250  if(it == map.end())
251  return false;
252  *pentry = &it->second;
253  return true;
254  }
255 
256  void remove(const Key& key)
257  {
258  MapIt it = map.find(key);
259  // note: don't complain if not in the cache: this happens after
260  // writing a file and invalidating its cache entry, which may
261  // or may not exist.
262  if(it != map.end())
263  remove_(it);
264  }
265 
266  void on_access(Entry& entry)
267  {
268  mcd_calc.notify_impending_increase_or_remove(entry);
269 
270  // Landlord algorithm calls for credit to be reset to anything
271  // between its current value and the cost.
272  const float gain = 0.75f; // restore most credit
273  entry.credit = gain*entry.cost + (1.0f-gain)*entry.credit;
274 
275  mcd_calc.notify_increased_or_removed(entry);
276  }
277 
278  void remove_least_valuable(std::list<Entry>& entry_list)
279  {
280  // we are required to evict at least one entry. one iteration
281  // ought to suffice, due to definition of min_credit_density and
282  // tolerance; however, we provide for repeating if necessary.
283 again:
284 
285  // messing with this (e.g. raising if tiny) would result in
286  // different evictions than Landlord_Lazy, which is unacceptable.
287  // nor is doing so necessary: if mcd is tiny, so is credit.
288  const float min_credit_density = mcd_calc(map);
289  ENSURE(min_credit_density > 0.0f);
290 
291  for(MapIt it = map.begin(); it != map.end();) // no ++it
292  {
293  Entry& entry = it->second;
294 
295  charge(entry, min_credit_density);
296  if(should_evict(entry))
297  {
298  entry_list.push_back(entry);
299 
300  // annoying: we have to increment <it> before erasing
301  MapIt it_to_remove = it++;
302  map.erase(it_to_remove);
303  }
304  else
305  {
306  mcd_calc.notify_decreased(entry);
307  ++it;
308  }
309  }
310 
311  if(entry_list.empty())
312  goto again;
313  }
314 
315 protected:
316  class Map : public MAP<Key, Entry>
317  {
318  public:
319  static Entry& entry_from_it(typename Map::iterator it) { return it->second; }
320  static const Entry& entry_from_it(typename Map::const_iterator it) { return it->second; }
321  };
322  typedef typename Map::iterator MapIt;
323  typedef typename Map::const_iterator MapCIt;
324  Map map;
325 
326  // add entry and return iterator pointing to it.
327  MapIt add_(const Key& key, const Entry& entry)
328  {
329  typedef std::pair<MapIt, bool> PairIB;
330  typename Map::value_type val = std::make_pair(key, entry);
331  PairIB ret = map.insert(val);
332  ENSURE(ret.second); // must not already be in map
333 
334  mcd_calc.notify_added(entry);
335 
336  return ret.first;
337  }
338 
339  // remove entry (given by iterator) directly.
340  void remove_(MapIt it)
341  {
342  const Entry& entry = it->second;
343  mcd_calc.notify_impending_increase_or_remove(entry);
344  mcd_calc.notify_increased_or_removed(entry);
345  map.erase(it);
346  }
347 
348  void charge(Entry& entry, float delta)
349  {
350  entry.credit -= delta * entry.size;
351 
352  // don't worry about entry.size being 0 - if so, cost
353  // should also be 0, so credit will already be 0 anyway.
354  }
355 
356  // for each entry, 'charge' it (i.e. reduce credit by) delta * its size.
357  // delta is typically MCD (see above); however, several such updates
358  // may be lumped together to save time. Landlord_Lazy does this.
359  void charge_all(float delta)
360  {
361  for(MapIt it = map.begin(); it != map.end(); ++it)
362  {
363  Entry& entry = it->second;
364  entry.credit -= delta * entry.size;
365  if(!should_evict(entry))
366  mcd_calc.notify_decreased(entry);
367  }
368  }
369 
370  // is entry's credit exhausted? if so, it should be evicted.
371  bool should_evict(const Entry& entry)
372  {
373  // we need a bit of leeway because density calculations may not
374  // be exact. choose value carefully: must not be high enough to
375  // trigger false positives.
376  return entry.credit < 0.0001f;
377  }
378 
379 private:
380  McdCalc<Entry, Map> mcd_calc;
381 };
382 
383 // Cache manger policies. (these are partial specializations of Landlord,
384 // adapting it to the template params required by Cache)
385 template<class Key, class Entry> class Landlord_Naive : public Landlord<Key, Entry, McdCalc_Naive> {};
386 template<class Key, class Entry> class Landlord_Cached: public Landlord<Key, Entry, McdCalc_Cached> {};
387 
388 // variant of Landlord that adds a priority queue to directly determine
389 // which entry to evict. this allows lumping several charge operations
390 // together and thus reduces iteration over all entries.
391 // tradeoff: O(logN) removal (instead of N), but additional O(N) storage.
392 template<typename Key, class Entry>
393 class Landlord_Lazy : public Landlord_Naive<Key, Entry>
394 {
398 
399 public:
400  Landlord_Lazy() { pending_delta = 0.0f; }
401 
402  void add(const Key& key, const Entry& entry)
403  {
404  // we must apply pending_delta now - otherwise, the existing delta
405  // would later be applied to this newly added item (incorrect).
406  commit_pending_delta();
407 
408  MapIt it = Parent::add_(key, entry);
409  pri_q.push(it);
410  }
411 
412  void remove(const Key& key)
413  {
414  Parent::remove(key);
415 
416  // reconstruct pri_q from current map. this is slow (N*logN) and
417  // could definitely be done better, but we don't bother since
418  // remove is a very rare operation (e.g. invalidating entries).
419  while(!pri_q.empty())
420  pri_q.pop();
421  for(MapCIt it = this->map.begin(); it != this->map.end(); ++it)
422  pri_q.push(it);
423  }
424 
425  void on_access(Entry& entry)
426  {
427  Parent::on_access(entry);
428 
429  // entry's credit was changed. we now need to reshuffle the
430  // pri queue to reflect this.
431  pri_q.ensure_heap_order();
432  }
433 
434  void remove_least_valuable(std::list<Entry>& entry_list)
435  {
436  MapIt least_valuable_it = pri_q.top(); pri_q.pop();
437  Entry& entry = Map::entry_from_it(least_valuable_it);
438 
439  entry_list.push_back(entry);
440 
441  // add to pending_delta the MCD that would have resulted
442  // if removing least_valuable_it normally.
443  // first, calculate actual credit (i.e. apply pending_delta to
444  // this entry); then add the resulting density to pending_delta.
445  entry.credit -= pending_delta*entry.size;
446  const float credit_density = entry.credit_density();
447  ENSURE(credit_density > 0.0f);
448  pending_delta += credit_density;
449 
450  Parent::remove_(least_valuable_it);
451  }
452 
453 private:
455 
456  // sort iterators by credit_density of the Entry they reference.
457  struct CD_greater
458  {
459  bool operator()(MapIt it1, MapIt it2) const
460  {
461  return Map::entry_from_it(it1).credit_density() >
462  Map::entry_from_it(it2).credit_density();
463  }
464  };
465  // wrapper on top of priority_queue that allows 'heap re-sift'
466  // (see on_access).
467  // notes:
468  // - greater comparator makes pri_q.top() the one with
469  // LEAST credit_density, which is what we want.
470  // - deriving from an STL container is a bit dirty, but we need this
471  // to get at the underlying data (priority_queue interface is not
472  // very capable).
473  class PriQ: public std::priority_queue<MapIt, std::vector<MapIt>, CD_greater>
474  {
475  public:
477  {
478  // TODO: this is actually N*logN - ouch! that explains high
479  // CPU cost in profile. this is called after only 1 item has
480  // changed, so a logN "sift" operation ought to suffice.
481  // that's not supported by the STL heap functions, so we'd
482  // need a better implementation. pending..
483  std::make_heap(this->c.begin(), this->c.end(), this->comp);
484  }
485  };
487 
488  // delta values that have accumulated over several
489  // remove_least_valuable() calls. applied during add().
491 
493  {
494  if(pending_delta > 0.0f)
495  {
496  this->charge_all(pending_delta);
497  pending_delta = 0.0f;
498 
499  // we've changed entry credit, so the heap order *may* have been
500  // violated; reorder the pri queue. (I don't think so,
501  // due to definition of delta, but we'll play it safe)
502  pri_q.ensure_heap_order();
503  }
504  }
505 };
506 
507 
508 //
509 // functor that implements division of first arg by second
510 //
511 
512 // this is used to calculate credit_density(); performance matters
513 // because this is called for each entry during each remove operation.
514 
515 // floating-point division (fairly slow)
517 {
518 public:
519  Divider_Naive() {} // needed for default CacheEntry ctor
520  Divider_Naive(float UNUSED(x)) {}
521  float operator()(float val, float divisor) const
522  {
523  return val / divisor;
524  }
525 };
526 
527 // caches reciprocal of divisor and multiplies by that.
528 // tradeoff: only 4 clocks (instead of 20), but 4 bytes extra per entry.
530 {
531  float recip;
532 public:
533  Divider_Recip() {} // needed for default CacheEntry ctor
534  Divider_Recip(float x) { recip = 1.0f / x; }
535  float operator()(float val, float UNUSED(divisor)) const
536  {
537  return val * recip;
538  }
539 };
540 
541 
542 // initial implementation for testing purposes; quite inefficient.
543 template<typename Key, typename Entry>
544 class LRU
545 {
546 public:
547  bool empty() const
548  {
549  return lru.empty();
550  }
551 
552  void add(const Key& key, const Entry& entry)
553  {
554  lru.push_back(KeyAndEntry(key, entry));
555  }
556 
557  bool find(const Key& key, const Entry** pentry) const
558  {
559  CIt it = std::find(lru.begin(), lru.end(), KeyAndEntry(key));
560  if(it == lru.end())
561  return false;
562  *pentry = &it->entry;
563  return true;
564  }
565 
566  void remove(const Key& key)
567  {
568  lru.remove(KeyAndEntry(key));
569  }
570 
571  void on_access(Entry& entry)
572  {
573  for(It it = lru.begin(); it != lru.end(); ++it)
574  {
575  if(&entry == &it->entry)
576  {
577  add(it->key, it->entry);
578  lru.erase(it);
579  return;
580  }
581  }
582  DEBUG_WARN_ERR(ERR::LOGIC); // entry not found in list
583  }
584 
585  void remove_least_valuable(std::list<Entry>& entry_list)
586  {
587  entry_list.push_back(lru.front().entry);
588  lru.pop_front();
589  }
590 
591 private:
592  struct KeyAndEntry
593  {
594  KeyAndEntry(const Key& key): key(key) {}
595  KeyAndEntry(const Key& key, const Entry& entry): key(key), entry(entry) {}
596 
597  bool operator==(const KeyAndEntry& rhs) const { return key == rhs.key; }
598  bool operator!=(const KeyAndEntry& rhs) const { return !operator==(rhs); }
599 
600  Key key;
602  };
603 
604  typedef std::list<KeyAndEntry> List;
605  typedef typename List::iterator It;
606  typedef typename List::const_iterator CIt;
607  List lru;
608 };
609 
610 
611 // this is applicable to all cache management policies and stores all
612 // required information. a Divider functor is used to implement
613 // division for credit_density.
614 template<class Item, class Divider> struct CacheEntry
615 {
616  Item item;
617  size_t size;
618  size_t cost;
619  float credit;
620 
621  Divider divider;
622 
623  // needed for mgr.remove_least_valuable's entry_copy
625  {
626  }
627 
628  CacheEntry(const Item& item_, size_t size_, size_t cost_)
629  : item(item_), divider((float)size_)
630  {
631  size = size_;
632  cost = cost_;
633  credit = (float)cost;
634 
635  // else divider will fail
636  ENSURE(size != 0);
637  }
638 
639  float credit_density() const
640  {
641  return divider(credit, (float)size);
642  }
643 };
644 
645 
646 //
647 // Cache
648 //
649 
650 template
651 <
652 typename Key, typename Item,
653 // see documentation above for Manager's interface.
654 template<typename Key_, class Entry> class Manager = Landlord_Cached,
655 class Divider = Divider_Naive
656 >
657 class Cache
658 {
659 public:
660  Cache() : mgr() {}
661 
662  void add(const Key& key, const Item& item, size_t size, size_t cost)
663  {
664  return mgr.add(key, Entry(item, size, cost));
665  }
666 
667  // remove the entry identified by <key>. expected usage is to check
668  // if present and determine size via retrieve(), so no need for
669  // error checking.
670  // useful for invalidating single cache entries.
671  void remove(const Key& key)
672  {
673  mgr.remove(key);
674  }
675 
676  // if there is no entry for <key> in the cache, return false.
677  // otherwise, return true and pass back item and (optionally) size.
678  //
679  // if refill_credit (default), the cache manager 'rewards' this entry,
680  // tending to keep it in cache longer. this parameter is not used in
681  // normal operation - it's only for special cases where we need to
682  // make an end run around the cache accounting (e.g. for cache simulator).
683  bool retrieve(const Key& key, Item& item, size_t* psize = 0, bool refill_credit = true)
684  {
685  const Entry* entry;
686  if(!mgr.find(key, &entry))
687  return false;
688 
689  item = entry->item;
690  if(psize)
691  *psize = entry->size;
692 
693  if(refill_credit)
694  mgr.on_access((Entry&)*entry);
695 
696  return true;
697  }
698 
699  bool peek(const Key& key, Item& item, size_t* psize = 0)
700  {
701  return retrieve(key, item, psize, false);
702  }
703 
704  // toss out the least valuable entry. return false if cache is empty,
705  // otherwise true and (optionally) pass back its item and size.
706  bool remove_least_valuable(Item* pItem = 0, size_t* pSize = 0)
707  {
708  // as an artefact of the cache eviction policy, several entries
709  // may be "shaken loose" by one call to remove_least_valuable.
710  // we cache them in a list to disburden callers (they always get
711  // exactly one).
712  if(entries_awaiting_eviction.empty())
713  {
714  if(empty())
715  return false;
716 
717  mgr.remove_least_valuable(entries_awaiting_eviction);
718  ENSURE(!entries_awaiting_eviction.empty());
719  }
720 
721  const Entry& entry = entries_awaiting_eviction.front();
722  if(pItem)
723  *pItem = entry.item;
724  if(pSize)
725  *pSize = entry.size;
726  entries_awaiting_eviction.pop_front();
727 
728  return true;
729  }
730 
731  bool empty() const
732  {
733  return mgr.empty();
734  }
735 
736 private:
738 
739  // see note in remove_least_valuable().
740  std::list<Entry> entries_awaiting_eviction;
741 
742  Manager<Key, Entry> mgr;
743 };
744 
745 #endif // #ifndef INCLUDED_CACHE_ADT
void notify_impending_increase_or_remove(const Entry &entry)
Definition: cache_adt.h:176
float operator()(float val, float divisor) const
Definition: cache_adt.h:535
void commit_pending_delta()
Definition: cache_adt.h:492
const Status LOGIC
Definition: status.h:409
bool retrieve(const Key &key, Item &item, size_t *psize=0, bool refill_credit=true)
Definition: cache_adt.h:683
Definition: cache_adt.h:316
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
Definition: code_annotation.h:38
void remove_(MapIt it)
Definition: cache_adt.h:340
Definition: cache_adt.h:614
float min_credit_density
Definition: cache_adt.h:216
McdCalc< Entry, Map > mcd_calc
Definition: cache_adt.h:380
CacheEntry()
Definition: cache_adt.h:624
Definition: cache_adt.h:385
void notify_decreased(const Entry &) const
Definition: cache_adt.h:144
void add(const Key &key, const Entry &entry)
Definition: cache_adt.h:241
void notify_increased_or_removed(const Entry &entry)
Definition: cache_adt.h:182
Divider divider
Definition: cache_adt.h:621
float operator()(const Entries &entries) const
Definition: cache_adt.h:147
Landlord_Naive< Key, Entry >::Map Map
Definition: cache_adt.h:395
void notify_impending_increase_or_remove(const Entry &) const
Definition: cache_adt.h:145
Item item
Definition: cache_adt.h:616
bool operator==(const FCDJointWeightPair &a, const FCDJointWeightPair &b)
Definition: GeomReindex.cpp:59
#define MAP
Definition: cache_adt.h:40
bool remove_least_valuable(Item *pItem=0, size_t *pSize=0)
Definition: cache_adt.h:706
Divider_Naive()
Definition: cache_adt.h:519
float credit
Definition: cache_adt.h:619
bool find(const Key &key, const Entry **pentry) const
Definition: cache_adt.h:557
void charge(Entry &entry, float delta)
Definition: cache_adt.h:348
bool should_evict(const Entry &entry)
Definition: cache_adt.h:371
The MIT License free of charge
Definition: LICENSE.txt:5
void notify_increased_or_removed(const Entry &) const
Definition: cache_adt.h:146
void on_access(Entry &entry)
Definition: cache_adt.h:266
bool operator()(MapIt it1, MapIt it2) const
Definition: cache_adt.h:459
void add(const Key &key, const Item &item, size_t size, size_t cost)
Definition: cache_adt.h:662
Definition: cache_adt.h:158
static const Entry & entry_from_it(typename Map::const_iterator it)
Definition: cache_adt.h:320
Definition: cache_adt.h:592
KeyAndEntry(const Key &key, const Entry &entry)
Definition: cache_adt.h:595
void charge_all(float delta)
Definition: cache_adt.h:359
CacheEntry(const Item &item_, size_t size_, size_t cost_)
Definition: cache_adt.h:628
float operator()(float val, float divisor) const
Definition: cache_adt.h:521
Definition: cache_adt.h:473
void add(const Key &key, const Entry &entry)
Definition: cache_adt.h:552
Entry entry
Definition: cache_adt.h:601
Manager< Key, Entry > mgr
Definition: cache_adt.h:742
Definition: cache_adt.h:657
Landlord_Naive< Key, Entry > Parent
Definition: cache_adt.h:454
float pending_delta
Definition: cache_adt.h:490
#define ENSURE(expr)
ensure the expression <expr> evaluates to non-zero.
Definition: debug.h:287
PriQ pri_q
Definition: cache_adt.h:486
size_t cost
Definition: cache_adt.h:618
Definition: cache_adt.h:544
bool peek(const Key &key, Item &item, size_t *psize=0)
Definition: cache_adt.h:699
List::const_iterator CIt
Definition: cache_adt.h:606
Map::const_iterator MapCIt
Definition: cache_adt.h:323
Map map
Definition: cache_adt.h:324
void ensure_heap_order()
Definition: cache_adt.h:476
bool operator==(const KeyAndEntry &rhs) const
Definition: cache_adt.h:597
void remove_least_valuable(std::list< Entry > &entry_list)
Definition: cache_adt.h:434
void notify_added(const Entry &) const
Definition: cache_adt.h:143
Definition: cache_adt.h:457
void remove_least_valuable(std::list< Entry > &entry_list)
Definition: cache_adt.h:585
bool empty() const
Definition: cache_adt.h:547
pthread_key_t key
Definition: wpthread.cpp:140
Definition: cache_adt.h:233
void on_access(Entry &entry)
Definition: cache_adt.h:425
List lru
Definition: cache_adt.h:607
size_t size
Definition: cache_adt.h:617
uint32_t Entry
Definition: SilhouetteRenderer.cpp:135
Landlord_Naive< Key, Entry >::MapIt MapIt
Definition: cache_adt.h:396
static Entry & entry_from_it(typename Map::iterator it)
Definition: cache_adt.h:319
Definition: cache_adt.h:516
void on_access(Entry &entry)
Definition: cache_adt.h:571
Key key
Definition: cache_adt.h:600
CacheEntry< Item, Divider > Entry
Definition: cache_adt.h:737
Cache()
Definition: cache_adt.h:660
Landlord_Lazy()
Definition: cache_adt.h:400
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:336
McdCalc_Cached()
Definition: cache_adt.h:161
Divider_Recip()
Definition: cache_adt.h:533
Definition: cache_adt.h:393
Landlord_Naive< Key, Entry >::MapCIt MapCIt
Definition: cache_adt.h:397
float credit_density() const
Definition: cache_adt.h:639
void remove_least_valuable(std::list< Entry > &entry_list)
Definition: cache_adt.h:278
std::list< KeyAndEntry > List
Definition: cache_adt.h:604
bool empty() const
Definition: cache_adt.h:236
float recip
Definition: cache_adt.h:531
void add(const Key &key, const Entry &entry)
Definition: cache_adt.h:402
bool min_valid
Definition: cache_adt.h:217
Definition: cache_adt.h:140
bool feq(double d1, double d2, double epsilon=0.00001)
are the given floats nearly "equal"?
Definition: lib.h:96
bool is_min_entry
Definition: cache_adt.h:220
std::list< Entry > entries_awaiting_eviction
Definition: cache_adt.h:740
Definition: cache_adt.h:386
Map::iterator MapIt
Definition: cache_adt.h:322
bool operator!=(const KeyAndEntry &rhs) const
Definition: cache_adt.h:598
List::iterator It
Definition: cache_adt.h:605
Divider_Naive(float x)
Definition: cache_adt.h:520
Divider_Recip(float x)
Definition: cache_adt.h:534
Definition: cache_adt.h:529
KeyAndEntry(const Key &key)
Definition: cache_adt.h:594
void notify_decreased(const Entry &entry)
Definition: cache_adt.h:171
void notify_added(const Entry &entry)
Definition: cache_adt.h:163
MapIt add_(const Key &key, const Entry &entry)
Definition: cache_adt.h:327
bool empty() const
Definition: cache_adt.h:731
float ll_calc_min_credit_density(const Entries &entries)
Definition: cache_adt.h:121
bool find(const Key &key, const Entry **pentry) const
Definition: cache_adt.h:247
float operator()(const Entries &entries)
Definition: cache_adt.h:193