Coverage Report

Created: 2024-07-18 11:41

src/zserio/StringConvertUtil.h
Line
Count
Source
1
#ifndef ZSERIO_STRING_CONVERT_UTIL_H_INC
2
#define ZSERIO_STRING_CONVERT_UTIL_H_INC
3
4
#include <array>
5
#include <limits>
6
#include <sstream>
7
8
#include "zserio/RebindAlloc.h"
9
#include "zserio/String.h"
10
11
namespace zserio
12
{
13
14
namespace detail
15
{
16
17
/**
18
 * Converts integer value to string into the given buffer.
19
 *
20
 * The string is filled from backwards starting at the 24th byte.
21
 *
22
 * \return Beginning of the resulting string which is null-terminated.
23
 */
24
template <typename T,
25
        typename std::enable_if<std::is_unsigned<T>::value && !std::is_same<T, bool>::value, int>::type = 0>
26
const char* convertIntToString(std::array<char, 24>& buffer, T value, bool isNegative)
27
2.46k
{
28
2.46k
    static const std::array<char, 201> DIGITS = {
29
2.46k
            "0001020304050607080910111213141516171819"
30
2.46k
            "2021222324252627282930313233343536373839"
31
2.46k
            "4041424344454647484950515253545556575859"
32
2.46k
            "6061626364656667686970717273747576777879"
33
2.46k
            "8081828384858687888990919293949596979899"};
34
35
2.46k
    auto bufferEnd = buffer.end();
36
2.46k
    *(--bufferEnd) = 0; // always terminate with '\0'
37
38
4.99k
    while (value >= 100)
39
2.52k
    {
40
2.52k
        const unsigned int index = static_cast<unsigned int>((value % 100) * 2);
41
2.52k
        value /= 100;
42
2.52k
        *(--bufferEnd) = DIGITS[index + 1];
43
2.52k
        *(--bufferEnd) = DIGITS[index];
44
2.52k
    }
45
46
2.46k
    if (value < 10)
47
1.66k
    {
48
1.66k
        *(--bufferEnd) = static_cast<char>('0' + value);
49
1.66k
    }
50
804
    else
51
804
    {
52
804
        const unsigned int index = static_cast<unsigned int>(value * 2);
53
804
        *(--bufferEnd) = DIGITS[index + 1];
54
804
        *(--bufferEnd) = DIGITS[index];
55
804
    }
56
57
2.46k
    if (isNegative)
58
231
    {
59
231
        *(--bufferEnd) = '-';
60
231
    }
61
62
2.46k
    return &(*bufferEnd);
63
2.46k
}
64
65
} // namespace detail
66
67
/**
68
 * Converts unsigned integral value to string and writes the result to the given buffer.
69
 *
70
 * Note that the buffer is filled from behind.
71
 *
72
 * \param buffer Buffer to fill with the string representation of the given value.
73
 * \param value  Value to convert.
74
 *
75
 * \return Pointer to the beginning of the resulting string.
76
 */
77
template <typename T, typename std::enable_if<std::is_unsigned<T>::value, int>::type = 0>
78
const char* convertIntToString(std::array<char, 24>& buffer, T value)
79
1.96k
{
80
1.96k
    return detail::convertIntToString(buffer, value, false);
81
1.96k
}
82
83
/**
84
 * Converts signed integral value to string and writes the result to the given buffer.
85
 *
86
 * Note that the buffer is filled from behind.
87
 *
88
 * \param buffer Buffer to fill with the string representation of the given value.
89
 * \param value  Value to convert.
90
 *
91
 * \return Pointer to the beginning of the resulting string.
92
 */
93
template <typename T, typename std::enable_if<std::is_signed<T>::value, int>::type = 0>
94
const char* convertIntToString(std::array<char, 24>& buffer, T value)
95
504
{
96
504
    using unsigned_type = typename std::make_unsigned<T>::type;
97
504
    unsigned_type absValue = static_cast<unsigned_type>(value);
98
504
    const bool isNegative = value < 0;
99
504
    if (isNegative)
100
231
    {
101
231
        absValue = static_cast<unsigned_type>(0 - absValue);
102
231
    }
103
104
504
    return detail::convertIntToString(buffer, absValue, isNegative);
105
504
}
106
107
/**
108
 * Converts float to string and writes the result to the given buffer.
109
 *
110
 * Note that only five three digits after point are used and that the buffers are filled from behind.
111
 *
112
 * \param integerPartBuffer Buffer to fill with the string representation of the integer part.
113
 * \param floatingPartBuffer Buffer to fill with the string representation of the floating part.
114
 * \param value Value to convert.
115
 * \param floatingPartString Reference where to fill pointer to the beginning of the floating part in string.
116
 * \param integerPartString Reference where to fill pointer to the beginning of the integer part in string.
117
 */
118
inline void convertFloatToString(std::array<char, 24>& integerPartBuffer,
119
        std::array<char, 24>& floatingPartBuffer, float value, const char*& integerPartString,
120
        const char*& floatingPartString)
121
21
{
122
21
    if (value >= static_cast<float>(std::numeric_limits<int64_t>::max()))
123
2
    {
124
2
        integerPartString = "+Inf";
125
2
        floatingPartString = nullptr;
126
2
    }
127
19
    else if (value <= static_cast<float>(std::numeric_limits<int64_t>::min()))
128
1
    {
129
1
        integerPartString = "-Inf";
130
1
        floatingPartString = nullptr;
131
1
    }
132
18
    else
133
18
    {
134
18
        const int64_t integerPart = static_cast<int64_t>(value);
135
18
        const int64_t floatingPart =
136
18
                static_cast<int64_t>((value - static_cast<float>(integerPart)) * 1e3F); // 3 digits
137
18
        const int64_t floatingPartAbs = (floatingPart < 0) ? 
0 - floatingPart1
:
floatingPart17
;
138
18
        integerPartString = convertIntToString(integerPartBuffer, integerPart);
139
18
        floatingPartString = convertIntToString(floatingPartBuffer, floatingPartAbs);
140
18
    }
141
21
}
142
143
/**
144
 * Converts bool value to boolalpha C-string ("true" or "false").
145
 *
146
 * \param value Value to convert.
147
 *
148
 * \return C-string representation of the given bool value.
149
 */
150
inline const char* convertBoolToString(bool value)
151
23
{
152
23
    return value ? 
"true"13
:
"false"10
;
153
23
}
154
155
/**
156
 * Converts an integral value to string using the given allocator. Defined for convenience.
157
 *
158
 * \param value     Value to convert.
159
 * \param allocator Allocator to use for the string allocation.
160
 *
161
 * \return String representation of the given integral value.
162
 */
163
template <typename ALLOC, typename T>
164
string<ALLOC> toString(T value, const ALLOC& allocator = ALLOC())
165
497
{
166
497
    std::array<char, 24> buffer = {};
167
497
    return string<ALLOC>(convertIntToString(buffer, value), allocator);
168
497
}
169
170
/**
171
 * Converts a boolean value to string using the given allocator. Defined for convenience.
172
 *
173
 * Note that in contrast to std::to_string, this behaves as STL streams with boolalpha flag and produces
174
 * "true" and "false" strings.
175
 *
176
 * \param value Value to convert.
177
 * \param allocator Allocator to use for the string allocation.
178
 */
179
template <typename ALLOC>
180
string<ALLOC> toString(bool value, const ALLOC& allocator = ALLOC())
181
21
{
182
21
    return string<ALLOC>(convertBoolToString(value), allocator);
183
21
}
184
185
/**
186
 * Converts an integral (or a boolean) value to string. Convenience wrapper to call without allocator.
187
 *
188
 * \param value Value to convert.
189
 *
190
 * \return String representation of the given value.
191
 */
192
template <typename T>
193
string<std::allocator<char>> toString(T value)
194
287
{
195
287
    return toString<std::allocator<char>>(value);
196
287
}
197
198
} // namespace zserio
199
200
#endif // ifndef ZSERIO_STRING_CONVERT_UTIL_H_INC