API Documentation
Loading...
Searching...
No Matches
NumberParser.hpp
Go to the documentation of this file.
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{
38 /**--------------------------------------------------------------------------------------------------
39 \brief Data for quick text to number lookup
40 **/
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
64 /**--------------------------------------------------------------------------------------------------
65 \brief For a given number type, returns the maximum number of digits the number type can represent
66 **/
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
83 {
84 public:
85 template<class t_type>
86 static t_type parse(const char* in, const char** out = nullptr, t_type Invalid_Value = Constant<t_type>::Invalid, bool check_overflow = true)
87 {
88 return _parse<t_type>(in, out, Invalid_Value, check_overflow);
89 }
90 template<class t_type>
91 static constexpr t_type parseUInt(const char* in, const char** out, t_type Invalid_Value, bool check_overflow)
92 {
93 if (*in < '0' || *in > '9')
94 {
95 if (out) *out = in;
96 return Invalid_Value;
97 }
98 t_type value = 0;
99 for (uint04 i = 0; i < MaxDigits<t_type>() - 1; i++)
100 {
101 if (*in < '0' || *in > '9')
102 {
103 check_overflow = false;
104 break;
105 }
106 value = (value * 10) + cast<t_type>(*in - '0');
107 ++in;
108 }
109 if (check_overflow)
110 {
111 if (*in >= '0' && *in <= '9')//read in last digit
112 {
113 t_type new_value = (value * 10) + (*in - '0');
114 ++in;
115 if (new_value < value)
116 {
117 value = Invalid_Value;
118 }
119 else
120 {
121 value = new_value;
122 if (*in > '0' && *in < '9')
123 value = Invalid_Value;
124 }
125 }
126 }
127 if (out)
128 *out = in;
129 return value;
130 }
131 // Number of relevant decimals for floating-point parsing.
132 template <class t_int_type, typename t_type>
133 static t_type parseFloat(const char* c, const char** out_s, t_type Invalid_Value, bool check_overflow)
134 {
135 if (c == nullptr)
136 {
137 if (out_s)
138 *out_s = c;
139 return Invalid_Value;
140 }
141 bool inv = (*c == '-');
142 if (inv || *c == '+')
143 ++c;
144 t_int_type value = 0;
145 if(*c != '.')
146 value = parse<t_int_type>(c, &c, Constant<t_int_type>::Invalid, check_overflow);
147 if (IsInvalid(value))
148 {
149 if (out_s)
150 *out_s = c;
151 return Invalid_Value;
152 }
153 t_type float_value = cast<t_type>(value);
154 if (*c == '.')
155 {
156 ++c;
157 const char* c_old = c;
159 if (!IsInvalid(value))
160 {
161 fltp08 pl = cast<fltp08>(value);
162 uint04 size = cast<uint04>(c - c_old);
163 pl *= fast_atof_table[size];
164 float_value += cast<t_type>(pl);
165 while (*c >= '0' && *c <= '9')//read in leftover
166 c++;
167 }
168 }
169 if (*c == 'e' || *c == 'E')
170 {
171 ++c;
172 float_value *= cast<t_type>(std::pow(cast<t_type>(10.0), parse<sint02>(c, &c, Constant<sint02>::Invalid, check_overflow)));
173 }
174 if(out_s)
175 *out_s = c;
176 if (inv)
177 float_value = -float_value;
178 return float_value;
179 }
180
181 // ------------------------------------------------------------------------------------
182 // Convert a string in hex format to a number
183 // ------------------------------------------------------------------------------------
184 static inline uint04 parseHex(const char* in, const char** out = nullptr)
185 {
186 uint04 value = 0;
187 for (;;)
188 {
189 if (*in >= '0' && *in <= '9')
190 value = (value << 4u) + (*in - '0');
191 else if (*in >= 'A' && *in <= 'F')
192 value = (value << 4u) + (*in - 'A') + 10;
193 else if (*in >= 'a' && *in <= 'f')
194 value = (value << 4u) + (*in - 'a') + 10;
195 else
196 break;
197 ++in;
198 }
199 if (out)*out = in;
200 return value;
201 }
202
203 // ------------------------------------------------------------------------------------
204 // Convert just one hex digit
205 // Return value is null if the input character is not a hex digit.
206 // ------------------------------------------------------------------------------------
207 template<class t_char_type>
208 static inline uint04 HexDigitToDecimal(t_char_type in)
209 {
211 if (in >= '0' && in <= '9')
212 out = in - '0';
213 else if (in >= 'a' && in <= 'f')
214 out = 10u + in - 'a';
215 else if (in >= 'A' && in <= 'F')
216 out = 10u + in - 'A';
217 return out;
218 }
219
220 // ------------------------------------------------------------------------------------
221 // Convert a hex-encoded octet (2 characters, i.e. df or 1a).
222 // ------------------------------------------------------------------------------------
223 template<class t_char_type>
224 static inline uint01 HexOctetToDecimal(const t_char_type* in)
225 {
226 return (cast<uint01>(HexDigitToDecimal(in[0])) << 4) + cast<uint01>(HexDigitToDecimal(in[1]));
227 }
228
229
230 private:
231 template<class t_type>
232 static t_type _parse(const char* in, const char** out, t_type Invalid_Value, bool check_overflow);
233
234 template<>
235 static inline uint01 _parse(const char* in, const char** out, uint01 Invalid_Value, bool check_overflow)
236 {
237 if (*in == '+') in++;
238 return parseUInt(in, out, Invalid_Value, check_overflow);
239 }
240 template<>
241 static inline uint02 _parse(const char* in, const char** out, uint02 Invalid_Value, bool check_overflow)
242 {
243 if (*in == '+') in++;
244 return parseUInt(in, out, Invalid_Value, check_overflow);
245 }
246 template<>
247 static inline uint04 _parse(const char* in, const char** out, uint04 Invalid_Value, bool check_overflow)
248 {
249 if (*in == '+') in++;
250 return parseUInt(in, out, Invalid_Value, check_overflow);
251 }
252 template<>
253 static inline uint08 _parse(const char* in, const char** out, uint08 Invalid_Value, bool check_overflow)
254 {
255 if (*in == '+') in++;
256 return parseUInt(in, out, Invalid_Value, check_overflow);
257 }
258 template<>
259 static inline sint01 _parse(const char* in, const char** out, sint01 Invalid_Value, bool check_overflow)
260 {
261 bool inv = (*in == '-');
262 if (inv || *in == '+')
263 ++in;
264 sint01 value = parseUInt<sint01>(in, out, Constant<sint01>::Invalid, check_overflow);
265 if (IsInvalid(value))
266 return Invalid_Value;
267 return inv ? -value : value;
268 }
269 template<>
270 static inline sint02 _parse(const char* in, const char** out, sint02 Invalid_Value, bool check_overflow)
271 {
272 bool inv = (*in == '-');
273 if (inv || *in == '+')
274 ++in;
275 sint02 value = parseUInt<sint02>(in, out, Constant<sint02>::Invalid, check_overflow);
276 if (IsInvalid(value))
277 return Invalid_Value;
278 return inv ? -value : value;
279 }
280
281 template<>
282 static inline sint04 _parse(const char* in, const char** out, sint04 Invalid_Value, bool check_overflow)
283 {
284 bool inv = (*in == '-');
285 if (inv || *in == '+')
286 ++in;
287 sint04 value = parseUInt<sint04>(in, out, Constant<sint04>::Invalid, check_overflow);
288 if (IsInvalid(value))
289 return Invalid_Value;
290 return inv ? -value : value;
291 }
292
293 template<>
294 static inline sint08 _parse(const char* in, const char** out, sint08 Invalid_Value, bool check_overflow)
295 {
296 bool inv = (*in == '-');
297 if (inv || *in == '+')
298 ++in;
299 sint08 value = parseUInt<sint08>(in, out, Constant<sint08>::Invalid, check_overflow);
300 if (IsInvalid(value))
301 return Invalid_Value;
302 if (inv)
303 value = -value;
304 return value;
305 }
306
307 // ------------------------------------------------------------------------------------
308 // The same but more human.
309 template<>
310 static inline fltp04 _parse(const char* in, const char** out, fltp04 Invalid_Value, bool check_overflow)
311 {
312 return parseFloat<uint04, fltp04>(in, out, Invalid_Value, check_overflow);
313 }
314
315 template<>
316 static inline fltp08 _parse(const char* in, const char** out, fltp08 Invalid_Value, bool check_overflow)
317 {
318 return parseFloat<uint08, fltp08>(in, out, Invalid_Value, check_overflow);
319 }
320 // ------------------------------------------------------------------------------------
321 // Convert a string in octal format to a number
322 // ------------------------------------------------------------------------------------
323 static inline uint04 parseOctal(const char* in, const char** out = nullptr)
324 {
325 uint04 value = 0;
326 for (;;)
327 {
328 if (*in < '0' || *in > '7')
329 break;
330 value = (value << 3) + (*in - '0');
331 ++in;
332 }
333 if (out)*out = in;
334 return value;
335 }
336
337
338
339 // ------------------------------------------------------------------------------------
340 // Parse a C++-like integer literal - hex and oct prefixes.
341 // 0xNNNN - hex
342 // 0NNN - oct
343 // NNN - dec
344 // ------------------------------------------------------------------------------------
345 template<class t_char_type>
346 static uint04 strtoul_cppstyle(const t_char_type* in, const t_char_type** out = nullptr)
347 {
348 if ('0' == in[0])
349 {
350 return 'x' == in[1] ? strtoul16(in + 2, out) : strtoul8(in + 1, out);
351 }
352 return strtoul10(in, out);
353 }
354 template<>
355 static inline Angle<sint04> _parse(const char* in, const char** out, Angle<sint04> Invalid_Value, bool check_overflow)
356 {
357 return Angle<sint04>(NumberParser::_parse<sint04>(in, out, Invalid_Value.internal<false>(), check_overflow));
358 }
359 template<>
360 static inline Angle<fltp08> _parse(const char* in, const char** out, Angle<fltp08> Invalid_Value, bool check_overflow)
361 {
362 return Angle<fltp08>(NumberParser::_parse<fltp08>(in, out, Invalid_Value.internal<false>(), check_overflow));
363 }
364 template<>
365 static inline Angle<fltp04> _parse(const char* in, const char** out, Angle<fltp04> Invalid_Value, bool check_overflow)
366 {
367 return Angle<fltp04>(NumberParser::_parse<fltp04>(in, out, Invalid_Value.internal<false>(), check_overflow));
368 }
369 };
370};//End namespace NDEVR
Definition NumberParser.hpp:83
static t_type parse(const char *in, const char **out=nullptr, t_type Invalid_Value=Constant< t_type >::Invalid, bool check_overflow=true)
Definition NumberParser.hpp:86
static constexpr t_type parseUInt(const char *in, const char **out, t_type Invalid_Value, bool check_overflow)
Definition NumberParser.hpp:91
static uint01 HexOctetToDecimal(const t_char_type *in)
Definition NumberParser.hpp:224
static uint04 HexDigitToDecimal(t_char_type in)
Definition NumberParser.hpp:208
static uint04 parseHex(const char *in, const char **out=nullptr)
Definition NumberParser.hpp:184
static t_type parseFloat(const char *c, const char **out_s, t_type Invalid_Value, bool check_overflow)
Definition NumberParser.hpp:133
Definition ACIColor.h:37
int32_t sint04
-Defines an alias representing a 4 byte, signed integer. -Can represent exact integer values -2147483...
Definition BaseValues.hpp:64
constexpr bool IsInvalid(const t_type &value)
Query if 'value' is valid or invalid. Invalid values should return invalid if used for calculations o...
Definition BaseFunctions.hpp:170
constexpr uint04 MaxDigits< uint02 >()
Definition NumberParser.hpp:73
int64_t sint08
-Defines an alias representing an 8 byte, signed integer -Can represent exact integer values -9223372...
Definition BaseValues.hpp:71
constexpr uint04 MaxDigits< uint04 >()
Definition NumberParser.hpp:76
constexpr uint04 MaxDigits()
For a given number type, returns the maximum number of digits the number type can represent.
constexpr uint04 MaxDigits< sint08 >()
Definition NumberParser.hpp:79
float fltp04
Defines an alias representing a 4 byte floating-point number Bit layout is as follows: -Sign: 1 bit a...
Definition BaseValues.hpp:127
constexpr const fltp08 fast_atof_table[20]
Data for quick text to number lookup.
Definition NumberParser.hpp:41
uint8_t uint01
-Defines an alias representing a 1 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:80
int8_t sint01
-Defines an alias representing a 1 byte, signed integer. -Can represent exact integer values -127 thr...
Definition BaseValues.hpp:50
constexpr uint04 MaxDigits< uint01 >()
Definition NumberParser.hpp:70
constexpr uint04 MaxDigits< sint04 >()
Definition NumberParser.hpp:77
constexpr uint04 MaxDigits< sint01 >()
Definition NumberParser.hpp:71
constexpr uint04 MaxDigits< uint08 >()
Definition NumberParser.hpp:80
int16_t sint02
-Defines an alias representing a 2 byte, signed integer. -Can represent exact integer values -32767 t...
Definition BaseValues.hpp:57
uint64_t uint08
-Defines an alias representing an 8 byte, unsigned integer
Definition BaseValues.hpp:106
constexpr uint04 MaxDigits< sint02 >()
Definition NumberParser.hpp:74
uint32_t uint04
-Defines an alias representing a 4 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:96
constexpr t_to cast(const Angle< t_from > &value)
Definition Angle.h:375
uint16_t uint02
-Defines an alias representing a 2 byte, unsigned integer -Can represent exact integer values 0 throu...
Definition BaseValues.hpp:88
double fltp08
Defines an alias representing an 8 byte floating-point number.
Definition BaseValues.hpp:149
Defines for a given type (such as sint04, fltp08, UUID, etc) a maximum, minimum, and reserved 'invali...
Definition BaseValues.hpp:233
static const t_type Invalid
Definition BaseValues.hpp:234