parent
eab4b33a9a
commit
dd15ad3295
@ -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 */
|
@ -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 <fsvec.hpp>
|
||||||
|
#include <uuid.hpp>
|
||||||
|
#include <fsvec.h>
|
||||||
|
|
||||||
#define FB file_back_buffer
|
#define FB file_back_buffer
|
||||||
using std::size_t;
|
using std::size_t;
|
||||||
|
namespace fs = std::filesystem;
|
||||||
|
|
||||||
|
/// A temporary file name
|
||||||
struct temp_file
|
struct temp_file
|
||||||
{
|
{
|
||||||
inline temp_file()
|
|
||||||
{
|
|
||||||
// Create random new file
|
|
||||||
}
|
|
||||||
inline temp_file(const temp_file& c) = delete;
|
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(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:
|
inline const fs::path* operator->() const { return &full_path(); }
|
||||||
const char* name;
|
private:
|
||||||
|
std::string name;
|
||||||
|
mutable fs::path _full_path;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct FB::impl
|
struct FB::impl
|
||||||
{
|
{
|
||||||
size_t cap;
|
size_t cap;
|
||||||
temp_file file;
|
temp_file file;
|
||||||
|
|
||||||
|
fvec_t backing;
|
||||||
|
|
||||||
|
inline ~impl()
|
||||||
|
{
|
||||||
|
fvec_close(&backing);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
FB::FB(size_t cap) : inner(std::make_unique<FB::impl>())
|
FB::FB(size_t cap) : inner(std::make_unique<FB::impl>())
|
||||||
{
|
{
|
||||||
// Set cap
|
// Set cap
|
||||||
inner->cap = 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){}
|
FB::FB() : FB(DEFAULT_CAP){}
|
||||||
|
|
||||||
void FB::push_buf(byte* buf, size_t len)
|
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;
|
return !!fvec_pop_end(&inner->backing, len);
|
||||||
}
|
|
||||||
|
|
||||||
void FB::pop_n(size_t len)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue