string: upgrade sprintf to write directly into std::string buffer

This removes extra memory allocation.

Signed-off-by: Simon Rozman <simon@rozman.si>
This commit is contained in:
Simon Rozman 2024-01-05 20:32:00 +01:00
parent 1685cd3283
commit 293da738b9

View File

@ -2367,17 +2367,17 @@ namespace stdex
switch (errno) { switch (errno) {
case 0: case 0:
count = vsnprintf(NULL, 0, format, locale, arg); count = vsnprintf(NULL, 0, format, locale, arg);
_Assume_(count >= 0);
break; break;
case EINVAL: throw std::invalid_argument("invalid vsnprintf arguments"); case EINVAL: throw std::invalid_argument("invalid vsnprintf arguments");
case EILSEQ: throw std::runtime_error("encoding error"); case EILSEQ: throw std::runtime_error("encoding error");
default: throw std::runtime_error("failed to format string"); default: throw std::runtime_error("failed to format string");
} }
} }
auto buf_dyn = std::make_unique<T[]>(count + 1); size_t offset = str.size();
count = vsnprintf(buf_dyn.get(), count + 1, format, locale, arg); str.resize(offset + count);
if (count < 0) _Unlikely_ if (vsnprintf(&str[offset], count + 1, format, locale, arg) != count) _Unlikely_
throw std::runtime_error("failed to format string"); throw std::runtime_error("failed to format string");
str.append(buf_dyn.get(), count);
return count; return count;
} }
@ -2504,16 +2504,16 @@ namespace stdex
if (count) { if (count) {
// Copy from stack. // Copy from stack.
str.append(buf, count); str.append(buf, count);
return;
} }
else { size_t offset = str.size();
for (size_t capacity = 2 * 1024 / sizeof(T);; capacity *= 2) { for (size_t capacity = 2 * 1024 / sizeof(T);; capacity *= 2) {
// Allocate on heap and retry. // Allocate on heap and retry.
auto buf_dyn = std::make_unique<T[]>(capacity); str.resize(offset + capacity);
count = strftime(buf_dyn.get(), capacity, format, time, locale); count = strftime(&str[offset], capacity + 1, format, time, locale);
if (count) { if (count) {
str.append(buf_dyn.get(), count); str.resize(offset + count);
break; return;
}
} }
} }
} }