diff options
author | babenko <babenko@yandex-team.com> | 2022-08-26 10:04:55 +0300 |
---|---|---|
committer | babenko <babenko@yandex-team.com> | 2022-08-26 10:04:55 +0300 |
commit | af6b0b93037268a9ca1343dd09629cf910c944d9 (patch) | |
tree | 609b08bbb2cd7498d55b6f7a92aaf1a4d51d003c /library/cpp/yt/string/format.cpp | |
parent | d40e0a72d30643f29b6fe0dee30d6d686f563e3f (diff) | |
download | ydb-af6b0b93037268a9ca1343dd09629cf910c944d9.tar.gz |
Natively support %x and %X in Format
Diffstat (limited to 'library/cpp/yt/string/format.cpp')
-rw-r--r-- | library/cpp/yt/string/format.cpp | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/library/cpp/yt/string/format.cpp b/library/cpp/yt/string/format.cpp new file mode 100644 index 0000000000..6c824e8ba3 --- /dev/null +++ b/library/cpp/yt/string/format.cpp @@ -0,0 +1,110 @@ +#include "format.h" +#include "string.h" + +namespace NYT::NDetail { + +//////////////////////////////////////////////////////////////////////////////// + +template <class TValue> +void FormatValueViaSprintf( + TStringBuilderBase* builder, + TValue value, + TStringBuf format, + TStringBuf genericSpec) +{ + constexpr int MaxFormatSize = 64; + constexpr int SmallResultSize = 64; + + auto copyFormat = [] (char* destination, const char* source, int length) { + int position = 0; + for (int index = 0; index < length; ++index) { + if (IsQuotationSpecSymbol(source[index])) { + continue; + } + destination[position] = source[index]; + ++position; + } + return destination + position; + }; + + char formatBuf[MaxFormatSize]; + YT_VERIFY(format.length() >= 1 && format.length() <= MaxFormatSize - 2); // one for %, one for \0 + formatBuf[0] = '%'; + if (format[format.length() - 1] == GenericSpecSymbol) { + char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length() - 1); + ::memcpy(formatEnd, genericSpec.begin(), genericSpec.length()); + formatEnd[genericSpec.length()] = '\0'; + } else { + char* formatEnd = copyFormat(formatBuf + 1, format.begin(), format.length()); + *formatEnd = '\0'; + } + + char* result = builder->Preallocate(SmallResultSize); + size_t resultSize = ::snprintf(result, SmallResultSize, formatBuf, value); + if (resultSize >= SmallResultSize) { + result = builder->Preallocate(resultSize + 1); + YT_VERIFY(::snprintf(result, resultSize + 1, formatBuf, value) == static_cast<int>(resultSize)); + } + builder->Advance(resultSize); +} + +#define XX(type) \ + template \ + void FormatValueViaSprintf( \ + TStringBuilderBase* builder, \ + type value, \ + TStringBuf format, \ + TStringBuf genericSpec); + +XX(i32) +XX(ui32) +XX(i64) +XX(ui64) +XX(float) +XX(double) +XX(const void*) + +#undef XX + +template <class TValue> +void FormatIntValue( + TStringBuilderBase* builder, + TValue value, + TStringBuf format, + TStringBuf genericSpec) +{ + if (format == TStringBuf("v")) { + constexpr int MaxResultSize = 64; + char buffer[MaxResultSize]; + char* end = buffer + MaxResultSize; + char* start = WriteDecIntToBufferBackwards(end, value); + builder->AppendString(TStringBuf(start, end)); + } else if (format == TStringBuf("x") || format == TStringBuf("X")) { + constexpr int MaxResultSize = 64; + char buffer[MaxResultSize]; + char* end = buffer + MaxResultSize; + char* start = WriteHexIntToBufferBackwards(end, value, format[0] == 'X'); + builder->AppendString(TStringBuf(start, end)); + } else { + FormatValueViaSprintf(builder, value, format, genericSpec); + } +} + +#define XX(type) \ + template \ + void FormatIntValue( \ + TStringBuilderBase* builder, \ + type value, \ + TStringBuf format, \ + TStringBuf genericSpec); + +XX(i32) +XX(ui32) +XX(i64) +XX(ui64) + +#undef XX + +//////////////////////////////////////////////////////////////////////////////// + +} // namespace NYT::NDetail |