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 if constexpr (std::is_signed_v<ResultType>)
109 {
110 value = isNegative ?
111 // Unary minus on unsigned type makes MSVC unhappy
112 static_cast<ResultType>(0 - result) :
113 static_cast<ResultType>(result);
114 }
115 else
116 value = static_cast<ResultType>(result);
117
118 return { ptr, std::errc() };
119}
120
121template <typename ResultType>
123IntFromChars(const char* buffer, const char* last, ResultType& value) noexcept
124{
125 const char* origin = buffer;
126
127 if (buffer >= last)
128 return { buffer, std::errc::invalid_argument };
129
130 const bool isNegative = *buffer == '-';
131
132 if (isNegative)
133 {
134 if constexpr (std::is_signed_v<ResultType>)
135 ++buffer;
136 else
137 return { origin, std::errc::invalid_argument };
138 }
139
140 const auto fastStringResult =
141 FastStringToInt(buffer, last, value, isNegative);
142
143 if (fastStringResult.ec == std::errc::invalid_argument)
144 return { origin, std::errc::invalid_argument };
145
146 return fastStringResult;
147}
148} // namespace
149
150FromCharsResult FromChars(const char* buffer, const char* last, float& value) noexcept
151{
152 const auto result = fast_float::from_chars(buffer, last, value);
153 return { result.ptr, result.ec };
154}
155
156FromCharsResult FromChars(const char* buffer, const char* last, double& value) noexcept
157{
158 const auto result = fast_float::from_chars(buffer, last, value);
159 return { result.ptr, result.ec };
160}
161
162FromCharsResult FromChars(const char* buffer, const char* last, short& value) noexcept
163{
164 return IntFromChars(buffer, last, value);
165}
166
167FromCharsResult FromChars(const char* buffer, const char* last, unsigned short& value) noexcept
168{
169 return IntFromChars(buffer, last, value);
170}
171
172FromCharsResult FromChars(const char* buffer, const char* last, int& value) noexcept
173{
174 return IntFromChars(buffer, last, value);
175}
176
177FromCharsResult FromChars(const char* buffer, const char* last, unsigned int& value) noexcept
178{
179 return IntFromChars(buffer, last, value);
180}
181
182FromCharsResult FromChars(const char* buffer, const char* last, long& value) noexcept
183{
184 return IntFromChars(buffer, last, value);
185}
186
187FromCharsResult FromChars(const char* buffer, const char* last, unsigned long& value) noexcept
188{
189 return IntFromChars(buffer, last, value);
190}
191
192FromCharsResult FromChars(const char* buffer, const char* last, long long& value) noexcept
193{
194 return IntFromChars(buffer, last, value);
195}
196
197FromCharsResult FromChars(const char* buffer, const char* last, unsigned long long& value) noexcept
198{
199 return IntFromChars(buffer, last, value);
200}
201
203FromChars(const char* buffer, const char* last, bool& value) noexcept
204{
205 if (buffer >= last)
206 return { buffer, std::errc::invalid_argument };
207
208 if (buffer[0] == '0')
209 {
210 value = false;
211 return { buffer + 1, std::errc() };
212 }
213 else if (buffer[0] == '1')
214 {
215 value = true;
216 return { buffer + 1, std::errc() };
217 }
218
219 return { buffer, std::errc::invalid_argument };
220}
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:150
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:123
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