An open API service indexing awesome lists of open source software.

https://github.com/eteran/cxx17_printf


https://github.com/eteran/cxx17_printf

c-plus-plus c-plus-plus-17 templates

Last synced: about 1 year ago
JSON representation

Awesome Lists containing this project

README

          

# cxx17_printf

An implementation of `printf` using c++17's variadic templates. It was inspired
by some of the "safe printf" examples that I've seen. But none of them attempted
to actually implement the `printf` fully with all of its quirks. This code is
(an attempt) to do that.

An advantage of this, is that we can support ANY type being passed to a format,
even complex objects. For example, when `CXX17_PRINTF_EXTENSIONS` is enabled
`"%?"` means "call `to_string` on the argument and print the result" This uses
ADL, so it will find the version that you specify in your namespaces, or use
`std::to_string` as a fallback. If no `to_string` is found, it uses the internal
one which asserts.

NOTE: floating point is not implemented, as it is complex to do correctly, but
is on the TODO list.

Usage is similar to `snprintf`, but more robust. Instead of a buffer/size pair
being passed as a parameter, you pass a context object which has 3 functions
and a data member:

// writes a single character to the output of your choosing
void write(char ch);

// writes a string of characters to the output of your choosing
void write(const char *p, size_t n);

// called when formatting is complete, useful for ensuring NUL termination
void done();

// increment this every time we write is called, this is what printf will
// return.
size_t written = 0;


A simple example of the usage of the library is as follows:

char buf[256];
cxx17::buffer_writer ctx(buf, sizeof(buf));
cxx17::Printf(ctx, "[hello %*s %d]", 10, "world", 123);

// buffer now contains "[hello world 123]"

The context uses duck typing, so any object that meets the critera will suffice,
but there are several examples in Formatters.h

--------

Additionally, while the context based interface is very flexible and can
accomidate essentially any destination stream or buffer. This implementation
also includes more familiar interfaces:

* `int cxx17::sprintf(std::ostream &os, const char *format, const Ts &... ts);`
* `int cxx17::sprintf(char *str, size_t size, const char *format, const Ts &... ts);`
* `int cxx17::printf(const char *format, const Ts &... ts);`

All of which work in the expected ways without the need to manually manage the
concept of "contexts".

--------

Performance so far, when optimizations are at -O3, slightly edges out glibc's
printf. Here is the included test program's output on my machine:

hello world, A, -123, 00001234 0x7ffff03cb7c8 0000004294967292 ffffffff 0000000000000100
hello world, A, -123, 00001234 0x7ffff03cb7c8 0000004294967292 ffffffff 0000000000000100
cxx17 Took: 366344 µs to execute.
printf Took: 384387 µs to execute.

When profile guided optimizations are used, it performs even better. I am sure
however, that there is room for some optimizations too :-)