VoxelEngine/src/io/memory_ostream.hpp
2025-03-20 22:04:29 +03:00

106 lines
2.7 KiB
C++

#include <iostream>
#include <streambuf>
#include <cstring>
#include <algorithm>
#include <string_view>
#include "util/Buffer.hpp"
class memory_buffer : public std::streambuf {
public:
explicit memory_buffer(size_t initial_size = 64)
: buffer(std::make_unique<char[]>(initial_size)),
capacity(initial_size) {
setp(buffer.get(), buffer.get() + initial_size);
}
std::string_view view() const {
return std::string_view(pbase(), pptr() - pbase());
}
util::Buffer<char> release() {
return {std::move(buffer), size()};
}
size_t size() const {
return pptr() - pbase();
}
protected:
int_type overflow(int_type c) override {
if (c == traits_type::eof())
return traits_type::eof();
const size_t data_size = pptr() - pbase();
const size_t new_capacity = std::max(capacity * 2, data_size + 1);
auto new_buffer = std::make_unique<char[]>(new_capacity);
std::memcpy(new_buffer.get(), pbase(), data_size);
buffer = std::move(new_buffer);
capacity = new_capacity;
setp(buffer.get(), buffer.get() + new_capacity);
pbump(data_size);
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
std::streamsize xsputn(const char* s, std::streamsize count) override {
const std::streamsize avail = epptr() - pptr();
if (avail >= count) {
std::memcpy(pptr(), s, count);
pbump(count);
return count;
}
std::streamsize written = 0;
if (avail > 0) {
std::memcpy(pptr(), s, avail);
written += avail;
s += avail;
count -= avail;
pbump(avail);
}
const size_t data_size = pptr() - pbase();
const size_t required_capacity = data_size + count;
const size_t new_capacity = std::max(capacity * 2, required_capacity);
auto new_buffer = std::make_unique<char[]>(new_capacity);
std::memcpy(new_buffer.get(), pbase(), data_size);
std::memcpy(new_buffer.get() + data_size, s, count);
buffer = std::move(new_buffer);
capacity = new_capacity;
setp(buffer.get(), buffer.get() + new_capacity);
pbump(data_size + count);
written += count;
return written;
}
private:
std::unique_ptr<char[]> buffer;
size_t capacity;
};
class memory_ostream : public std::ostream {
public:
explicit memory_ostream(size_t initialCapacity = 64)
: std::ostream(&buffer), buffer(initialCapacity) {}
std::string_view view() const {
return buffer.view();
}
util::Buffer<char> release() {
return buffer.release();
}
private:
memory_buffer buffer;
};