Cachier 1.0
Fast C++ header only library that provides simple and efficient way to cache computed data for files
Loading...
Searching...
No Matches
cachier.h
1#ifndef CACHIER_H
2#define CACHIER_H
3
4#include <algorithm>
5#include <dirent.h>
6#include <filesystem>
7#include <fstream>
8#include <iostream>
9#include <limits>
10#include <sstream>
11#include <string>
12#include <sys/stat.h>
13#include <unistd.h>
14#include <vector>
15
20class Cachier {
21public:
25 enum CacheOverwriteOption { OVERWRITE_CACHE, DONT_OVERWRITE_CACHE };
26
31 struct HashResult {
32 std::size_t key;
33 std::string error;
34 };
35
44 Cachier(const std::string &cache_store_path,
45 bool ensure_cache_store_path = true)
46 : cache_store_path(cache_store_path) {
47
48 // Create cache_store_path if asked
49 if (ensure_cache_store_path) {
50 createDir(cache_store_path);
51 }
52
53 // Check if the cache_store_path is valid and writable
54 struct stat dir_stat;
55 if (!(stat(cache_store_path.c_str(), &dir_stat) == 0 &&
56 S_ISDIR(dir_stat.st_mode) &&
57 access(cache_store_path.c_str(), W_OK) == 0)) {
58 std::cerr
59 << "Warning: Cache store path is not valid or not writeable, caching "
60 "feature will not work."
61 << std::endl;
62 } else {
63 initialized = true;
64 }
65 }
66
81 HashResult addCache(const std::string &filename,
82 const std::string &content = "",
83 const CacheOverwriteOption &cache_overwrite_option =
84 DONT_OVERWRITE_CACHE) {
85
86 initCheck();
87
88 // Compute hash
89 HashResult hash_result = computeHash(filename);
90
91 if (hash_result.error != "") {
92 return {0, hash_result.error};
93 }
94
95 // Prevent overwrite if cache exists and was asked not to overwrite it
96 if (cache_overwrite_option == DONT_OVERWRITE_CACHE &&
97 cacheExists(hash_result.key)) {
98 auto error = "Error: cache exists, not over-writing it.";
99 return {0, error};
100 }
101
102 // Add file to cache_store_path
103 bool cache_created =
104 createCacheFile(std::to_string(hash_result.key), content);
105
106 HashResult error = {0, "Error: unable to create cache file."};
107 return cache_created ? hash_result : error;
108 }
109
117 bool cacheExists(const std::size_t &key) {
118 // Check if file is in cache_store_path
119 return fileExists(cache_store_path +
120 std::filesystem::path::preferred_separator +
121 std::to_string(key));
122 }
123
134 bool cacheExists(const std::string &filename) {
135
136 initCheck();
137
138 // Compute hash
139 auto hash_result = computeHash(filename);
140
141 // Check if file is in cache_store_path
142 return fileExists(cache_store_path +
143 std::filesystem::path::preferred_separator +
144 std::to_string(hash_result.key));
145 }
146
154 initialization_checked = true;
155 return initialized;
156 }
157
170 HashResult computeHash(const std::string &filename) {
171
172 struct stat fileStat;
173
174 if (stat(filename.c_str(), &fileStat) != 0 &&
175 !std::filesystem::is_regular_file(filename)) {
176 auto error = "Error: " + filename + " is not a valid file.";
177 return {0, error};
178 }
179
180 // Get file size and modification time
181 size_t fileSize = fileStat.st_size;
182 time_t fileTime = fileStat.st_mtime;
183
184 // Read first 8 bytes of file
185 std::ifstream file(filename, std::ios::binary);
186 std::vector<char> buffer(8);
187 file.read(buffer.data(), 8);
188
189 // Hash file name, size, time, and header info
190 std::string fileHeader(buffer.begin(), buffer.end());
191 std::stringstream ss;
192 ss << fileSize << fileTime << fileHeader;
193 std::string fileString = filename + ss.str();
194 std::size_t fileHash = std::hash<std::string>{}(fileString);
195
196 return {fileHash, ""};
197 }
198
206 std::string getContent(const std::string &key) {
207 auto target_cache_file_path =
208 cache_store_path + std::filesystem::path::preferred_separator + key;
209 return read_file_content(target_cache_file_path);
210 }
211
212private:
213 std::string cache_store_path;
214
215 bool initialized = false;
216
217 bool initialization_checked = false;
218
224 std::size_t stringToSize_t(std::string str) {
225 std::stringstream sstream(str);
226 size_t result;
227 sstream >> result;
228 return result;
229 }
230
237 bool createCacheFile(const std::string &filename,
238 const std::string &content = "") {
239 std::string file_path = cache_store_path +
240 std::filesystem::path::preferred_separator +
241 filename;
242
243 std::ofstream file(file_path);
244 file << content;
245 file.close();
246
247 return file.good();
248 }
249
259 bool fileExists(const std::string &path) {
260 return std::filesystem::exists(path);
261 }
262
270 bool createDir(const std::string &path) {
271 if (!std::filesystem::exists(path))
272 return std::filesystem::create_directories(path);
273 else
274 return false;
275 }
276
285 std::string read_file_content(const std::string &filename) {
286 std::ifstream file(filename);
287 if (!file.is_open()) {
288 // handle error
289 return "";
290 }
291 std::string content((std::istreambuf_iterator<char>(file)),
292 (std::istreambuf_iterator<char>()));
293 return content;
294 }
295
301 void initCheck() {
302 if (initialization_checked == false) {
303 throw std::runtime_error("Initialization checks were not performed, did "
304 "you forgot calling Cachier::isInitialized "
305 "before using the library?");
306 }
307 }
308};
309
310#endif // CACHIER_H
The Cachier class.
Definition: cachier.h:20
bool cacheExists(const std::size_t &key)
cacheExists
Definition: cachier.h:117
Cachier(const std::string &cache_store_path, bool ensure_cache_store_path=true)
Cachier.
Definition: cachier.h:44
std::string getContent(const std::string &key)
getContent
Definition: cachier.h:206
CacheOverwriteOption
The CacheOverwriteOption enum.
Definition: cachier.h:25
HashResult addCache(const std::string &filename, const std::string &content="", const CacheOverwriteOption &cache_overwrite_option=DONT_OVERWRITE_CACHE)
addCache
Definition: cachier.h:81
bool isInitialized()
isInitialized
Definition: cachier.h:153
HashResult computeHash(const std::string &filename)
computeHash
Definition: cachier.h:170
bool cacheExists(const std::string &filename)
cacheExists
Definition: cachier.h:134
The HashResult class.
Definition: cachier.h:31