KSeExpr 6.0.0.0
Utils.cpp
Go to the documentation of this file.
1// SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
2// SPDX-License-Identifier: GPL-3.0-or-later
3
4#include "Utils.h"
5#include <cerrno>
6
7#if defined(KSeExpr_HAVE_CHARCONV_WITH_DOUBLES)
8#include <charconv>
9#include <cstring>
10
11double_t KSeExpr::Utils::atof(const char *num)
12{
13 double_t v;
14 auto [p, ec] = std::from_chars(num, num + std::strlen(num), v);
15 if (ec == std::errc()) {
16 return v;
17 } else {
18 return HUGE_VAL;
19 }
20}
21
22double_t KSeExpr::Utils::atof(const std::string &num)
23{
24 double_t v;
25 auto [p, ec] = std::from_chars(num.data(), num.data() + num.size(), v);
26 if (ec == std::errc()) {
27 return v;
28 } else {
29 return HUGE_VAL;
30 }
31}
32
33int32_t KSeExpr::Utils::strtol(const std::string &num)
34{
35 int32_t v;
36 auto [p, ec] = std::from_chars(num.data(), num.data() + num.size(), v);
37 if (ec == std::errc()) {
38 return v;
39 } else if (ec == std::errc::result_out_of_range) {
40 throw std::out_of_range {"KSeExpr::Utils::strtol: out of range"};
41 } else {
42 throw std::invalid_argument {"KSeExpr::Utils::strtol: impossible to parse the given number"};
43 }
44}
45
46#else
52{
53 if (!num) {
54 return 0;
55 }
56
57 double_t sign = 1;
58 double_t int_part = 0.0;
59 double_t frac_part = 0.0;
60 bool has_frac = false;
61 bool has_exp = false;
62
63 // +/- sign
64 if (*num == '-') {
65 ++num;
66 sign = -1;
67 } else if (*num == '+') {
68 ++num;
69 }
70
71 while (*num != '\0') {
72 if (*num >= '0' && *num <= '9') {
73 int_part = int_part * 10 + (*num - '0');
74 } else if (*num == '.') {
75 has_frac = true;
76 ++num;
77 break;
78 } else if (*num == 'e') {
79 has_exp = true;
80 ++num;
81 break;
82 } else {
83 return HUGE_VAL;
84 }
85 ++num;
86 }
87
88 if (has_frac) {
89 double_t frac_exp = 0.1; // NOLINT readability-magic-numbers
90
91 while (*num != '\0') {
92 if (*num >= '0' && *num <= '9') {
93 frac_part += frac_exp * (*num - '0');
94 frac_exp *= 0.1; // NOLINT readability-magic-numbers
95 } else if (*num == 'e') {
96 has_exp = true;
97 ++num;
98 break;
99 } else {
100 return HUGE_VAL;
101 }
102 ++num;
103 }
104 }
105
106 // parsing exponent part
107 double_t exp_part = 1.0;
108 if (*num != '\0' && has_exp) {
109 int exp_sign = 1;
110 if (*num == '-') {
111 exp_sign = -1;
112 ++num;
113 } else if (*num == '+') {
114 ++num;
115 }
116
117 int e = 0;
118 while (*num != '\0') {
119 if (*num >= '0' && *num <= '9') {
120 e = e * 10 + *num - '0'; // NOLINT readability-magic-numbers
121 } else {
122 return HUGE_VAL;
123 }
124
125 ++num;
126 }
127
128 exp_part = pow(exp_sign * e, 10); // NOLINT readability-magic-numbers
129 }
130
131 return sign * (int_part + frac_part) * exp_part;
132}
133
135{
136 return Utils::atof(num.data());
137}
138
140{
141 char *ptr {nullptr};
142 // integer numbers only use dots
143 const auto result {std::strtol(num.c_str(), &ptr, 10)};
144 if (ptr == num.c_str())
145 throw std::invalid_argument {"KSeExpr::Utils::atoi: impossible to parse the given number"};
146 else if (ptr != num.c_str() + num.size())
147 throw std::invalid_argument {"KSeExpr::Utils::atoi: the string had invalid extra characters"};
148 else if (errno == ERANGE)
149 throw std::out_of_range {"KSeExpr::Utils::atoi: out of range"};
150 return result;
151}
152
153#endif // defined(HAVE_CHARCONV_WITH_DOUBLES)
154
155// Dynamically dispatchable functions.
156// These have to be in a namespace, otherwise GCC chokes.
157// See https://stackoverflow.com/questions/19785010/gcc-function-multiversioning-and-namespaces
158
159namespace KSeExpr
160{
161namespace Utils
162{
164{
165 return std::round(val);
166}
167
169{
170 return std::floor(val);
171}
172
173#if defined(KSeExpr_HAVE_DYNAMIC_DISPATCH)
175{
177}
178
179KSeExpr_SSE41 double_t floor(double_t val)
180{
181 return _mm_cvtsd_f64(_mm_floor_sd(_mm_set_sd(0.0), _mm_set_sd(val)));
182}
183#endif
184} // namespace Utils
185} // namespace KSeExpr
#define KSeExpr_DEFAULT
Definition Utils.h:18
static constexpr std::array< int, 514 > p
Definition NoiseTables.h:10
KSeExpr_DEFAULT double_t round(double_t val)
Definition Utils.cpp:163
KSeExpr_DEFAULT double_t floor(double_t val)
Definition Utils.cpp:168
int32_t strtol(const char *num)
double_t atof(const char *num)
Definition Utils.cpp:51