This is the mail archive of the libstdc++@gcc.gnu.org mailing list for the libstdc++ project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

The note about improving std::to_string() for SSO strings


Hi Paolo,

I've been looking at this note in <ext/string_conversions.h> now that
we have a new std::string:

     // XXX Eventually the result will be constructed in place in
     // the C++0x string, likely with the help of internal hooks.
     _CharT* __s = static_cast<_CharT*>(__builtin_alloca(sizeof(_CharT)
                                                         * __n));

I see a couple of ways to do that.

1) Create a string that has the maximum size for an SSO string:

   _String __str;
   __str.resize(__str.capacity());

then try to print the number into it. If it fits, return it, otherwise
grow the string by re-allocating with resize() and print into it again,
then return it.


2) Use alloca() to create a buffer that has room for a string and the
big-enough buffer of sizeof(_CharT) + __n bytes, overlapping like so:

   |-------------------
   | _M_pointer       |
   |------------------|
   | _M_string_length |
   |------------------|------------------|
   | _M_local_buf     | __s              |
   |                  |                  |
   |                  |                  |
   |                  |                  |
   |                  |                  |
   |------------------|                  |
                      |                  |
                      |                  |
                      |------------------|

We use printf to write to __s and if it fits in _M_local_buf we set
_M_pointer = _M_local_buf and _M_string_length = __len, then
return *reinterpret_cast<_String*>(__alloca_buf)

If the characters printed into __s don't fit in _M_local_buf just
return _String(__s, __s + __len)


For (1) we get the RVO, so if the string fits in the SSO buffer
there's no copying. But if it doesn't fit we need two calls to
sprintf/swprintf.

For (2) we won't get the RVO, so there's always a memcpy from __s to
the return value's storage.  We only ever do one call to
sprintf/swprintf.

(2) seems to have no advantage over the current code, which benefits
from the RVO, only ever makes one sprintf call, but unconditionally
does a memcpy from the alloca() buffer to the returned string object.
So let's dismiss (2) and consider (1).

In both cases we only allocate from the heap when the string doesn't
fit in the SSO buffer. The difference is that for small values that
fit in the SSO buffer (1) avoids a memcpy. For larger values that
don't fit (where "larger" is a much lower limit for wide strings)
using (1) will do an extra sprintf/swprintf.

Since a memcpy for the short-string case is really cheap I don't think
we gain much by optimising to avoid that.

If someone else wants to benchmark (1) and prove it's worth doing I'm
willing to be convinced, but without that I'm not planning on changing
anything here.  I think the current code works pretty well for both
COW and SSO strings.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]