diff --git a/include/fsvec.h b/include/fsvec.h new file mode 100644 index 0000000..87756a7 --- /dev/null +++ b/include/fsvec.h @@ -0,0 +1,31 @@ +#ifndef _FSVEC_H +#define _FSVEC_H + +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#define restrict __restrict__ +#endif + +// A simple file-backed back inserter +typedef struct { + FILE* backing; + size_t len; +} fvec_t; + +int fvec_new(fvec_t* restrict obj, const char* path); +void fvec_close(fvec_t* restrict obj); + +int fvec_pop_end(fvec_t* restrict obj, size_t sz); +void fvec_push_whole_buffer(fvec_t* restrict obj, const void* _buffer, size_t sz); +int fvec_get_whole_buffer(const fvec_t* restrict obj, void* _buffer, size_t _sz); + +#ifdef __cplusplus +#undef restrict +} +#endif + +#endif /* _FSVEC_H */ diff --git a/include/fsvec.hpp b/include/fsvec.hpp index 48fd2e5..c2a603f 100644 --- a/include/fsvec.hpp +++ b/include/fsvec.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include @@ -17,9 +18,8 @@ struct file_back_buffer inline file_back_buffer(file_back_buffer&& m) : inner(std::move(m.inner)){} void push_buf(byte* buf, std::size_t len); - byte* back(std::size_t len); - const byte* back(std::size_t len) const; - void pop_n(std::size_t len); + bool back(byte* buf, std::size_t len) const; + bool pop_n(std::size_t len); ~file_back_buffer(); private: @@ -45,10 +45,10 @@ namespace { template struct file_vector { - inline file_vector(){} - inline file_vector(std::size_t cap) : inserter(file_back_buffer(cap)), len(0) {} + inline file_vector() : file_vector(file_back_buffer::DEFAULT_CAP){} + inline file_vector(std::size_t cap) : inserter(file_back_buffer(cap)), len(0), current_back(std::vector(sizeof(T))) {current_back.resize(sizeof(T));} inline file_vector(const file_vector& c) = delete; - inline file_vector(file_vector&& m) : inserter(std::move(m.inserter)), len(m.len) {} + inline file_vector(file_vector&& m) : inserter(std::move(m.inserter)), len(m.len), current_back(std::move(m.current_back)){} inline void push_back(T&& value) { @@ -58,21 +58,24 @@ struct file_vector inline T& back() { if(!len) panic("back() called on empty file_vector"); - return *_die_if_null((T*)inserter.back(sizeof(T)), "file_vector::back() returned null pointer"); + if(!inserter.back(¤t_back[0], sizeof(T))) panic("back() failed"); + return *_die_if_null((T*)¤t_back[0], "file_vector::back() returned null pointer"); } inline const T& back() const { if(!len) panic("back() called on empty file_vector"); - return *_die_if_null((const T*)inserter.back(sizeof(T)), "file_vector::back() (const) returned null pointer"); + if(!inserter.back(¤t_back[0], sizeof(T))) panic("back() failed"); + return *_die_if_null((const T*)¤t_back[0], "file_vector::back() (const) returned null pointer"); } inline void pop_back() { if(!len) return; - inserter.pop_n(sizeof(T)); + if(!inserter.pop_n(sizeof(T))) panic("pop_back(): 0 elements"); len-=1; } private: + mutable std::vector current_back; // what an awful hack... file_back_buffer inserter; std::uint64_t len; }; diff --git a/include/uuid.hpp b/include/uuid.hpp new file mode 100644 index 0000000..5331ccc --- /dev/null +++ b/include/uuid.hpp @@ -0,0 +1,31 @@ +#pragma once + +#include +#include + +struct uuid //not to spec but idc +{ + const static constexpr int SIZE=16; + inline static uuid generate() + { + using namespace std; + static thread_local random_device dev; + static thread_local mt19937 rng(dev()); + uniform_int_distribution dist(0, 15); + constexpr const char hex[] = "0123456789abcdef"; + uuid id; + for(int i=0;i&() const { return str; } + + inline std::string to_string() const + { + return std::string(&str[0]); + } +private: + inline uuid(){} + std::array str; +}; diff --git a/src/fsvec.c b/src/fsvec.c new file mode 100644 index 0000000..ed4a4bc --- /dev/null +++ b/src/fsvec.c @@ -0,0 +1,67 @@ +#include +#include +#include + +int fvec_new(fvec_t* restrict obj, const char* path) +{ + obj->backing = fopen(path, "wb"); + if(!obj->backing) { + perror("fvec_new(): Failed to open file"); + return 0; + } + obj->len=0; + return 1; +} + +void fvec_close(fvec_t* restrict obj) +{ + if(obj->backing) fclose(obj->backing); + obj->backing=NULL; + obj->len=0; +} + +int fvec_pop_end(fvec_t* restrict obj, size_t sz) +{ + if(!obj->len) return 0; + + if(ftruncate(fileno(obj->backing), (obj->len-=sz))<0) { + perror("Failed to pop buffer"); + return 0; + } + return 1; +} + +void fvec_push_whole_buffer(fvec_t* restrict obj, const void* _buffer, size_t sz) +{ + size_t w= 0; + size_t c; + const unsigned char* buffer = _buffer; + while ( wbacking))>0 ) w+=c; + if(w!=sz) { + perror("Corrupted buffer state, aborting"); + panic("Cannot continue"); + } + obj->len += sz; +} +int fvec_get_whole_buffer(const fvec_t* restrict obj, void* _buffer, size_t _sz) +{ + ssize_t sz = (ssize_t)_sz; + if(_sz != (size_t)sz) panic("Buffer size %lu too large", _sz); + + if(obj->len<(size_t)sz) return 0; + if(fseek(obj->backing, -sz, SEEK_END)<0) { + perror("fvec_get_whole_buffer() failed to seek"); + return 0; + } + + size_t w=0; + ssize_t c; + unsigned char* buffer = _buffer; + while ( w<_sz && (c=fread(buffer+w, 1, sz-w, obj->backing))>0 ) w+=c; + if (w!=_sz) { + perror("Corrupted buffer state, aborting"); + panic("Cannot continue"); + } + + return 1; +} diff --git a/src/fsvec.cpp b/src/fsvec.cpp index 2811afd..365fd97 100644 --- a/src/fsvec.cpp +++ b/src/fsvec.cpp @@ -1,57 +1,73 @@ +#include + #include +#include +#include #define FB file_back_buffer using std::size_t; +namespace fs = std::filesystem; +/// A temporary file name struct temp_file { - inline temp_file() - { - // Create random new file - } inline temp_file(const temp_file& c) = delete; - inline temp_file(temp_file&& m) : name(m.name) { m.name= nullptr; } + + inline temp_file(temp_file&& m) : name(std::move(m.name)) {} + inline temp_file() : name(uuid::generate().to_string()){} inline temp_file(const char* name) : name(name) {} - inline ~temp_file() + inline temp_file(std::string&& name) : name(name) {} + + inline ~temp_file() = default; + + inline const fs::path& full_path() const { - if(name) name = nullptr; + if(_full_path.empty()) + _full_path = fs::canonical( fs::temp_directory_path() / name ); + return _full_path; } + inline const std::string& base_name() const { return name; } -private: - const char* name; + inline const fs::path* operator->() const { return &full_path(); } +private: + std::string name; + mutable fs::path _full_path; }; struct FB::impl { size_t cap; temp_file file; + + fvec_t backing; + + inline ~impl() + { + fvec_close(&backing); + } }; FB::FB(size_t cap) : inner(std::make_unique()) { // Set cap inner->cap = cap; - // Open `inner->file` + // Create then open `inner->file` + if(!fvec_new(&inner->backing, inner->file->c_str())) panic("Failed to open backing for temp file buffer"); } FB::FB() : FB(DEFAULT_CAP){} void FB::push_buf(byte* buf, size_t len) { - + fvec_push_whole_buffer(&inner->backing, (void*)buf, len); } -FB::byte* FB::back(size_t len) +bool FB::back(byte* buf, size_t len) const { - return nullptr; + return !!fvec_get_whole_buffer(&inner->backing, (void*)buf, len); } -const FB::byte* FB::back(size_t len) const +bool FB::pop_n(size_t len) { - return nullptr; -} - -void FB::pop_n(size_t len) -{ - + return !!fvec_pop_end(&inner->backing, len); }