Audacity 3.2.0
FromChars.cpp
Go to the documentation of this file.
1/*!********************************************************************
2
3 Audacity: A Digital Audio Editor
4
5 @file FromChars.cpp
6 @brief Define functions to convert numeric types to string representation.
7
8 Dmitry Vedenko
9 **********************************************************************/
10
11#include "FromChars.h"
12
13#include "3party/fast_float.h"
14
15#include <limits>
16#include <algorithm>
17
18namespace
19{
20// Converting c to unsigned here helps to eliminate one check
21unsigned digitToInt(char c) noexcept
22{
23 return static_cast<unsigned>(c) - '0';
24}
25
26template <typename T>
27bool safeMul10Add(T& result, T a, T b)
28{
29 static_assert(std::is_unsigned_v<T>);
30
31 constexpr auto bits = sizeof(a) * 8 - 3;
32 // Check for the top 3 bits of a
33 if (a >> bits)
34 return false;
35
36 const T times8 = a << 3;
37 // a << 1 won't overflow
38 const T times2 = a << 1;
39
40 // timesX are all unsigned values, if overflow occurs - times10 will be <
41 // times8
42 const T times10 = times8 + times2;
43
44 if (times10 < times8)
45 return false;
46
47 const T tempResult = times10 + b;
48
49 if (tempResult < times10)
50 return false;
51
52 result = tempResult;
53
54 return true;
55}
56
57template <typename ResultType>
59 const char* first, const char* last, ResultType& value,
60 bool isNegative) noexcept
61{
62 using UnsignedResultType = std::make_unsigned_t<ResultType>;
63
64 const auto availableBytes = last - first;
65
66 if (availableBytes <= 0)
67 return { first, std::errc::invalid_argument };
68
69 UnsignedResultType result = digitToInt(*first);
70
71 if (result > 10)
72 return { first, std::errc::invalid_argument };
73
74 constexpr auto maxSafeDigits = std::numeric_limits<ResultType>::digits10;
75
76 const char* ptr = first;
77 const char* safeLast =
78 first + std::min<decltype(availableBytes)>(availableBytes, maxSafeDigits);
79
80 unsigned d;
81
82 // No integer overflow here
83 while (++ptr < safeLast && (d = digitToInt(*ptr)) <= 9)
84 {
85 result = result * 10 + d;
86 }
87
88 // But here live dragons
89 while (ptr < last && (d = digitToInt(*ptr)) <= 9)
90 {
91 if (!safeMul10Add<UnsignedResultType>(result, result, d))
92 return { ptr, std::errc::result_out_of_range };
93
94 // Even if there were no unsigned overflow,
95 // signed overflow is still possible
96 if constexpr (std::is_signed_v<ResultType>)
97 {
98 const UnsignedResultType max =
99 static_cast<UnsignedResultType>(
100 std::numeric_limits<ResultType>::max()) +
101 (isNegative ? 1 : 0);
102
103 if (result > max)
104 return { ptr, std::errc::result_out_of_range };
105 }
106
107
108 ++ptr;
109 }
110
111 if constexpr (std::is_signed_v<ResultType>)
112 {
113 value = isNegative ?
114 // Unary minus on unsigned type makes MSVC unhappy
115 static_cast<ResultType>(0 - result) :
116 static_cast<ResultType>(result);
117 }
118 else
119 value = static_cast<ResultType>(result);
120
121 return { ptr, std::errc() };
122}
123
124template <typename ResultType>
126IntFromChars(const char* buffer, const char* last, ResultType& value) noexcept
127{
128 const char* origin = buffer;
129
130 if (buffer >= last)
131 return { buffer, std::errc::invalid_argument };
132
133 const bool isNegative = *buffer == '-';
134
135 if (isNegative)
136 {
137 if constexpr (std::is_signed_v<ResultType>)
138 ++buffer;
139 else
140 return { origin, std::errc::invalid_argument };
141 }
142
143 const auto fastStringResult =
144 FastStringToInt(buffer, last, value, isNegative);
145
146 if (fastStringResult.ec == std::errc::invalid_argument)
147 return { origin, std::errc::invalid_argument };
148
149 return fastStringResult;
150}
151} // namespace
152
153FromCharsResult FromChars(const char* buffer, const char* last, float& value) noexcept
154{
155 const auto result = fast_float::from_chars(buffer, last, value);
156 return { result.ptr, result.ec };
157}
158
159FromCharsResult FromChars(const char* buffer, const char* last, double& value) noexcept
160{
161 const auto result = fast_float::from_chars(buffer, last, value);
162 return { result.ptr, result.ec };
163}
164
165FromCharsResult FromChars(const char* buffer, const char* last, short& value) noexcept
166{
167 return IntFromChars(buffer, last, value);
168}
169
170FromCharsResult FromChars(const char* buffer, const char* last, unsigned short& value) noexcept
171{
172 return IntFromChars(buffer, last, value);
173}
174
175FromCharsResult FromChars(const char* buffer, const char* last, int& value) noexcept
176{
177 return IntFromChars(buffer, last, value);
178}
179
180FromCharsResult FromChars(const char* buffer, const char* last, unsigned int& value) noexcept
181{
182 return IntFromChars(buffer, last, value);
183}
184
185FromCharsResult FromChars(const char* buffer, const char* last, long& value) noexcept
186{
187 return IntFromChars(buffer, last, value);
188}
189
190FromCharsResult FromChars(const char* buffer, const char* last, unsigned long& value) noexcept
191{
192 return IntFromChars(buffer, last, value);
193}
194
195FromCharsResult FromChars(const char* buffer, const char* last, long long& value) noexcept
196{
197 return IntFromChars(buffer, last, value);
198}
199
200FromCharsResult FromChars(const char* buffer, const char* last, unsigned long long& value) noexcept
201{
202 return IntFromChars(buffer, last, value);
203}
204
206FromChars(const char* buffer, const char* last, bool& value) noexcept
207{
208 if (buffer >= last)
209 return { buffer, std::errc::invalid_argument };
210
211 if (buffer[0] == '0')
212 {
213 value = false;
214 return { buffer + 1, std::errc() };
215 }
216 else if (buffer[0] == '1')
217 {
218 value = true;
219 return { buffer + 1, std::errc() };
220 }
221
222 return { buffer, std::errc::invalid_argument };
223}
FromCharsResult FromChars(const char *buffer, const char *last, float &value) noexcept
Parse a string into a single precision floating point value, always uses the dot as decimal.
Definition: FromChars.cpp:153
Declare functions to convert numeric types to string representation.
bool safeMul10Add(T &result, T a, T b)
Definition: FromChars.cpp:27
FromCharsResult FastStringToInt(const char *first, const char *last, ResultType &value, bool isNegative) noexcept
Definition: FromChars.cpp:58
unsigned digitToInt(char c) noexcept
Definition: FromChars.cpp:21
FromCharsResult IntFromChars(const char *buffer, const char *last, ResultType &value) noexcept
Definition: FromChars.cpp:126
from_chars_result from_chars(const char *first, const char *last, T &value, chars_format fmt=chars_format::general) noexcept
Definition: fast_float.h:2900
Result of the conversion, similar to std::from_chars_result.
Definition: FromChars.h:17