Subject: Re: [PATCH 1/4] strbuf: add strbuf_add_uint()

From: René Scharfe <[email-masked]>
Date: Tue, 12 May 2026 21:32:09 +0200

On 5/12/26 8:42 PM, Jeff King wrote:
> On Tue, May 12, 2026 at 01:56:00PM +0200, René Scharfe wrote:
> 
>> Prepare the number string in a temporary buffer.  Make it big enough for
>> any unsigned integer value: A decimal digit can represent ln(10)/ln(2) ≈
>> 3.32 bits; dividing the number of bits of uintmax_t by 3.3 and rounding
>> up gives a sufficiently close conservative size estimate.
> 
> Cute. The naive obvious question here is: why not just grow the strbuf
> and format it there directly?
> 
> And the answer is that it's much easier to format numbers right-to-left,
> and then you know how many digits you need. ;)

Right.  Using the strbuf to format the number at the right end and
memmove()ing it in place is a valid approach.  I expected it to be
faster than using a buffer on the stack because there's a chance that
only one cache line needs to be touched.

> You can compute the number of digits needed up front, of course, but
> it's log-10. You might be able to do it quickly based on the size of the
> leading bit, but there are a lot of off-by-one gotchas.

That's the simplest approach and I expected the few necessary extra
divisions to be faster than using a buffer and having to copy the
result.

The three variants were close in my tests, the no-copy variant slightly
winning on Apple silicon, but losing slightly more on an AMD Ryzen
laptop CPU.  So I went with the solid choice of using an on-stack
buffer, same as in printf(3) (at least on BSD).  Buffering at the end of
the strbuf was not really faster; perhaps memmove(3) is just that much
slower than memcpy(3).

Perhaps an optimized decimal_width() could change the picture somewhat,
but I don't expect a big win.  On the other hand I just told you how
unreliable my expectations are, so there might be treasure after all. :)

René