You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
shuffle3/include/fsvec.hpp

164 lines
4.2 KiB

4 years ago
#pragma once
#include <cstdint>
4 years ago
#include <cstddef>
4 years ago
#include <memory>
#include <utility>
4 years ago
#include <vector>
4 years ago
#include <panic.h>
4 years ago
#include <debug.h>
#include <shuffle3.h>
4 years ago
4 years ago
template<typename T>
struct i_back_inserter
{
virtual void push_back(T&& value) =0;
virtual void pop_back() =0;
virtual const T& back() const =0;
virtual T& back() =0;
virtual const std::size_t size() const =0;
4 years ago
inline bool is_empty() const { return size()==0; }
4 years ago
virtual inline ~i_back_inserter() =default;
};
4 years ago
struct file_back_buffer
{
const static constexpr std::size_t DEFAULT_CAP = 1024;
typedef std::uint8_t byte;
file_back_buffer();
file_back_buffer(std::size_t cap);
file_back_buffer(const file_back_buffer& c) = delete;
file_back_buffer(file_back_buffer&& m);
4 years ago
void push_buf(byte* buf, std::size_t len);
4 years ago
bool back(byte* buf, std::size_t len) const;
bool pop_n(std::size_t len);
4 years ago
~file_back_buffer();
private:
struct impl;
std::unique_ptr<impl> inner;
};
namespace {
template<typename T>
inline const T* _die_if_null(const T* input, const char* msg)
{
if(!input) panic(msg);
return input;
}
template<typename T>
inline T* _die_if_null(T* input, const char* msg)
{
if(!input) panic(msg);
return input;
}
}
template<typename T>
4 years ago
struct file_vector : public i_back_inserter<T>
4 years ago
{
4 years ago
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<unsigned char>(sizeof(T))) {current_back.resize(sizeof(T));}
4 years ago
inline file_vector(const file_vector<T>& c) = delete;
4 years ago
inline file_vector(file_vector<T>&& m) : inserter(std::move(m.inserter)), len(m.len), current_back(std::move(m.current_back)){}
4 years ago
4 years ago
inline void push_back(T&& value) override
4 years ago
{
inserter.push_buf((file_back_buffer::byte*)&value, sizeof(T));
len += 1;
}
4 years ago
inline T& back() override
4 years ago
{
if(!len) panic("back() called on empty file_vector");
4 years ago
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");
4 years ago
}
4 years ago
inline const T& back() const override
4 years ago
{
if(!len) panic("back() called on empty file_vector");
4 years ago
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");
4 years ago
}
4 years ago
inline void pop_back() override
4 years ago
{
if(!len) return;
4 years ago
if(!inserter.pop_n(sizeof(T))) panic("pop_back(): 0 elements");
4 years ago
len-=1;
}
4 years ago
inline const std::size_t size() const override { return len; }
4 years ago
private:
file_back_buffer inserter;
4 years ago
std::size_t len=0;
mutable std::vector<unsigned char> current_back; // what an awful hack...
4 years ago
};
4 years ago
4 years ago
template<typename T, std::size_t Spill = FSV_DEFAULT_SPILL_AT >
4 years ago
requires (Spill > 0)
struct fixed_spill_vector : public i_back_inserter<T>
{
constexpr const static std::size_t SPILL_AT = Spill;
4 years ago
inline fixed_spill_vector() : mem(std::make_unique<std::array<T, Spill> >()){}
4 years ago
inline fixed_spill_vector(const fixed_spill_vector<T>& c) = delete;
inline fixed_spill_vector(fixed_spill_vector<T>&& m)
: mem(std::move(m.mem)),
mem_fill_ptr(m.mem_fill_ptr),
fil(std::move(m.fil))
{}
4 years ago
inline ~fixed_spill_vector() = default;
4 years ago
inline void push_back(T&& value) override
{
4 years ago
if(mem_is_full()) {
//D_dprintf("Inserting value into fs");
fil.push_back(std::move(value));
} else {
//D_dprintf("Inserting value into memory");
(*mem)[++mem_fill_ptr] = value;
}
4 years ago
}
inline void pop_back() override
{
4 years ago
if(!size()) return;
if(fil.size()) {
//D_dprintf("Popping from fs");
fil.pop_back();
} else {
//D_dprintf("Popping from memory %ld", mem_fill_ptr);
mem_fill_ptr -= 1;
}
4 years ago
}
inline const T& back() const override
4 years ago
{
if (!size()) panic("back() (const) called on no elements");
if(fil.size()) return fil.back();
else return (*mem)[mem_fill_ptr];
4 years ago
}
inline T& back() override
{
4 years ago
if (!size()) panic("back() called on no elements");
if(fil.size()) return fil.back();
else return (*mem)[mem_fill_ptr];
4 years ago
}
inline const std::size_t size() const override
{
4 years ago
return fil.size() + (std::size_t)(mem_fill_ptr+1);
4 years ago
}
private:
4 years ago
inline bool mem_is_full() const { return mem_fill_ptr >= (ssize_t)(Spill-1); }
ssize_t mem_fill_ptr=-1;
4 years ago
4 years ago
std::unique_ptr<std::array<T, Spill>> mem;
4 years ago
file_vector<T> fil;
};