progress
Avril 4 years ago
parent eab4b33a9a
commit dd15ad3295
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -0,0 +1,31 @@
#ifndef _FSVEC_H
#define _FSVEC_H
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#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 */

@ -3,6 +3,7 @@
#include <cstdint>
#include <memory>
#include <utility>
#include <vector>
#include <panic.h>
@ -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<typename T>
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<T>& c) = delete;
inline file_vector(file_vector<T>&& m) : inserter(std::move(m.inserter)), len(m.len) {}
inline file_vector(file_vector<T>&& 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(&current_back[0], sizeof(T))) panic("back() failed");
return *_die_if_null((T*)&current_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(&current_back[0], sizeof(T))) panic("back() failed");
return *_die_if_null((const T*)&current_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<unsigned char> current_back; // what an awful hack...
file_back_buffer inserter;
std::uint64_t len;
};

@ -0,0 +1,31 @@
#pragma once
#include <random>
#include <string>
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<int> dist(0, 15);
constexpr const char hex[] = "0123456789abcdef";
uuid id;
for(int i=0;i<SIZE;i++) id.str[i] = hex[dist(rng)];
id.str[SIZE] =0;
return id;
}
inline operator const char*() const { return &str[0]; }
inline operator const std::array<char, SIZE+1>&() const { return str; }
inline std::string to_string() const
{
return std::string(&str[0]);
}
private:
inline uuid(){}
std::array<char, SIZE+1> str;
};

@ -0,0 +1,67 @@
#include <unistd.h>
#include <fsvec.h>
#include <panic.h>
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 ( w<sz && (c=fwrite(buffer+w, 1, sz-w, obj->backing))>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;
}

@ -1,57 +1,73 @@
#include <filesystem>
#include <fsvec.hpp>
#include <uuid.hpp>
#include <fsvec.h>
#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; }
inline const fs::path* operator->() const { return &full_path(); }
private:
const char* name;
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<FB::impl>())
{
// 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);
}

Loading…
Cancel
Save