Boost logo

Boost :

Subject: Re: [boost] Variadic append for std::string
From: Christof Donat (cd_at_[hidden])
Date: 2017-01-15 08:39:59


Hi,

Am 13.01.2017 17:29, schrieb Peter Dimov:
> Christof Donat wrote:
>> Am 12.01.2017 20:05, schrieb Olaf van der Spek:
>> > I like fmt's syntax much more:
>> >
>> > string s = fmt::format("The answer is {}", 42);
>> >
>> >
>> > http://fmtlib.net/latest/index.html
>
> fmtlib looks pretty cool. In fact it's basically a superset of my
> private library. Some of the design decisions aren't the same but the
> overall style is very similar.
>
>> Format will have to parse the format string at runtime and then chose
>> dynamically the function to stringify the number.
>
> It does, of course, parse the format string, but I'm not sure what you
> mean by "choose function dynamically." The above basically does
> something like
>
> os << "The answer is ";
> os << 42;
> return os.str();
>
> using one virtual call for the os << 42 part.

A call to a virtual function is a dynamic choice of the function to
call.

A non virtual call can be inlined. Even if it is not, it is simply an
absolute jump, while a virtual call is at least loading the vtable
pointer and loading the pointer to the function from said vtable, before
you can jump to the function. But that is not the worst part of virtual
function calls. With non virtual calls, the branch prediction will
always be correct, the upcoming instructions will already be loaded and
fed into the pipeline, and the code runs almost as fast as the inlined
version (ignoring parameter passing here, which is where inlining really
pays of).

Virtual function calls give the branch prediction only a statistical
chance to chose correctly. When it fails, the instruction cache has to
be filled with instructions from the correct branch, while the
prefetched instructions, that already partially executed in the
pipeline, have to be rolled back. Depending on your hardware, that might
cost up to several dozens of clock cycles, in case of a cache miss.

We were talking about performance here. Therefore I tried to come up
with a syntax, that can be implemented without virtual function calls as
much as possible and avoids parsing format strings. Also that syntax
should allow for creating the result in one go, in order to avoid
unnecessary reallocations. Keeping that in mind, I think, my proposal is
not the worst possible, though, of course, someone might come up with a
better one.

Libraries like boost::format have their strengths, when simply
concatenating information does not fit the needs. E.g. for
internationalized text output. I like boost::format a lot, but speed
actually is not its focus.

auto translate(const std::string& key) -> std::string;

// ...
// will translate to e.g. "%2% Bytes werden von der Datei '%1%' belegt."
std::cerr << boost::format(translate("file '%1%' contains %2% bytes"s))
% filename % filesize << std::endl;

On the other hand e.g. for writing a set of values as CSV, my proposed
interface will produce faster code:

for(const auto& line : all_lines)
     out << (cat() + line<1> + ',' + line<2> + ',' + line<3> + ',' +
line<4> + ',' + line<5> + '\n').str();

Christof


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk