| 7 | |
| 8 | template <class TValue> |
| 9 | void FormatValueViaSprintf( |
| 10 | TStringBuilderBase* builder, |
| 11 | TValue value, |
| 12 | TStringBuf format, |
| 13 | TStringBuf genericSpec) |
| 14 | { |
| 15 | constexpr int MaxFormatSize = 64; |
| 16 | constexpr int SmallResultSize = 64; |
| 17 | |
| 18 | auto copyFormat = [] (char* destination, const char* source, int length) { |
| 19 | int position = 0; |
| 20 | for (int index = 0; index < length; ++index) { |
| 21 | if (IsQuotationSpecSymbol(source[index])) { |
| 22 | continue; |
| 23 | } |
| 24 | destination[position] = source[index]; |
| 25 | ++position; |
| 26 | } |
| 27 | return destination + position; |
| 28 | }; |
| 29 | |
| 30 | char formatBuf[MaxFormatSize]; |
| 31 | YT_VERIFY(format.length() >= 1 && format.length() <= MaxFormatSize - 2); // one for %, one for \0 |
| 32 | formatBuf[0] = '%'; |
| 33 | |
| 34 | if (format.back() == GenericSpecSymbol) { |
| 35 | char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length() - 1); |
| 36 | ::memcpy(formatEnd, genericSpec.begin(), genericSpec.length()); |
| 37 | formatEnd[genericSpec.length()] = '\0'; |
| 38 | } else { |
| 39 | char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length()); |
| 40 | *formatEnd = '\0'; |
| 41 | } |
| 42 | |
| 43 | char* result = builder->Preallocate(SmallResultSize); |
| 44 | size_t resultSize = ::snprintf(result, SmallResultSize, formatBuf, value); |
| 45 | if (resultSize >= SmallResultSize) { |
| 46 | result = builder->Preallocate(resultSize + 1); |
| 47 | YT_VERIFY(::snprintf(result, resultSize + 1, formatBuf, value) == static_cast<int>(resultSize)); |
| 48 | } |
| 49 | builder->Advance(resultSize); |
| 50 | } |
| 51 | |
| 52 | #define XX(type) \ |
| 53 | template \ |
no test coverage detected