aboutsummaryrefslogtreecommitdiffstats
path: root/library/cpp/yt/string/format.cpp
blob: 47b0c1d712d398d4b438002fdc15e374430f3390 (plain) (blame)
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