#include "format.h" #include "string.h" namespace NYT::NDetail { //////////////////////////////////////////////////////////////////////////////// template 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.back() == 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(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 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 void FormatPointerValue( TStringBuilderBase* builder, const void* value, TStringBuf format) { static_assert(sizeof(value) == sizeof(ui64)); if (format == TStringBuf("p") || format == TStringBuf("v")) { builder->AppendString(TStringBuf("0x")); FormatValue(builder, reinterpret_cast(value), TStringBuf("x")); } else if (format == TStringBuf("x") || format == TStringBuf("X")) { FormatValue(builder, reinterpret_cast(value), format); } else { builder->AppendString(""); } } //////////////////////////////////////////////////////////////////////////////// } // namespace NYT::NDetail