Bridges-C++  3.4.5-dev1-6-g935685a
Bridges(C++ API)
Cache.h
Go to the documentation of this file.
1 #ifndef CACHE_H
2 #define CACHE_H
3 
4 #ifndef _WIN32
5 #include <unistd.h>
6 #endif
7 #ifdef _WIN32
8 #include <direct.h>
9 #endif
10 
11 #if __cplusplus >= 201703L
12 #include <filesystem>
13 #endif
14 
15 namespace bridges {
16 
17 
18  class CacheException : public std::exception {
19  const char* whatmsg;
20  public:
21 
22  CacheException(const char* what_msg = "")
23  : std::exception(), whatmsg(what_msg) {
24 
25  }
26 
27  virtual const char* what() const noexcept {
28  return whatmsg;
29  }
30 
31  };
32 
33  class Cache {
34  public:
35  virtual bool inCache(const std::string & docName) noexcept(false) = 0;
36  virtual std::string getDoc (const std::string & docName) noexcept(false) = 0;
37  //store content under docname
38  virtual void putDoc (const std::string & docName,
39  const std::string & content) noexcept(false) = 0;
40  };
41 
54  class SimpleCache : public Cache {
55  private:
56  std::string cacheDir;
57 
58  std::string getFilename(const std::string & docName) {
59  return cacheDir + "/" + docName; //TODO: bad things can happen if docName contains / or .. or stuff like that
60 
61  }
62 
63  //return whether s is a directory (true) or does not exist (false). all other cases are exception
64  bool directoryExist(const std::string &s) {
65  struct stat buffer;
66  int ret = stat (s.c_str(), &buffer);
67 
68  if (ret == 0) { //file exist
69  if ((buffer.st_mode & S_IFMT) == S_IFDIR) { //Not using S_ISDIR because VS2017 does not support it.
70  return true;
71  }
72  else {
73  throw CacheException("Expect directory"); //s exist but is not a directory
74  }
75  }
76 
77  return false;
78  }
79 
80  //make a directory called s or throw an exception
81  static void makeDirectory (const std::string &s) {
82 #if __cplusplus >= 201703L
83  //C++17 support
84 
85  //we can use std::filesystem::create_directories to make the directories recursively.
86 
87  bool ret = std::filesystem::create_directories(s);
88  if (!ret)
89  throw CacheException("error in makeDirectory");
90 
91 #else
92  //No C++17 support. So no std::filesystem support
93  //So forgo recursive creation. Probably not worth the cost of writing the code.
94 #ifndef _WIN32
95  int ret = mkdir(s.c_str(), 0700);
96 #endif
97 #ifdef _WIN32
98  int ret = _mkdir(s.c_str());
99 #endif
100 
101  if (ret != 0)
102  throw CacheException("error in makeDirectory");
103 
104 #endif
105 
106 
107  }
108 
109  public:
111  //According to XDG, you should put the cache data in
112  //$XDG_CACHE_HOME and if not defined in $HOME/.cache
113  //However, MS Windows does not set $HOME. So we
114  //use $LOCALAPPDATA as if it was $HOME.
115  //
116  //So we put the data in $XDG_CACHE_HOME/bridges_data/cxx
117  //
118  //Finally, one can overide everything by setting $FORCE_BRIDGES_CACHEDIR
119 
120  char * home = getenv("HOME"); // a reasonable location on unixes
121  if (home == nullptr)
122  home = getenv("LOCALAPPDATA"); // a reasonnable location on windowses
123 
124  if (home != nullptr)
125  cacheDir += std::string(home) + "/.cache/";
126 
127 
128  //override the directory of the cache if is set
129  char* xdg_cache_home = getenv("XDG_CACHE_HOME");
130  if (xdg_cache_home != nullptr)
131  cacheDir = std::string(xdg_cache_home) + "/";
132 
133  cacheDir += "bridges_data/cxx/";
134  //probably should check directory existence here, but exception in constructors are weird.
135 
136 
137  //override the directory of the cache if FORCE_BRIDGES_CACHEDIR is set
138  char* forcedir = getenv("FORCE_BRIDGES_CACHEDIR");
139  if (forcedir != nullptr)
140  cacheDir = std::string(forcedir) + "/";
141  }
142 
143  virtual ~SimpleCache() = default;
144 
145  //is docName in the cache
146  virtual bool inCache(const std::string & docName) noexcept(false) override {
147  std::string filename = getFilename(docName);
148 
149  std::ifstream in(filename);
150 
151  return in.is_open();
152  }
153 
154  //return the content of docName which is in the cache
155  virtual std::string getDoc (const std::string & docName) noexcept(false) override {
156  std::string filename = getFilename(docName);
157 
158  std::ifstream in(filename);
159 
160  if (!in.good() || !(in.is_open()))
161  throw CacheException("Can't open file to read");
162 
163  std::string contents;
164  in.seekg(0, std::ios::end);
165  contents.resize(in.tellg());
166  in.seekg(0, std::ios::beg);
167  in.read(&contents[0], contents.size());
168  if (! (in.good()))
169  throw CacheException("Error while reading cache document");
170  in.close();
171  return (contents);
172 
173  }
174 
175  //store content under docname
176  virtual void putDoc (const std::string & docName,
177  const std::string & content) noexcept(false) override {
178  if (!directoryExist(cacheDir))
179  makeDirectory(cacheDir);
180 
181  std::string filename = getFilename(docName);
182 
183  std::ofstream out(filename);
184  if (!out.good() || !(out.is_open()))
185  throw CacheException("can't open file to store");
186 
187  out << content.c_str(); //this assumes string isn't binary
188  if (!out.good() || !(out.is_open()))
189  throw CacheException("error while writing cache document");
190 
191  }
192 
197  bool evict(const std::string& docName) {
198  string f = cacheDir;
199  f.append(docName);
200 
201  return std::remove(f.c_str()) == 0;
202  }
203  };
204 
205  class lruCache : public Cache {
206 
207  int maxCache;
208  std::vector<std::string> v;
209  SimpleCache ca;
210  public:
211  lruCache(int maxFileNumber = 30)
212  : maxCache(maxFileNumber) {
213  }
214 
215  virtual ~lruCache() = default;
216 
217  virtual std::string getDoc (const std::string& hash_value) override { //returns LRU vector from cache file
218  string content;
219  getLRU();
220  content = ca.getDoc(hash_value);
221  updateLRU(hash_value);
222  saveLRU();
223  return content;
224  }
225 
226  virtual bool inCache(const std::string& hash_value) override {
227  if (ca.inCache(hash_value)) {
228  return true;
229  }
230  return false;
231  }
232 
233  virtual void putDoc(const std::string& hash_value, const std::string& content) override { //puts hash value at front of LRU vector
234  getLRU();
235  ca.putDoc(hash_value, content);
236  updateLRU(hash_value);
237 
238  //checks size of vector and pops lru off
239  if (v.size() >= maxCache + 1) { // keeps maxCache local maps
240  if (ca.evict(v[v.size() - 1]))
241  v.pop_back();
242  }
243  saveLRU();
244  return;
245  }
246 
247  private:
248  void updateLRU(std::string hash_value) {
249  for (auto it = v.begin(); it != v.end(); ) {
250  if (*it == hash_value) {
251  v.erase(it); //removes old hash vlaue location in vector
252  break;
253  }
254  else {
255  ++it;
256  }
257  }
258  v.insert(v.begin(), hash_value); //puts hash value in the front of the vector
259  return;
260  }
261  void getLRU() {
262  v.clear();
263  if (ca.inCache("lru")) {
264  string vector_string = ca.getDoc("lru"); //Imported LRU
265  std::istringstream ss(vector_string);
266  std::string token;
267  //Parses string and turns it into vector
268  while (std::getline(ss, token, ',')) {
269  v.push_back(token);
270  }
271  }
272  return;
273  }
274 
275  void saveLRU() {
276  //Saves the vector to file
277  string out_vector;
278  int x = 0;
279  for (auto s : v) {
280  if (x == 0) { //prevents , from being first character
281  out_vector = s;
282  x++;
283  }
284  else {
285  out_vector = out_vector + "," + s;
286  }
287  }
288  ca.putDoc("lru", out_vector);
289  }
290  };
291 }
292 
293 #endif
Definition: Cache.h:18
CacheException(const char *what_msg="")
Definition: Cache.h:22
virtual const char * what() const noexcept
Definition: Cache.h:27
Definition: Cache.h:33
virtual std::string getDoc(const std::string &docName) noexcept(false)=0
virtual bool inCache(const std::string &docName) noexcept(false)=0
virtual void putDoc(const std::string &docName, const std::string &content) noexcept(false)=0
object managing a disk cache for which ever purpose needed.
Definition: Cache.h:54
bool evict(const std::string &docName)
evicts a document from the cache
Definition: Cache.h:197
virtual ~SimpleCache()=default
virtual void putDoc(const std::string &docName, const std::string &content) noexcept(false) override
Definition: Cache.h:176
virtual std::string getDoc(const std::string &docName) noexcept(false) override
Definition: Cache.h:155
virtual bool inCache(const std::string &docName) noexcept(false) override
Definition: Cache.h:146
SimpleCache()
Definition: Cache.h:110
Definition: Cache.h:205
virtual void putDoc(const std::string &hash_value, const std::string &content) override
Definition: Cache.h:233
lruCache(int maxFileNumber=30)
Definition: Cache.h:211
virtual bool inCache(const std::string &hash_value) override
Definition: Cache.h:226
virtual ~lruCache()=default
virtual std::string getDoc(const std::string &hash_value) override
Definition: Cache.h:217
Support for drawing Bar charts.
Definition: alltypes.h:4