Created
December 5, 2020 19:12
-
-
Save oliverlee/651c49840f7301a4148d0ee40a867ebb to your computer and use it in GitHub Desktop.
array backed streambuf
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <array> | |
#include <cstdio> | |
#include <cstdlib> | |
#include <iostream> | |
#include <new> | |
#include <sstream> | |
#include <vector> | |
namespace { | |
template <std::size_t N> | |
struct output_arraybuf : std::streambuf { | |
using base_type = std::streambuf; | |
using char_type = typename base_type::char_type; | |
using int_type = typename base_type::int_type; | |
static constexpr auto capacity = N; | |
output_arraybuf(std::ostream& os = std::cout) : output_sink_{os} { | |
// Reserve the last character for null-termination, which is necessary in case of overflow. | |
setp(buffer_.begin(), buffer_.end() - 1); | |
} | |
~output_arraybuf() { | |
std::cout << "[output_arraybuf::~output_arraybuf()]" << std::endl; | |
sync(); | |
} | |
auto sink() -> std::ostream& { return output_sink_; } | |
protected: | |
auto overflow(int_type ch) -> int_type override { | |
static constexpr auto not_eof = char_type{}; | |
commit(); | |
sputc(ch); | |
return not_eof; | |
} | |
auto sync() -> int override { | |
sputc(0); | |
commit(); | |
output_sink_.flush(); | |
return 0; | |
} | |
private: | |
auto commit() -> void { | |
const auto n = pptr() - pbase(); | |
output_sink_.write(pbase(), n); | |
pbump(-n); | |
} | |
std::array<base_type::char_type, N> buffer_ = {}; | |
std::ostream& output_sink_; | |
}; | |
struct output_stringbuf : std::stringbuf { | |
using base_type = std::stringbuf; | |
using char_type = typename base_type::char_type; | |
using int_type = typename base_type::int_type; | |
output_stringbuf(std::ostream& os = std::cout) : output_sink_{os} {} | |
~output_stringbuf() { | |
std::cout << "[output_stringbuf::~output_stringbuf()]" << std::endl; | |
sync(); | |
} | |
auto sink() -> std::ostream& { return output_sink_; } | |
protected: | |
auto sync() -> int override { | |
const auto n = pptr() - pbase(); | |
output_sink_.write(pbase(), n); | |
output_sink_.flush(); | |
str(""); | |
return 0; | |
} | |
private: | |
std::ostream& output_sink_; | |
}; | |
template <class Prefix, class OutputStreambuf> | |
struct prefixed_output_buf : OutputStreambuf { | |
using base_type = OutputStreambuf; | |
using char_type = typename base_type::char_type; | |
using int_type = typename base_type::int_type; | |
static constexpr auto prefix_value = Prefix::value; | |
protected: | |
auto overflow(int_type ch) -> int_type override { | |
if (send_prefix_) { | |
this->sink().write(prefix_value, prefix_length); | |
send_prefix_ = false; | |
} | |
return base_type::overflow(ch); | |
} | |
auto sync() -> int override { | |
if (send_prefix_) { | |
this->sink().write(prefix_value, prefix_length); | |
} | |
send_prefix_ = true; | |
return base_type::sync(); | |
} | |
private: | |
static constexpr auto length(const char* s) -> std::size_t { | |
return (*s == 0) ? 0 : length(s + 1) + 1; | |
} | |
static constexpr auto prefix_length = length(prefix_value); | |
bool send_prefix_ = true; | |
}; | |
struct dummy_prefix { | |
static constexpr auto value = "[DUMMY]: "; | |
}; | |
} // namespace | |
auto operator new(std::size_t size) -> void* { | |
if (auto ptr = std::malloc(size)) { | |
std::cout << "[operator::new(" << size << ") -> " << ptr << "]\n"; | |
return ptr; | |
} | |
throw std::bad_alloc{}; | |
} | |
auto operator delete(void* ptr) noexcept -> void { | |
std::cout << "[operator::delete(" << ptr << ")]\n"; | |
std::free(ptr); | |
} | |
int main(int, char**) { | |
std::cout << "[info] creating stream" << std::endl; | |
// auto buf = output_stringbuf{}; | |
// auto buf = prefixed_output_buf<dummy_prefix, output_stringbuf>{}; | |
// auto buf = output_arraybuf<8>{}; | |
auto buf = prefixed_output_buf<dummy_prefix, output_arraybuf<8>>{}; | |
auto os = std::ostream{&buf}; | |
std::cout << "[info] writing to stream" << std::endl; | |
os << "Here is a very long string that would normally result in allocation!" << std::endl; | |
std::cout << "[info] done!" << std::endl; | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment