#include <map>
#include <cstring>
#include <fstream>
#include <sstream>
#include <iostream>
#include <future>
struct AsyncFileReader {
private:
std::string cache;
int cacheOffset;
bool hasCache;
std::function<void(std::string_view)> pendingReadCb;
int fileSize;
std::string fileName;
std::ifstream fin;
uWS::Loop *loop;
public:
AsyncFileReader(std::string fileName) : fileName(fileName) {
fin.open(fileName, std::ios::binary);
fin.seekg(0, fin.end);
fileSize = fin.tellg();
cache.resize(1024 * 1024);
fin.seekg(0, fin.beg);
fin.read(cache.data(), cache.length());
cacheOffset = 0;
hasCache = true;
loop = uWS::Loop::get();
}
std::string_view peek(int offset) {
if (hasCache && offset >= cacheOffset && ((offset - cacheOffset) < cache.length())) {
int chunkSize = std::min<int>(fileSize - offset, cache.length() - offset + cacheOffset);
return std::string_view(cache.data() + offset - cacheOffset, chunkSize);
} else {
return std::string_view(nullptr, 0);
}
}
void request(int offset, std::function<void(std::string_view)> cb) {
if (!hasCache) {
std::cout << "ERROR: already requesting a chunk!" << std::endl;
return;
}
hasCache = false;
std::async(std::launch::async, [this, cb, offset]() {
if (!fin.good()) {
fin.close();
fin.open(fileName, std::ios::binary);
}
fin.seekg(offset, fin.beg);
fin.read(cache.data(), cache.length());
cacheOffset = offset;
loop->defer([this, cb, offset]() {
int chunkSize = std::min<int>(cache.length(), fileSize - offset);
if (chunkSize == 0) {
std::cout << "Zero size!?" << std::endl;
}
if (chunkSize != cache.length()) {
std::cout << "LESS THAN A CACHE 1 MB!" << std::endl;
}
hasCache = true;
cb(std::string_view(cache.data(), chunkSize));
});
});
}
void abort() {
}
int getFileSize() {
return fileSize;
}
};