123 lines
4.2 KiB
C++
123 lines
4.2 KiB
C++
/* @file log_streambuf.hpp */
|
|
|
|
#pragma once
|
|
|
|
#include <iostream>
|
|
#include <vector>
|
|
#include <cstring> // e.g. for std::memcpy()
|
|
#include <cstdint>
|
|
#include <cassert>
|
|
|
|
namespace xo {
|
|
/* recycling buffer for logging.
|
|
* write to self-extending storage array;
|
|
*/
|
|
template <typename CharT, typename Traits>
|
|
class log_streambuf : public std::streambuf {
|
|
public:
|
|
log_streambuf(std::uint32_t buf_z) {
|
|
this->buf_v_.resize(buf_z);
|
|
this->reset_stream();
|
|
} /*ctor*/
|
|
|
|
std::streamsize capacity() const { return this->buf_v_.size(); }
|
|
char const * lo() const { return this->pbase(); }
|
|
char const * hi() const { return this->lo() + this->capacity(); }
|
|
std::uint32_t pos() const { return this->pptr() - this->pbase(); }
|
|
|
|
void reset_stream() {
|
|
char * p_lo = &(this->buf_v_[0]);
|
|
char * p_hi = p_lo + this->capacity();
|
|
|
|
/* tells parent our buffer extent */
|
|
this->setp(p_lo, p_hi);
|
|
} /*reset_stream*/
|
|
|
|
protected:
|
|
virtual std::streamsize
|
|
xsputn(char const * s, std::streamsize n) override {
|
|
/* s must be an address in [this->lo() .. this->lo() + capacity()] */
|
|
|
|
assert(this->hi() >= this->pptr());
|
|
|
|
#ifdef NOT_USING_DEBUG
|
|
std::cout << "xsputn: pbase=" << (void *)(this->pbase())
|
|
<< ", pptr=" << (void*)(this->pptr())
|
|
<< "(+" << (this->pptr() - this->lo()) << ")"
|
|
<< ", n=" << n << " -> (+" << (this->pptr() + n - this->lo()) << ")"
|
|
<< ", buf_v.size=" << this->buf_v_.size()
|
|
<< std::endl;
|
|
#endif
|
|
//std::cout << "xsputn: s=" << quot(string_view(s, n)) << ", n=" << n << std::endl;
|
|
|
|
if (this->pptr() + n > this->hi()) {
|
|
n = this->hi() - this->pptr();
|
|
std::memcpy(this->pptr(), s, n);
|
|
} else {
|
|
std::memcpy(this->pptr(), s, n);
|
|
}
|
|
this->pbump(n);
|
|
|
|
return n;
|
|
} /*xsputn*/
|
|
|
|
virtual int_type
|
|
overflow(int_type new_ch) override
|
|
{
|
|
char * old_pptr = this->pptr();
|
|
std::streamsize old_n = old_pptr - this->pbase();
|
|
|
|
assert(old_n <= static_cast<std::streamsize>(this->buf_v_.size()));
|
|
|
|
std::size_t new_z = 2 * this->buf_v_.size();
|
|
|
|
this->buf_v_.resize(new_z);
|
|
this->buf_v_[old_n] = new_ch;
|
|
|
|
/* 'buffered range' will now be .buf_v[old_n .. new_z] */
|
|
char * p_base = &(this->buf_v_[0]);
|
|
//char * p_lo = &(this->buf_v_[old_n+1]);
|
|
char * p_hi = p_base + this->buf_v_.capacity();
|
|
|
|
this->setp(p_base, p_hi);
|
|
this->pbump(old_n + 1); /*see 'this->buf_v_[old_n] - new_ch' above*/
|
|
|
|
return new_ch;
|
|
} /*overflow*/
|
|
|
|
/* off. offset, relative to starting point dir.
|
|
* dir.
|
|
* which. in|out|both
|
|
*/
|
|
virtual pos_type seekoff(off_type off,
|
|
std::ios_base::seekdir dir,
|
|
std::ios_base::openmode which) override {
|
|
//std::cout << "seekoff: off=" << off << ", dir=" << dir << ", which=" << which << std::endl;
|
|
|
|
// Only output stream is supported
|
|
if (which != std::ios_base::out)
|
|
throw std::runtime_error("log_streambuf: only output mode supported");
|
|
|
|
if (dir == std::ios_base::cur) {
|
|
this->pbump(off);
|
|
} else if (dir == std::ios_base::end) {
|
|
/* .setp(): using for side effect: sets .pptr to .pbase */
|
|
this->setp(this->pbase(), this->epptr());
|
|
this->pbump(off);
|
|
} else if (dir == std::ios_base::beg) {
|
|
/* .setp(): using for side effect: sets .pptr to .pbase */
|
|
this->setp(this->pbase(), this->epptr());
|
|
this->pbump(this->capacity() + off);
|
|
}
|
|
|
|
return this->pptr() - this->pbase();
|
|
} /*seekoff*/
|
|
|
|
private:
|
|
/* buffered output stored here */
|
|
std::vector<char> buf_v_;
|
|
}; /*log_streambuf*/
|
|
|
|
} /*namespace xo*/
|
|
|
|
/* end log_streambuf.hpp */
|