Coverage Report

Created: 2024-04-30 09:35

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