I am writing a plugin in C++ that uses C API that gives me a single logging function with this signature:
typedef void(*println_t)(const char* text);
I want to wrap this type of a function in a nice ostream
to use all C++ formatting features. Having read it is best to use streambuf
for this, I made this code:
//println_buf.h #include <string> #include <sstream> class println_buf : public std::streambuf { typedef void(*println_t)(const char* text); println_t logfunc_; std::string buffer; public: println_buf(println_t logfunc) : logfunc_(logfunc) { } println_buf(const println_buf &) = delete; println_buf(println_buf &&); println_buf& operator=(const println_buf &) = delete; println_buf& operator=(println_buf &&); virtual std::streamsize xsputn(const char* s, std::streamsize n) override; virtual int overflow(int c) override; virtual int sync() override; };
//println_buf.cpp #include "println_buf.h" using namespace std; println_buf::println_buf(println_buf &&o) : logfunc_(o.logfunc_), buffer(std::move(o.buffer)) { } println_buf& println_buf::operator=(println_buf &&o) { logfunc_ = o.logfunc_; buffer = std::move(o.buffer); return *this; } streamsize println_buf::xsputn(const char* s, streamsize n) { streamsize start = 0; for (std::streamsize i = 0; i < n; i++) { if (s[i] == '\n') { buffer.append(s + start, s + i); sync(); start = i + 1; } } buffer.append(s + start, s + n); return n; } int println_buf::overflow(int c) { char ch = traits_type::to_char_type(c); if (ch == '\n') { sync(); } else { buffer.append(1, c); } return c; } int println_buf::sync() { logfunc_(buffer.c_str()); buffer.clear(); return 0; }
Usage:
println_t logfunc = ...; println_buf buffer(logfunc); std::ostream stream(&buffer); stream << "Hello world" << std::endl;
It should be noted that println_t
includes a newline automatically in the actual output, but I want to have to specify the line separator in C++.
My concern is that the function should not be called with a string containing \n
, but the string must be passed to the function only if it originally ended with \n
, and be buffered otherwise. Also endl
should cause the function to be called immediately.