NDEVR
API Documentation
NumberParser.hpp
1/*--------------------------------------------------------------------------------------------
2Copyright (c) 2019, NDEVR LLC
3tyler.parke@ndevr.org
4 __ __ ____ _____ __ __ _______
5 | \ | | | __ \ | ___|\ \ / / | __ \
6 | \ | | | | \ \ | |___ \ \ / / | |__) |
7 | . \| | | |__/ / | |___ \ V / | _ /
8 | |\ |_|_____/__|_____|___\_/____| | \ \
9 |__| \__________________________________| \__\
10
11Subject to the terms of the Enterprise+ Agreement, NDEVR hereby grants
12Licensee a limited, non-exclusive, non-transferable, royalty-free license
13(without the right to sublicense) to use the API solely for the purpose of
14Licensee's internal development efforts to develop applications for which
15the API was provided.
16
17The above copyright notice and this permission notice shall be included in all
18copies or substantial portions of the Software.
19
20THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
21INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
22PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
23FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25DEALINGS IN THE SOFTWARE.
26
27Library: Base
28File: NumberParser
29Included in API: True
30Author(s): Tyler Parke
31 *-----------------------------------------------------------------------------------------**/
32#pragma once
33#include <NDEVR/BaseValues.h>
34#include <NDEVR/Angle.h>
35#include <cmath>
36namespace NDEVR
37{
41 constexpr const fltp08 fast_atof_table[20] = {
42 0.0,
43 0.1,
44 0.01,
45 0.001,
46 0.0001,
47 0.00001,
48 0.000001,
49 0.0000001,
50 0.00000001,
51 0.000000001,
52 0.0000000001,
53 0.00000000001,
54 0.000000000001,
55 0.0000000000001,
56 0.00000000000001,
57 0.000000000000001,
58 0.0000000000000001,
59 0.00000000000000001,
60 0.000000000000000001,
61 0.0000000000000000001,
62 };
63
67 template<class t_type>
68 constexpr uint04 MaxDigits();
69
70 template<> constexpr uint04 MaxDigits<uint01>() { return 3; }
71 template<> constexpr uint04 MaxDigits<sint01>() { return 3; }
72
73 template<> constexpr uint04 MaxDigits<uint02>() { return 5; }
74 template<> constexpr uint04 MaxDigits<sint02>() { return 5; }
75
76 template<> constexpr uint04 MaxDigits<uint04>() { return 10; }
77 template<> constexpr uint04 MaxDigits<sint04>() { return 10; }
78
79 template<> constexpr uint04 MaxDigits<sint08>() { return 19; }
80 template<> constexpr uint04 MaxDigits<uint08>() { return 20; }
81
82 template<class t_type>
83 static constexpr t_type npow10(uint02 exp);
84 template<class t_type>
85 static constexpr t_type pow10(uint02 exp);
86 /*{
87 t_type result = static_cast<t_type>(1);
88 t_type factor = static_cast<t_type>(10);
89 while (exp > 0)
90 {
91 if (exp & 1)
92 result *= factor;
93 factor *= factor;
94 exp >>= 1;
95 }
96 return result;
97 }*/
98 template<>
99 constexpr fltp04 pow10(uint02 exp)
100 {
101 constexpr fltp04 table[] = {
102 1e0f, 1e1f, 1e2f, 1e3f, 1e4f, 1e5f, 1e6f, 1e7f, 1e8f, 1e9f,
103 1e10f, 1e11f, 1e12f, 1e13f, 1e14f, 1e15f, 1e16f, 1e17f, 1e18f, 1e19f,
104 1e20f, 1e21f, 1e22f, 1e23f, 1e24f, 1e25f, 1e26f, 1e27f, 1e28f, 1e29f,
105 1e30f, 1e31f, 1e32f, 1e33f, 1e34f, 1e35f, 1e36f, 1e37f, 1e38f
106 };
107 return (exp < 39) ? table[exp] : INFINITY;
108 }
109 template<>
110 constexpr fltp04 npow10(uint02 exp)
111 {
112 constexpr fltp04 table[] = {
113 1e-0f, 1e-1f, 1e-2f, 1e-3f, 1e-4f, 1e-5f, 1e-6f, 1e-7f, 1e-8f, 1e-9f,
114 1e-10f, 1e-11f, 1e-12f, 1e-13f, 1e-14f, 1e-15f, 1e-16f, 1e-17f, 1e-18f, 1e-19f,
115 1e-20f, 1e-21f, 1e-22f, 1e-23f, 1e-24f, 1e-25f, 1e-26f, 1e-27f, 1e-28f, 1e-29f,
116 1e-30f, 1e-31f, 1e-32f, 1e-33f, 1e-34f, 1e-35f, 1e-36f, 1e-37f, 1e-38f
117 };
118 return (exp < 39) ? table[exp] : 0.0f;
119 }
120 template<>
121 constexpr fltp08 pow10(uint16_t exp)
122 {
123 // Table of 10^0, 10^8, 10^16, ..., 10^304
124 constexpr fltp08 table[] = {
125 1e0, 1e8, 1e16, 1e24, 1e32, 1e40, 1e48, 1e56,
126 1e64, 1e72, 1e80, 1e88, 1e96, 1e104, 1e112, 1e120,
127 1e128, 1e136, 1e144, 1e152, 1e160, 1e168, 1e176, 1e184,
128 1e192, 1e200, 1e208, 1e216, 1e224, 1e232, 1e240, 1e248,
129 1e256, 1e264, 1e272, 1e280, 1e288, 1e296, 1e304
130 };
131
132 if (exp > 308)
133 return INFINITY;
134
135 const uint16_t block = exp / 8;
136 const uint16_t rem = exp % 8;
137
138 // Multiply 10^block by 10^rem computed inline
139 constexpr fltp08 pow10_small[] = {
140 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7
141 };
142
143 return table[block] * pow10_small[rem];
144 }
145 template<>
146 constexpr fltp08 npow10(uint16_t exp)
147 {
148 // Table stores 10^-0, 10^-8, 10^-16, ..., 10^-304
149 constexpr fltp08 table[] = {
150 1e0, 1e-8, 1e-16, 1e-24, 1e-32, 1e-40, 1e-48, 1e-56,
151 1e-64, 1e-72, 1e-80, 1e-88, 1e-96, 1e-104, 1e-112, 1e-120,
152 1e-128, 1e-136, 1e-144, 1e-152, 1e-160, 1e-168, 1e-176, 1e-184,
153 1e-192, 1e-200, 1e-208, 1e-216, 1e-224, 1e-232, 1e-240, 1e-248,
154 1e-256, 1e-264, 1e-272, 1e-280, 1e-288, 1e-296, 1e-304
155 };
156
157 if (exp > 308)
158 return 0.0;
159
160 const uint16_t block = exp / 8;
161 const uint16_t rem = exp % 8;
162
163 // Multiply 10^-block by 10^-rem computed inline
164 constexpr fltp08 pow10_inv[] = {
165 1e0, 1e-1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7
166 };
167
168 return table[block] * pow10_inv[rem];
169 }
170 class NumberParser
171 {
172 public:
173
174 template<class t_type>
175 static constexpr t_type parse(const char* in, const char** out = nullptr, t_type Invalid_Value = Constant<t_type>::Invalid, bool check_overflow = true)
176 {
177 if (in == nullptr)
178 return Constant<t_type>::Invalid;
179 return _parse(in, out, Invalid_Value, check_overflow);
180 }
181 template<class t_type>
182 static constexpr t_type parseUInt(const char* in, const char** out, t_type Invalid_Value, bool check_overflow)
183 {
184 if (*in < '0' || *in > '9')
185 {
186 if (out) *out = in;
187 return Invalid_Value;
188 }
189 t_type value = 0;
190 for (uint04 i = 0; i < MaxDigits<t_type>() - 1; i++)
191 {
192 if (*in < '0' || *in > '9')
193 {
194 check_overflow = false;
195 break;
196 }
197 value = (value * 10) + cast<t_type>(*in - '0');
198 ++in;
199 }
200 if (check_overflow)
201 {
202 if (*in >= '0' && *in <= '9')//read in last digit
203 {
204 t_type new_value = (value * 10) + (*in - '0');
205 ++in;
206 if (new_value < value)
207 {
208 value = Invalid_Value;
209 }
210 else
211 {
212 value = new_value;
213 if (*in > '0' && *in < '9')
214 value = Invalid_Value;
215 }
216 }
217 }
218 if (out)
219 *out = in;
220 return value;
221 }
222 // Number of relevant decimals for floating-point parsing.
223 template <class t_int_type, typename t_type>
224 static constexpr t_type parseFloat(const char* c, const char** out_s, t_type Invalid_Value, bool check_overflow)
225 {
226 if (c == nullptr)
227 {
228 if (out_s)
229 *out_s = c;
230 return Invalid_Value;
231 }
232 bool inv = (*c == '-');
233 if (inv || *c == '+')
234 ++c;
235 t_int_type value = 0;
236 if (*c != '.')
237 value = parse<t_int_type>(c, &c, Constant<t_int_type>::Invalid, check_overflow);
238 if (IsInvalid(value))
239 {
240 if (out_s)
241 *out_s = c;
242 return Invalid_Value;
243 }
244 t_type float_value = cast<t_type>(value);
245 if (*c == '.')
246 {
247 ++c;
248 const char* c_old = c;
249 value = parseUInt<t_int_type>(c, &c, Constant<t_int_type>::Invalid, false);
250 if (IsValid(value))
251 {
252 fltp08 pl = cast<fltp08>(value);
253 uint04 size = cast<uint04>(c - c_old);
254 pl *= fast_atof_table[size];
255 float_value += cast<t_type>(pl);
256 while (*c >= '0' && *c <= '9')//read in leftover
257 c++;
258 }
259 }
260 if (*c == 'e' || *c == 'E')
261 {
262 ++c;
263 bool inv_e = (*c == '-');
264 if (inv_e || *c == '+')
265 ++c;
266 uint02 val = parseUInt<uint02>(c, &c, Constant<uint02>::Invalid, check_overflow);
267 if (inv_e)
268 float_value *= npow10<t_type>(val);
269 else
270 float_value *= pow10<t_type>(val);
271 }
272 if (out_s)
273 *out_s = c;
274 if (inv)
275 float_value = -float_value;
276 return float_value;
277 }
278
279 // ------------------------------------------------------------------------------------
280 // Convert a string in hex format to a number
281 // ------------------------------------------------------------------------------------
282 static constexpr inline uint04 parseHex(const char* in, const char** out = nullptr)
283 {
284 uint04 value = 0;
285 for (;;)
286 {
287 if (*in >= '0' && *in <= '9')
288 value = (value << 4u) + (*in - '0');
289 else if (*in >= 'A' && *in <= 'F')
290 value = (value << 4u) + (*in - 'A') + 10;
291 else if (*in >= 'a' && *in <= 'f')
292 value = (value << 4u) + (*in - 'a') + 10;
293 else
294 break;
295 ++in;
296 }
297 if (out)*out = in;
298 return value;
299 }
300
301 // ------------------------------------------------------------------------------------
302 // Convert just one hex digit
303 // Return value is null if the input character is not a hex digit.
304 // ------------------------------------------------------------------------------------
305 template<class t_char_type>
306 static constexpr inline uint04 HexDigitToDecimal(t_char_type in)
307 {
308 uint04 out = Constant<uint04>::Invalid;
309 if (in >= '0' && in <= '9')
310 out = in - '0';
311 else if (in >= 'a' && in <= 'f')
312 out = 10u + in - 'a';
313 else if (in >= 'A' && in <= 'F')
314 out = 10u + in - 'A';
315 return out;
316 }
317
318 // ------------------------------------------------------------------------------------
319 // Convert a hex-encoded octet (2 characters, i.e. df or 1a).
320 // ------------------------------------------------------------------------------------
321 template<class t_char_type>
322 static constexpr inline uint01 HexOctetToDecimal(const t_char_type* in)
323 {
324 return (cast<uint01>(HexDigitToDecimal(in[0])) << 4) + cast<uint01>(HexDigitToDecimal(in[1]));
325 }
326 private:
327 static constexpr inline uint01 _parse(const char* in, const char** out, uint01 Invalid_Value, bool check_overflow)
328 {
329 if (*in == '+') in++;
330 return parseUInt(in, out, Invalid_Value, check_overflow);
331 }
332 static constexpr inline uint02 _parse(const char* in, const char** out, uint02 Invalid_Value, bool check_overflow)
333 {
334 if (*in == '+') in++;
335 return parseUInt(in, out, Invalid_Value, check_overflow);
336 }
337 static constexpr inline uint04 _parse(const char* in, const char** out, uint04 Invalid_Value, bool check_overflow)
338 {
339 if (*in == '+') in++;
340 return parseUInt(in, out, Invalid_Value, check_overflow);
341 }
342 static constexpr inline uint08 _parse(const char* in, const char** out, uint08 Invalid_Value, bool check_overflow)
343 {
344 if (*in == '+') in++;
345 return parseUInt(in, out, Invalid_Value, check_overflow);
346 }
347 static constexpr inline sint01 _parse(const char* in, const char** out, sint01 Invalid_Value, bool check_overflow)
348 {
349 bool inv = (*in == '-');
350 if (inv || *in == '+')
351 ++in;
352 sint01 value = parseUInt<sint01>(in, out, Constant<sint01>::Invalid, check_overflow);
353 if (IsInvalid(value))
354 return Invalid_Value;
355 return inv ? -value : value;
356 }
357 static constexpr inline sint02 _parse(const char* in, const char** out, sint02 Invalid_Value, bool check_overflow)
358 {
359 bool inv = (*in == '-');
360 if (inv || *in == '+')
361 ++in;
362 sint02 value = parseUInt<sint02>(in, out, Constant<sint02>::Invalid, check_overflow);
363 if (IsInvalid(value))
364 return Invalid_Value;
365 return inv ? -value : value;
366 }
367 static constexpr inline sint04 _parse(const char* in, const char** out, sint04 Invalid_Value, bool check_overflow)
368 {
369 bool inv = (*in == '-');
370 if (inv || *in == '+')
371 ++in;
372 sint04 value = parseUInt<sint04>(in, out, Constant<sint04>::Invalid, check_overflow);
373 if (IsInvalid(value))
374 return Invalid_Value;
375 return inv ? -value : value;
376 }
377 static constexpr inline sint08 _parse(const char* in, const char** out, sint08 Invalid_Value, bool check_overflow)
378 {
379 bool inv = (*in == '-');
380 if (inv || *in == '+')
381 ++in;
382 sint08 value = parseUInt<sint08>(in, out, Constant<sint08>::Invalid, check_overflow);
383 if (IsInvalid(value))
384 return Invalid_Value;
385 if (inv)
386 value = -value;
387 return value;
388 }
389 static constexpr inline fltp04 _parse(const char* in, const char** out, fltp04 Invalid_Value, bool check_overflow)
390 {
391 return parseFloat<uint04, fltp04>(in, out, Invalid_Value, check_overflow);
392 }
393 static constexpr inline fltp08 _parse(const char* in, const char** out, fltp08 Invalid_Value, bool check_overflow)
394 {
395 return parseFloat<uint08, fltp08>(in, out, Invalid_Value, check_overflow);
396 }
397 static constexpr inline Angle<sint04> _parse(const char* in, const char** out, Angle<sint04> Invalid_Value, bool check_overflow)
398 {
399 return Angle<sint04>(NumberParser::_parse(in, out, Invalid_Value.internal<false>(), check_overflow));
400 }
401 static constexpr inline Angle<fltp08> _parse(const char* in, const char** out, Angle<fltp08> Invalid_Value, bool check_overflow)
402 {
403 return Angle<fltp08>(NumberParser::_parse(in, out, Invalid_Value.internal<false>(), check_overflow));
404 }
405 static constexpr inline Angle<fltp04> _parse(const char* in, const char** out, Angle<fltp04> Invalid_Value, bool check_overflow)
406 {
407 return Angle<fltp04>(NumberParser::_parse(in, out, Invalid_Value.internal<false>(), check_overflow));
408 }
409 // ------------------------------------------------------------------------------------
410 // Convert a string in octal format to a number
411 // ------------------------------------------------------------------------------------
412 static constexpr inline uint04 parseOctal(const char* in, const char** out = nullptr)
413 {
414 uint04 value = 0;
415 for (;;)
416 {
417 if (*in < '0' || *in > '7')
418 break;
419 value = (value << 3) + (*in - '0');
420 ++in;
421 }
422 if (out)*out = in;
423 return value;
424 }
425 };
426 static_assert(NumberParser::parse<fltp04>("0.1234") == 0.1234f, "Bad parsing");
427 static_assert(NumberParser::parse<sint04>("43043") == 43043, "Bad parsing");
428 static_assert(NumberParser::parse<fltp08>("0.123456337891233") == 0.123456337891233, "Bad parsing");
429 static_assert(NumberParser::parse<fltp08>("2e54") == 2e54, "Bad parsing");
430 static_assert(NumberParser::parse<fltp08>("21e-222") == 21e-222, "Bad parsing");
431 static_assert(NumberParser::parse<fltp08>("21222bds") == 21222.0, "Bad parsing");
432 static_assert(NumberParser::parse<uint01>("255") == 255U, "Bad parsing");
433 static_assert(NumberParser::parse<uint01>("-126") == Constant<uint01>::Invalid, "Bad parsing");
434 static_assert(NumberParser::parse<sint01>("-128") == -128, "Bad parsing");
435 static_assert(NumberParser::parse<sint01>("-130") == -128, "Bad parsing");
436}//End namespace NDEVR
The primary namespace for the NDEVR SDK.
constexpr const fltp08 fast_atof_table[20]
Data for quick text to number lookup.
float fltp04
Defines an alias representing a 4 byte floating-point number Bit layout is as follows: -Sign: 1 bit a...
static constexpr bool IsValid(const Angle< t_type > &value)
Checks whether the given Angle holds a valid value.
Definition Angle.h:398
uint16_t uint02
-Defines an alias representing a 2 byte, unsigned integer -Can represent exact integer values 0 throu...
uint64_t uint08
-Defines an alias representing an 8 byte, unsigned integer
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
double fltp08
Defines an alias representing an 8 byte floating-point number.
int16_t sint02
-Defines an alias representing a 2 byte, signed integer.
int32_t sint04
-Defines an alias representing a 4 byte, signed integer.
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
static constexpr bool IsInvalid(const Angle< t_type > &value)
Checks whether the given Angle holds an invalid value.
Definition Angle.h:388
int8_t sint01
-Defines an alias representing a 1 byte, signed integer.
int64_t sint08
-Defines an alias representing an 8 byte, signed integer -Can represent exact integer values -9223372...
constexpr uint04 MaxDigits()
For a given number type, returns the maximum number of digits the number type can represent.
constexpr t_to cast(const Angle< t_from > &value)
Casts an Angle from one backing type to another.
Definition Angle.h:408