9 #ifndef IMPKERNEL_CACHE_H 
   10 #define IMPKERNEL_CACHE_H 
   12 #include <IMP/kernel_config.h> 
   13 #include "internal/cache.h" 
   18 #include <boost/multi_index_container.hpp> 
   19 #include <boost/multi_index/sequenced_index.hpp> 
   20 #include <boost/multi_index/hashed_index.hpp> 
   21 #include <boost/multi_index/global_fun.hpp> 
   29 IMPKERNEL_BEGIN_NAMESPACE
 
   38 template <
class Generator,
 
   39           class Checker = std::equal_to<typename Generator::result_type> >
 
   43   mutable bool has_result_;
 
   44   mutable typename Generator::result_type result_;
 
   45   mutable int num_misses_;
 
   46   mutable int num_stats_;
 
   49   typedef typename Generator::result_type Value;
 
   50   typedef typename Generator::argument_type Key;
 
   51   Memoizer(
const Generator &gen, 
const Checker &checker = Checker())
 
   57   Generator &access_generator() { 
return gen_; }
 
   58   const Generator &get_generator()
 const { 
return gen_; }
 
   63   const Value &
get() 
const {
 
   71                        "Wrong result returned from generator");
 
   75   void set(
const Value &v)
 const {
 
   80   double get_hit_rate()
 const {
 
   81     return 1.0 - 
static_cast<double>(num_misses_) / num_stats_;
 
   88 template <
class Generator, 
class Checker>
 
   91   typedef typename Generator::argument_type::value_type Key;
 
   92   typedef typename Generator::result_type::value_type Entry;
 
   99   static Key get_0(Entry e) { 
return std::get<0>(e); }
 
  100   static Key get_1(Entry e) { 
return std::get<1>(e); }
 
  103   typedef boost::multi_index::global_fun<Entry, Key, &This::get_0> P0Member;
 
  104   typedef boost::multi_index::global_fun<Entry, Key, &This::get_1> P1Member;
 
  105   typedef boost::multi_index::hashed_non_unique<P0Member> Hash0Index;
 
  106   typedef boost::multi_index::hashed_non_unique<P1Member> Hash1Index;
 
  107   typedef boost::multi_index::indexed_by<Hash0Index, Hash1Index> IndexBy;
 
  108   typedef boost::multi_index_container<Entry, IndexBy> Cache;
 
  109   typedef typename boost::multi_index::nth_index<Cache, 0>::type::const_iterator
 
  111   typedef typename boost::multi_index::nth_index<Cache, 1>::type::const_iterator
 
  118     EntryEqual(Key t0, Key t1) : v(t0, t1) {}
 
  120     bool operator()(
const O &o)
 const {
 
  121       return v[0] == o[0] && v[1] == o[1];
 
  125   Hash0Iterator 
get(Key t0, Key t1) 
const {
 
  127     boost::tie(b, e) = cache_.template get<0>().equal_range(t0);
 
  130     Hash0Iterator f = std::find_if(b, e, EntryEqual(t0, t1));
 
  133       return cache_.template get<0>().end();
 
  138   void check_it()
 const {
 
  139 #if IMP_HAS_CHECKS >= IMP_INTERNAL 
  143                                           << gen_(domain_, 
this)
 
  144                                           << 
" and cleared is " << cleared_);
 
  145     for (Hash0Iterator c = cache_.template get<0>().begin();
 
  146          c != cache_.template get<0>().end(); ++c) {
 
  148           get(c->operator[](1), c->operator[](0)) ==
 
  149               cache_.template get<0>().end(),
 
  150           "Both an entry and its flip are in the table: " << *c << 
": " << cur);
 
  156       for (
unsigned int i = 0; i < cleared_.size(); ++i) {
 
  159           boost::tie(b, e) = cache_.template get<0>().equal_range(cleared_[i]);
 
  161                                                       << 
" was not cleared.");
 
  165           boost::tie(b, e) = cache_.template get<1>().equal_range(cleared_[i]);
 
  167                                                       << 
" was not cleared.");
 
  173     IMP_LOG_VERBOSE(
"Inserting " << nv << 
" into pair memoizer" << std::endl);
 
  175       for (
unsigned int i = 0; i < nv.size(); ++i) {
 
  177             std::find_if(nv.begin(), nv.end(),
 
  178                          EntryEqual(nv[i][1], nv[i][0])) == nv.end(),
 
  179             "An entry and its flip are already in list: " << nv);
 
  182     cache_.insert(nv.begin(), nv.end());
 
  184     IMP_LOG_VERBOSE(
"To get " << 
typename Generator::result_type(cache_.begin(),
 
  189   template <
class F, 
class It>
 
  190   F do_apply(It b, It e, F f)
 const {
 
  191     for (It c = b; c != e; ++c) {
 
  199                               const Generator &gen = Generator(),
 
  200                               const Checker &check = Checker())
 
  201       : gen_(gen), checker_(check), cleared_(domain), domain_(domain) {
 
  202     IMP_LOG_TERSE(
"Domain for memoizer is " << domain << std::endl);
 
  207     if (!cleared_.empty()) fill_it();
 
  209     return do_apply(cache_.begin(), cache_.end(), f);
 
  215     return do_apply(cache_.begin(), cache_.end(), f);
 
  219   void remove(
const Key &a) {
 
  220     if (std::find(cleared_.begin(), cleared_.end(), a) != cleared_.end()) {
 
  224     cleared_.push_back(a);
 
  227       boost::tie(b, e) = cache_.template get<0>().equal_range(a);
 
  228       cache_.template get<0>().erase(b, e);
 
  232       boost::tie(b, e) = cache_.template get<1>().equal_range(a);
 
  233       cache_.template get<1>().erase(b, e);
 
  236   void insert(
const Entry &e) { cache_.insert(e); }
 
  241   const Generator &get_generator()
 const { 
return gen_; }
 
  242   Generator &access_generator()
 const { 
return gen_; }
 
  252 template <
class Generator,
 
  253           class Checker = std::equal_to<typename Generator::result_type> >
 
  256   typedef typename Generator::result_type Value;
 
  257   typedef typename Generator::argument_type Key;
 
  262   unsigned int max_size_;
 
  263   mutable int num_stats_;
 
  264   mutable int num_misses_;
 
  268     KVP(
const Key &k, 
const Value &v) : key(k), value(v) {}
 
  270   typedef boost::multi_index::member<KVP, Key, &KVP::key> KeyMember;
 
  271   typedef boost::multi_index::hashed_unique<KeyMember> HashIndex;
 
  272   typedef boost::multi_index::sequenced<> Sequenced;
 
  273   typedef boost::multi_index_container<
 
  274       KVP, boost::multi_index::indexed_by<HashIndex, Sequenced> > Map;
 
  276   typedef typename boost::multi_index::template nth_index<
 
  277       Map, 0>::type::const_iterator LookupIterator;
 
  278   typedef typename boost::multi_index::template nth_index<
 
  279       Map, 1>::type::const_iterator OrderIterator;
 
  280   Value add_value(
const Key &k)
 const {
 
  281     Value v = gen_(k, *
this);
 
  282     map_.template get<1>().push_front(KVP(k, v));
 
  283     while (map_.size() > max_size_) {
 
  285       map_.template get<1>().pop_back();
 
  291   LRUCache(
const Generator &gen, 
unsigned int size,
 
  292            const Checker checker = Checker())
 
  298   Value 
get(
const Key &k) 
const {
 
  299     LookupIterator it = map_.template get<0>().find(k);
 
  301     if (it == map_.template get<0>().end()) {
 
  304       Value v = add_value(k);
 
  306                                                map_.template get<0>().end(),
 
  307                          "Failed to insert into cache");
 
  310       map_.template get<1>().relocate(map_.template project<1>(it),
 
  311                                       map_.template get<1>().begin());
 
  318           map_.template get<0>().find(k) != map_.template get<0>().end(),
 
  319           "Gone, gone I tell you");
 
  323   double get_hit_rate()
 const {
 
  324     return 1.0 - 
static_cast<double>(num_misses_) / num_stats_;
 
  328     for (OrderIterator it = map_.template get<1>().begin();
 
  329          it != map_.template get<1>().end(); ++it) {
 
  330       ret.push_back(it->key);
 
  334   typedef OrderIterator ContentIterator;
 
  335   ContentIterator contents_begin()
 const {
 
  336     return map_.template get<1>().begin();
 
  338   ContentIterator contents_end()
 const { 
return map_.template get<1>().end(); }
 
  339   void insert(Key k, Value v) {
 
  340     LookupIterator it = map_.template get<0>().find(k);
 
  341     if (it == map_.template get<0>().end()) {
 
  342       map_.template get<1>().push_front(KVP(k, v));
 
  343       while (map_.size() > max_size_) {
 
  344         map_.template get<1>().pop_back();
 
  348   unsigned int size()
 const { 
return map_.size(); }
 
  349   Generator &access_generator() { 
return gen_; }
 
  350   const Generator &get_generator()
 const { 
return gen_; }
 
  353 IMPKERNEL_END_NAMESPACE
 
Helper class for writing memoizers. 
 
#define IMP_IF_CHECK(level)
Execute the code block if a certain level checks are on. 
 
#define IMP_FUNCTION_LOG
Beginning logging for a non-member function. 
 
Helper functions for implementing hashes. 
 
#define IMP_LOG_VERBOSE(expr)
 
Classes to handle static sized arrays of things. 
 
#define IMP_LOG_TERSE(expr)
 
void set(const Value &v) const 
Update the stored result manually. 
 
#define IMP_INTERNAL_CHECK(expr, message)
An assertion to check for internal errors in IMP. An IMP::ErrorException will be thrown. 
 
Logging and error reporting support. 
 
Implement a simple least recently used cache. 
 
A class for storing lists of IMP items. 
 
F apply_to_current_contents(F f)
 
Helper macros for throwing and handling exceptions.