1 
2 // =================================================================================================
3 // This file is part of the CLBlast project. The project is licensed under Apache Version 2.0. This
4 // project loosely follows the Google C++ styleguide and uses a tab-size of two spaces and a max-
5 // width of 100 characters per line.
6 //
7 // Author(s):
8 //   Cedric Nugteren <www.cedricnugteren.nl>
9 //
10 // This file implements the caching functionality of compiled binaries and programs.
11 //
12 // =================================================================================================
13 
14 #include <string>
15 #include <vector>
16 #include <mutex>
17 
18 #include "database/database.hpp"
19 #include "cache.hpp"
20 
21 namespace clblast {
22 // =================================================================================================
23 
24 template <typename Key, typename Value>
25 template <typename U>
Get(const U & key,bool * in_cache) const26 Value Cache<Key, Value>::Get(const U &key, bool *in_cache) const {
27   std::lock_guard<std::mutex> lock(cache_mutex_);
28 
29 #if __cplusplus >= 201402L
30   // generalized std::map::find() of C++14
31   auto it = cache_.find(key);
32 #else
33   // O(n) lookup in a vector
34   auto it = std::find_if(cache_.begin(), cache_.end(), [&] (const std::pair<Key, Value> &pair) {
35     return pair.first == key;
36   });
37 #endif
38   if (it == cache_.end()) {
39     if (in_cache) {
40       *in_cache = false;
41     }
42     return Value();
43   }
44 
45   if (in_cache) {
46     *in_cache = true;
47   }
48   return it->second;
49 }
50 
51 template <typename Key, typename Value>
Store(Key && key,Value && value)52 void Cache<Key, Value>::Store(Key &&key, Value &&value) {
53   std::lock_guard<std::mutex> lock(cache_mutex_);
54 
55 #if __cplusplus >= 201402L
56   // emplace() into a map
57   auto r = cache_.emplace(std::move(key), std::move(value));
58   if (!r.second) {
59     throw LogicError("Cache::Store: object already in cache");
60   }
61 #else
62   // emplace_back() into a vector
63   cache_.emplace_back(std::move(key), std::move(value));
64 #endif
65 }
66 
67 template <typename Key, typename Value>
Remove(const Key & key)68 void Cache<Key, Value>::Remove(const Key &key) {
69   std::lock_guard<std::mutex> lock(cache_mutex_);
70 #if __cplusplus >= 201402L
71   cache_.erase(key);
72 #else
73   auto it = cache_.begin();
74   while (it != cache_.end()) {
75     if ((*it).first == key) {
76       it = cache_.erase(it);
77     }
78     else ++it;
79   }
80 #endif
81 }
82 
83 template <typename Key, typename Value>
84 template <int I1, int I2>
RemoveBySubset(const Key & key)85 void Cache<Key, Value>::RemoveBySubset(const Key &key) {
86   std::lock_guard<std::mutex> lock(cache_mutex_);
87   auto it = cache_.begin();
88   while (it != cache_.end()) {
89     const auto current_key = (*it).first;
90     if ((std::get<I1>(key) == std::get<I1>(current_key)) &&
91         (std::get<I2>(key) == std::get<I2>(current_key))) {
92       it = cache_.erase(it);
93     }
94     else ++it;
95   }
96 }
97 
98 template <typename Key, typename Value>
Invalidate()99 void Cache<Key, Value>::Invalidate() {
100   std::lock_guard<std::mutex> lock(cache_mutex_);
101 
102   cache_.clear();
103 }
104 
105 template <typename Key, typename Value>
Instance()106 Cache<Key, Value> &Cache<Key, Value>::Instance() {
107   return instance_;
108 }
109 
110 template <typename Key, typename Value>
111 Cache<Key, Value> Cache<Key, Value>::instance_;
112 
113 // =================================================================================================
114 
115 template class Cache<BinaryKey, std::string>;
116 template std::string BinaryCache::Get(const BinaryKeyRef &, bool *) const;
117 
118 // =================================================================================================
119 
120 template class Cache<ProgramKey, Program>;
121 template Program ProgramCache::Get(const ProgramKeyRef &, bool *) const;
122 template void ProgramCache::RemoveBySubset<1, 2>(const ProgramKey &); // precision and routine name
123 
124 // =================================================================================================
125 
126 template class Cache<DatabaseKey, Database>;
127 template Database DatabaseCache::Get(const DatabaseKeyRef &, bool *) const;
128 
129 // =================================================================================================
130 } // namespace clblast
131