47 static bool store(
const std::vector<T>& data,
const std::string& path)
49 static_assert(std::is_standard_layout_v<T> && std::is_trivial_v<T>,
50 "T must be a POD type for binary serialization.");
59 for(
const auto& dir : searchPaths)
61 fs::path fullPath = fs::path(dir) / filename;
62 if(fs::exists(fullPath))
69 fs::path dirPath(cacheDir);
72 fs::create_directories(dirPath);
73 fs::path fullPath = dirPath / filename;
83 fs::path tempDirPath(tempDir);
86 fs::create_directories(tempDirPath);
87 fs::path fullPath = tempDirPath / filename;
123 HANDLE hFile = CreateFileA(fullPath.string().c_str(), GENERIC_READ | GENERIC_WRITE,
124 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_ALWAYS,
125 FILE_ATTRIBUTE_NORMAL, NULL);
126 if(hFile == INVALID_HANDLE_VALUE)
129 OVERLAPPED overlapped = {};
130 BOOL locked = LockFileEx(hFile, LOCKFILE_EXCLUSIVE_LOCK, 0, MAXDWORD, 0, &overlapped);
137 LARGE_INTEGER fileSize = {};
138 GetFileSizeEx(hFile, &fileSize);
139 if(fileSize.QuadPart >=
sizeof(
size_t))
141 UnlockFileEx(hFile, 0, MAXDWORD, 0, &overlapped);
147 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
149 size_t vecSize = data.size();
150 WriteFile(hFile, &vecSize,
sizeof(vecSize), &bytesWritten, NULL);
153 WriteFile(hFile, data.data(),
static_cast<DWORD
>(
sizeof(T) * vecSize), &bytesWritten, NULL);
157 UnlockFileEx(hFile, 0, MAXDWORD, 0, &overlapped);
161 int fd = ::open(fullPath.string().c_str(), O_RDWR | O_CREAT, 0666);
165 if(::flock(fd, LOCK_EX) == -1)
172 if(::fstat(fd, &st) == -1)
174 ::flock(fd, LOCK_UN);
179 if(st.st_size >=
sizeof(
size_t))
181 ::flock(fd, LOCK_UN);
186 ::lseek(fd, 0, SEEK_SET);
187 size_t vecSize = data.size();
188 if(
::write(fd, &vecSize,
sizeof(vecSize)) !=
sizeof(vecSize))
190 ::flock(fd, LOCK_UN);
196 if(
::write(fd, data.data(),
sizeof(T) * vecSize) !=
static_cast<ssize_t
>(
sizeof(T) * vecSize))
198 ::flock(fd, LOCK_UN);
203 ::ftruncate(fd,
sizeof(vecSize) +
sizeof(T) * vecSize);
205 ::flock(fd, LOCK_UN);
215 CreateFileA(fullPath.string().c_str(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
216 NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
217 if(hFile == INVALID_HANDLE_VALUE)
220 OVERLAPPED overlapped = {};
221 BOOL locked = LockFileEx(hFile, 0, 0, MAXDWORD, 0, &overlapped);
228 SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
231 if(!ReadFile(hFile, &vecSize,
sizeof(vecSize), &bytesRead, NULL) ||
232 bytesRead !=
sizeof(vecSize))
234 UnlockFileEx(hFile, 0, MAXDWORD, 0, &overlapped);
239 std::vector<T> data(vecSize);
242 if(!ReadFile(hFile, data.data(),
static_cast<DWORD
>(
sizeof(T) * vecSize), &bytesRead, NULL) ||
243 bytesRead !=
static_cast<DWORD
>(
sizeof(T) * vecSize))
245 UnlockFileEx(hFile, 0, MAXDWORD, 0, &overlapped);
251 UnlockFileEx(hFile, 0, MAXDWORD, 0, &overlapped);
255 int fd = ::open(fullPath.string().c_str(), O_RDONLY);
259 if(::flock(fd, LOCK_SH) == -1)
266 ssize_t readn = ::read(fd, &vecSize,
sizeof(vecSize));
267 if(readn !=
sizeof(vecSize))
269 ::flock(fd, LOCK_UN);
274 std::vector<T> data(vecSize);
277 readn = ::read(fd, data.data(),
sizeof(T) * vecSize);
278 if(readn !=
static_cast<ssize_t
>(
sizeof(T) * vecSize))
280 ::flock(fd, LOCK_UN);
286 ::flock(fd, LOCK_UN);
296 auto ftime = fs::last_write_time(path);
297 auto sctp = std::chrono::system_clock::time_point(
298 std::chrono::duration_cast<std::chrono::system_clock::duration>(
299 ftime.time_since_epoch()));
300 return std::chrono::system_clock::to_time_t(sctp);