#include <cstdarg>
#include <cstdio>
#include <string>
#include <unistd.h>
#include <cassert>


class aprintf_class
{
public:
    ~aprintf_class()
    {
        if(audit_length)
            flush();
    }

    void flush()
    {
        write(1,"[debug, calling write():]\n",26);
        write(1,buffer.c_str(),buffer.size());
        buffer.clear();
        audit_length=0;
    }

    aprintf_class &operator()(const char* format, ...)
    {
        assert((buffer.size() == audit_length)
                && "don't have multiple PrintContext active in same thread");

        va_list args4len, args;
        va_start(args, format);
        va_copy(args4len, args); // each va_list can only be used once, so make a copy

        // calculate length of what we want to add to the buffer
        int len = vsnprintf(NULL, 0, format, args4len);
        va_end(args4len);

        // create room for it in the buffer
        int pos = buffer.size();
        buffer.resize(pos + len);
        audit_length += len;

        // add the new data to the buffer
        vsnprintf(buffer.data()+pos,buffer.size()-pos+1,format, args); // +1 because std::string makes room for null terminator
        va_end(args);

        return *this;
    }
private:
    int audit_length = 0;
    inline static thread_local std::string buffer;
};
#define aprintf aprintf_class()


int main()
{
    // simple usage:
    aprintf("Hello, %s! The answer is %d\n", "John", 42);

    // loop usage with scope
    {
        aprintf_class pc;
        pc("First line (blah %g)\n", 47.89);
        for(int i=0;i<2;i++)
            pc("%d\n",i);
        pc("This line should always go with the first one\n");
    } // pc goes out of scope here, which is when it is written

    // or this way w/out loop, but it all could have been one printf() anyway...
    aprintf("one line\n")("and another\n");

    // ok not to wrap with scope as long as you flush()
    aprintf_class pc;
    pc("something new\n");
    pc.flush();
    pc("reuse\n");
    pc.flush();
    aprintf_class pc2;
    pc2("from pc2\n"); // won't see this because we didn't flush() before the crash!

    // demonstrate abuse of the API, which abort()s
    {
        aprintf_class p1, p2;
        p1("to first context\n");
        p2("to second context\n"); // should abort
    }


    return 0;
}

Embed on website

To embed this project on your website, copy the following code and paste it into your website's HTML: