GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: src/zserio/StringConvertUtil.h Lines: 46 46 100.0 %
Date: 2023-12-13 14:51:09 Branches: 53 159 33.3 %

Line Branch Exec Source
1
#ifndef ZSERIO_STRING_CONVERT_UTIL_H_INC
2
#define ZSERIO_STRING_CONVERT_UTIL_H_INC
3
4
#include <sstream>
5
#include <limits>
6
#include <array>
7
8
#include "zserio/String.h"
9
#include "zserio/RebindAlloc.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
2439
const char* convertIntToString(std::array<char, 24>& buffer, T value, bool isNegative)
27
{
28
    static const std::array<char, 201> DIGITS = {"0001020304050607080910111213141516171819"
29
                                                 "2021222324252627282930313233343536373839"
30
                                                 "4041424344454647484950515253545556575859"
31
                                                 "6061626364656667686970717273747576777879"
32
                                                 "8081828384858687888990919293949596979899"};
33
34
2439
    auto bufferEnd = buffer.end();
35
2439
    *--bufferEnd = 0; // always terminate with '\0'
36
37


7481
    while (value >= 100)
38
    {
39
2521
        const unsigned int index = static_cast<unsigned int>((value % 100) * 2);
40
2521
        value /= 100;
41
2521
        *--bufferEnd = DIGITS[index + 1];
42
2521
        *--bufferEnd = DIGITS[index];
43
    }
44
45


2439
    if (value < 10)
46
    {
47
1639
        *--bufferEnd = static_cast<char>('0' + value);
48
    }
49
    else
50
    {
51
800
        const unsigned int index = static_cast<unsigned int>(value * 2);
52
800
        *--bufferEnd = DIGITS[index + 1];
53
800
        *--bufferEnd = DIGITS[index];
54
    }
55
56


2439
    if (isNegative)
57
231
        *--bufferEnd = '-';
58
59
2439
    return &(*bufferEnd);
60
}
61
62
} // namespace detail
63
64
/**
65
 * Converts unsigned integral value to string and writes the result to the given buffer.
66
 *
67
 * Note that the buffer is filled from behind.
68
 *
69
 * \param buffer Buffer to fill with the string representation of the given value.
70
 * \param value  Value to convert.
71
 *
72
 * \return Pointer to the beginning of the resulting string.
73
 */
74
template <typename T,
75
        typename std::enable_if<std::is_unsigned<T>::value, int>::type = 0>
76
1941
const char* convertIntToString(std::array<char, 24>& buffer, T value)
77
{
78
1941
    return detail::convertIntToString(buffer, value, false);
79
}
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
498
const char* convertIntToString(std::array<char, 24>& buffer, T value)
93
{
94
    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 = 0 - absValue;
99
100
498
    return detail::convertIntToString(buffer, absValue, isNegative);
101
}
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
21
inline void convertFloatToString(std::array<char, 24>& integerPartBuffer,
115
        std::array<char, 24>& floatingPartBuffer, float value, const char*& integerPartString,
116
        const char*& floatingPartString)
117
{
118
21
    if (value >= static_cast<float>(std::numeric_limits<int64_t>::max()))
119
    {
120
2
        integerPartString = "+Inf";
121
2
        floatingPartString = nullptr;
122
    }
123
19
    else if (value <= static_cast<float>(std::numeric_limits<int64_t>::min()))
124
    {
125
1
        integerPartString = "-Inf";
126
1
        floatingPartString = nullptr;
127
    }
128
    else
129
    {
130
18
        const int64_t integerPart = static_cast<int64_t>(value);
131
        const int64_t floatingPart = static_cast<int64_t>(
132
18
                (value - static_cast<float>(integerPart)) * 1e3F); // 3 digits
133
18
        const int64_t floatingPartAbs = (floatingPart < 0) ? 0 - floatingPart : floatingPart;
134
18
        integerPartString = convertIntToString(integerPartBuffer, integerPart);
135
18
        floatingPartString = convertIntToString(floatingPartBuffer, floatingPartAbs);
136
    }
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
23
inline const char* convertBoolToString(bool value)
147
{
148
23
    return value ? "true" : "false";
149
}
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
497
string<ALLOC> toString(T value, const ALLOC& allocator = ALLOC())
161
{
162
497
    std::array<char, 24> buffer = {};
163






















497
    return string<ALLOC>(convertIntToString(buffer, value), allocator);
164
}
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
21
string<ALLOC> toString(bool value, const ALLOC& allocator = ALLOC())
177
{
178
21
    return string<ALLOC>(convertBoolToString(value), allocator);
179
}
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
287
string<std::allocator<char>> toString(T value)
190
{
191





287
    return toString<std::allocator<char>>(value);
192
}
193
194
} // namespace zserio
195
196
#endif // ifndef ZSERIO_STRING_CONVERT_UTIL_H_INC