aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/string/format.cpp
diff options
context:
space:
mode:
authorbabenko <babenko@yandex-team.com>2022-08-26 10:04:55 +0300
committerbabenko <babenko@yandex-team.com>2022-08-26 10:04:55 +0300
commitaf6b0b93037268a9ca1343dd09629cf910c944d9 (patch)
tree609b08bbb2cd7498d55b6f7a92aaf1a4d51d003c /library/cpp/yt/string/format.cpp
parentd40e0a72d30643f29b6fe0dee30d6d686f563e3f (diff)
downloadydb-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.cpp110
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