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.