245 lines
6.5 KiB
C++
245 lines
6.5 KiB
C++
#pragma once
|
|
|
|
#include <vector>
|
|
#include <cassert>
|
|
#include <cstring>
|
|
#include <memory>
|
|
|
|
namespace data {
|
|
|
|
/// Map vector to istream
|
|
struct vec_istream: std::streambuf {
|
|
vec_istream(const std::vector<char> &vec) {
|
|
this->setg((char*)&vec[0], (char*)&vec[0], (char*)&vec[0] + vec.size());
|
|
}
|
|
};
|
|
|
|
/// Abstract data with moving cursor
|
|
struct view {
|
|
view(size_t size): siz(size) { }
|
|
|
|
size_t siz;
|
|
size_t cur = 0;
|
|
|
|
constexpr size_t size() const { return siz; }
|
|
constexpr bool isDone() const { return cur >= siz; }
|
|
};
|
|
// Abstract data writer
|
|
struct in_view: view {
|
|
in_view(uint8_t *ptr, size_t size): view(size), ptr(ptr) {
|
|
assert(ptr != nullptr);
|
|
}
|
|
|
|
uint8_t* ptr;
|
|
uint8_t* writeTo(size_t len) {
|
|
assert(cur + len <= siz);
|
|
auto p = ptr + cur;
|
|
cur += len;
|
|
return p;
|
|
}
|
|
void write(const uint8_t* data, size_t len) {
|
|
memcpy(writeTo(len), data, len);
|
|
}
|
|
};
|
|
/// Writer with Dynamic allocation and subparts
|
|
struct in_writer: public in_view {
|
|
private:
|
|
static constexpr auto EMPTY_OFFSET = 0x1000;
|
|
static uint8_t* alloc(size_t size) { return (uint8_t*)(size > 0 ? ::malloc(size) : reinterpret_cast<uint8_t*>(EMPTY_OFFSET)); }
|
|
static uint8_t* realloc(uint8_t* ptr, size_t size) { return (uint8_t*)::realloc(ptr, size); }
|
|
static void free(uint8_t* ptr) { ::free(ptr); }
|
|
|
|
inline void auto_size(size_t len) {
|
|
if (cur + len > siz)
|
|
resize(cur + len);
|
|
}
|
|
|
|
public:
|
|
in_writer(size_t init_size = 0): in_view(alloc(init_size), init_size), vis_siz(init_size) { }
|
|
~in_writer() { if (ptr != reinterpret_cast<uint8_t*>(EMPTY_OFFSET)) free(ptr); }
|
|
|
|
size_t vis_siz = 0;
|
|
|
|
uint8_t* data() { return ptr; }
|
|
constexpr size_t size() const { return vis_siz; }
|
|
|
|
void write(const void* data, size_t len) {
|
|
in_view::write((uint8_t*)data, len);
|
|
}
|
|
/// Write without resize
|
|
template<typename D>
|
|
void write(const D& d) {
|
|
write(&d, sizeof(d));
|
|
}
|
|
|
|
uint8_t* pushTo(size_t len) {
|
|
auto_size(len);
|
|
return writeTo(len);
|
|
}
|
|
void push(const void* data, size_t len) {
|
|
auto_size(len);
|
|
in_view::write((uint8_t*)data, len);
|
|
}
|
|
template<typename D>
|
|
void push(const D& d) {
|
|
push(&d, sizeof(d));
|
|
}
|
|
|
|
size_t getCursor() const { return cur; }
|
|
void writeAt(size_t pos, const void* data, size_t len) {
|
|
assert(pos + len <= vis_siz);
|
|
memcpy(ptr + pos, data, len);
|
|
}
|
|
template<typename D>
|
|
void writeAt(size_t pos, const D& d) {
|
|
writeAt(pos, &d, sizeof(d));
|
|
}
|
|
|
|
void reserve(size_t target) {
|
|
if (target >= siz) {
|
|
ptr = realloc(ptr, target);
|
|
siz = target;
|
|
}
|
|
}
|
|
void resize(size_t target) {
|
|
reserve(target);
|
|
vis_siz = target;
|
|
}
|
|
|
|
bool isFull() const {
|
|
return cur >= vis_siz;
|
|
}
|
|
|
|
// Must take ptr ownership before
|
|
void reset() {
|
|
ptr = reinterpret_cast<uint8_t*>(EMPTY_OFFSET);
|
|
cur = 0;
|
|
siz = 0;
|
|
vis_siz = 0;
|
|
}
|
|
|
|
struct part {
|
|
part(in_writer* parent): up(parent), start(parent->cur) { }
|
|
in_writer* up;
|
|
size_t start;
|
|
|
|
uint8_t* data() { return up->data() + start; }
|
|
constexpr size_t size() const { return up->size() - start; }
|
|
|
|
void reserve(size_t size) {
|
|
up->reserve(start + size);
|
|
}
|
|
void resize(size_t size) {
|
|
up->resize(start + size);
|
|
}
|
|
};
|
|
template<typename CB>
|
|
size_t pushPart(const CB& callback) {
|
|
const auto prev = cur;
|
|
callback(part(this));
|
|
cur = vis_siz;
|
|
return cur - prev;
|
|
}
|
|
template<typename CB>
|
|
size_t pushSizedPart(const CB& callback) {
|
|
const auto size_cur = cur;
|
|
push<size_t>(0);
|
|
const size_t size = pushPart(callback);
|
|
writeAt(size_cur, size);
|
|
return size;
|
|
}
|
|
};
|
|
/// Vector with in_view interface
|
|
struct in_vector {
|
|
/// 512 Mébibits
|
|
static constexpr size_t MAX_SIZE = 1ul << 26;
|
|
|
|
in_vector(size_t max_size = MAX_SIZE): max_size(max_size) {}
|
|
|
|
std::vector<uint8_t> data;
|
|
size_t max_size;
|
|
|
|
uint8_t* writeTo(size_t len) {
|
|
const auto offset = data.size();
|
|
assert(offset + len <= max_size);
|
|
data.resize(offset + len);
|
|
return data.data() + offset;
|
|
}
|
|
void write(const uint8_t* data, size_t len) {
|
|
memcpy(writeTo(len), data, len);
|
|
}
|
|
};
|
|
/// Abstract data reader
|
|
struct out_view: view {
|
|
out_view(): out_view(nullptr, 0) { }
|
|
out_view(const uint8_t *ptr, size_t size): view(size), ptr(ptr) { }
|
|
|
|
const uint8_t* ptr;
|
|
const uint8_t* readFrom(size_t len) {
|
|
assert(cur + len <= siz);
|
|
auto p = ptr + cur;
|
|
cur += len;
|
|
return p;
|
|
}
|
|
void read(uint8_t* out, size_t len) {
|
|
memcpy(out, readFrom(len), len);
|
|
}
|
|
|
|
constexpr const uint8_t* data() const { return ptr; }
|
|
constexpr size_t remaining() const { return size() - cur; }
|
|
};
|
|
/// Helper to read from out_view
|
|
struct out_reader: public out_view {
|
|
out_reader(const out_view& buf): out_view(buf.ptr, buf.siz) { cur = buf.cur; }
|
|
|
|
template<typename D>
|
|
const D* read() {
|
|
return cur + sizeof(D) <= size() ?
|
|
(const D*)readFrom(sizeof(D)) : nullptr;
|
|
}
|
|
template<typename D>
|
|
bool read(D& out) {
|
|
const auto ptr = read<D>();
|
|
if (ptr == nullptr)
|
|
return false;
|
|
|
|
out = *ptr;
|
|
return true;
|
|
}
|
|
|
|
bool skip(size_t size) {
|
|
readFrom(size);
|
|
return !isDone();
|
|
}
|
|
|
|
data::out_view readPart(size_t size) {
|
|
return data::out_view(readFrom(size), size);
|
|
}
|
|
data::out_view readSizedPart() {
|
|
size_t size = 0;
|
|
read(size);
|
|
return readPart(size);
|
|
}
|
|
data::out_view readRemaining() {
|
|
return readPart(remaining());
|
|
}
|
|
};
|
|
/// Pointer to opaque owned memory
|
|
using handle_t = std::shared_ptr<const void>;
|
|
/// out_view with owned data
|
|
struct out_buffer: out_view {
|
|
out_buffer(): out_view() { }
|
|
out_buffer(const out_view& view, const handle_t& handle):
|
|
out_view(view), handle(handle) { }
|
|
/// Take view ownership
|
|
out_buffer(const out_view& view):
|
|
out_buffer(view, std::shared_ptr<const void>(view.ptr)) { }
|
|
/// Take ptr ownership
|
|
out_buffer(const uint8_t *ptr, size_t size): out_buffer(out_view(ptr, size)) { }
|
|
/// Take ptr ownership (release writer)
|
|
out_buffer(in_writer& writer):
|
|
out_buffer(writer.data(), writer.size()) { writer.reset(); }
|
|
|
|
handle_t handle = nullptr;
|
|
};
|
|
} |