1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
#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.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<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
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<ui64>(value), TStringBuf("x"));
} else if (format == TStringBuf("x") || format == TStringBuf("X")) {
FormatValue(builder, reinterpret_cast<ui64>(value), format);
} else {
builder->AppendString("<invalid pointer format>");
}
}
////////////////////////////////////////////////////////////////////////////////
} // namespace NYT::NDetail
|