Browse Source

vfs initial

master
alistair 11 months ago
parent
commit
673b531d40
  1. 6
      source/expected.hpp
  2. 32
      source/random.hpp
  3. 228
      source/vfs.cpp

6
source/expected.hpp

@ -0,0 +1,6 @@ @@ -0,0 +1,6 @@
#pragma once
#include <tl/expected.hpp>
using namespace tl;

32
source/random.hpp

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
#include <optional>
#include <random>
enum random_generator {
INODE,
};
template <auto instance> struct singleton {
std::optional<decltype(instance)> inner;
singleton() {
if (!inner.has_value()) {
inner = instance;
}
}
};
namespace rng {
template <typename T> struct mersenne_rng {
static std::random_device device;
static std::mt19937_64 generator;
mersenne_rng() { generator = std::mt19937_64(device); }
T next() { return generator(); }
};
singleton<mersenne_rng<int64_t>{}> rand;
}; // namespace rng

228
source/vfs.cpp

@ -0,0 +1,228 @@ @@ -0,0 +1,228 @@
#include "expected.hpp"
#include <SDL2/SDL_rwops.h>
#include <filesystem>
#include <fmt/format.h>
#include <gsl/span>
#include <inttypes.h>
#include <optional>
#include <random>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>
namespace vfs {
struct error {
std::string message;
};
struct vfs_mount {};
using vpath = std::string;
enum fnode_type { MOUNT, DIR, DATA, DEV };
struct vfnode {
static std::mt19937_64 gen64;
uint64_t id;
fnode_type type;
vfnode(fnode_type type) : id(gen64()), type(type) {}
vfnode(uint64_t id, fnode_type type) : id(id), type(type) {}
};
template <typename T> struct file_node {
virtual expected<size_t, error> size();
virtual expected<size_t, error> seek_from_end();
virtual expected<size_t, error> seek_from_start();
virtual expected<size_t, error> seek_from_current();
virtual expected<size_t, error> tell();
virtual bool can_read();
virtual bool valid();
virtual bool can_write();
virtual expected<std::vector<T>, error> read();
virtual bool write(std::span<T> data);
virtual bool close();
};
template <typename T> class caching_file : public file_node<T> {
private:
file_node<T> node;
};
template <typename T> class sdl_file_node : public file_node<T> {
private:
SDL_RWops *ops;
const char *last_error = "";
// https://wiki.libsdl.org/SDL2/SDL_RWops
expected<size_t, error> seek_sdl(size_t offset, int whence) {
if (ops == nullptr)
return unexpected(error("Invalid file"));
int ret = ops->seek(ops, offset, RW_SEEK_END);
if (ret == -1) {
last_error = SDL_GetError();
return unexpected(error(fmt::format("Error {}", whence)));
}
}
public:
sdl_file_node(const std::string &path, const std::string &mode) {
ops = SDL_RWFromFile(path.c_str(), mode.c_str());
if (ops == nullptr)
last_error = SDL_GetError();
}
sdl_file_node(const gsl::span<T> &memory) {
// https://wiki.libsdl.org/SDL2/SDL_RWFromMem
ops = SDL_RWFromMem(memory.data(), memory.size_bytes());
if (ops == nullptr)
last_error = SDL_GetError();
}
bool valid() { return ops != nullptr; }
expected<size_t, error> size() {
if (ops == nullptr)
return unexpected(
error(fmt::format("Invalid file {}", std::string(last_error))));
int ret = ops->size(ops);
if (ret == -1) {
last_error = SDL_GetError();
return unexpected(error(fmt::format("Error {}", last_error)));
}
return ret;
}
public:
expected<size_t, error> seek_from_end(size_t offset) {
return seek_sdl(offset, RW_SEEK_END);
}
expected<size_t, error> seek_from_current(size_t offset) {
return seek_sdl(offset, RW_SEEK_CUR);
}
expected<size_t, error> seek_from_start(size_t offset) {
return seek_sdl(offset, RW_SEEK_SET);
}
expected<std::vector<T>, error> read(size_t offset_from_start,
size_t length) {
if (ops == nullptr)
return unexpected(error("Invalid file"));
std::vector<T> chunks{};
chunks.reserve(length);
int chunks_read = ops->read(ops, chunks.data(), sizeof(T), length);
if (chunks_read == 0) {
return unexpected(error("Read error"));
}
// may be less than length
chunks.resize(chunks_read);
auto t = gsl::span(chunks);
return chunks;
}
bool write(std::span<T> elems) {
if (ops == nullptr)
return true;
ops->write(ops, elems.data(), sizeof(T), elems.size());
}
bool close() {
if (ops == nullptr)
return false;
int res = ops->close(ops);
ops = nullptr;
return res;
}
bool can_read() { return ops != nullptr; }
bool can_write() { return ops != nullptr; }
bool eof() { return ops != nullptr; }
};
struct directory {
vfnode node;
std::unordered_map<std::string, vfnode> children;
};
struct fdata {
// read whole file
// refresh cache
// subscribe modify events
// return iterator
vfnode node;
std::vector<unsigned char> read_all();
void write_all(const std::vector<unsigned char> data);
void write_subrange(const std::vector<unsigned char> data,
std::pair<int, int> bounds);
};
struct mount {
std::vector<vfnode> nodes;
std::unordered_map<std::string, vfnode> index;
};
struct directory_mount : public mount {
std::filesystem::path directory;
std::vector<vfnode> nodes;
std::unordered_map<vpath, vfnode> index;
directory_mount(std::filesystem::path directory) : directory(directory) {}
std::optional<vfnode> at(const vpath &location) {
std::filesystem::path loc = directory / location;
// query for known
if (index.contains(location)) {
return index.at(location);
}
// query for existing
if (!std::filesystem::exists(loc)) {
return {};
}
if (std::filesystem::is_directory(loc)) {
nodes.emplace_back(DIR);
index.insert({location, nodes.back()});
return nodes.back();
}
if (std::filesystem::is_regular_file(loc)) {
nodes.emplace_back(DATA);
index.insert({location, nodes.back()});
return nodes.back();
}
return {};
}
void create(const vpath &location) {
auto node = at(location);
if (node.has_value()) {
throw std::runtime_error("Exists");
}
}
void destroy(const vpath &location) {}
};
/**
* Specialisations
*
* - raw directory heirachy
* - #embed files
* - zip file
* - sqlar
*/
}; // namespace vfs
Loading…
Cancel
Save