comparison OrthancStone/Sources/Toolbox/GenericToolbox.h @ 1512:244ad1e4e76a

reorganization of folders
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 07 Jul 2020 16:21:02 +0200
parents Framework/Toolbox/GenericToolbox.h@30deba7bc8e2
children 5887a4f8594b
comparison
equal deleted inserted replaced
1511:9dfeee74c1e6 1512:244ad1e4e76a
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21 #pragma once
22
23 #include <Compatibility.h>
24 #include <OrthancException.h>
25
26 #include <boost/shared_ptr.hpp>
27
28 #include <string>
29 #include <stdint.h>
30 #include <math.h>
31
32 #include <memory>
33
34 namespace OrthancStone
35 {
36 namespace GenericToolbox
37 {
38 /**
39 Fast floating point string validation.
40 No trimming applied, so the input must match regex
41 /^[-]?[0-9]*\.?[0-9]*([eE][-+]?[0-9]+)?$/
42 The following are allowed as edge cases: "" and "-"
43 */
44 inline bool LegitDoubleString(const char* text)
45 {
46 const char* p = text;
47 if(*p == '-')
48 p++;
49 size_t period = 0;
50 while(*p != 0)
51 {
52 if (*p >= '0' && *p <= '9')
53 ++p;
54 else if(*p == '.')
55 {
56 if(period > 0)
57 return false;
58 else
59 period++;
60 ++p;
61 }
62 else if (*p == 'e' || *p == 'E')
63 {
64 ++p;
65 if (*p == '-' || *p == '+')
66 ++p;
67 // "e+"/"E+" "e-"/"E-" or "e"/"E" must be followed by a number
68 if (!(*p >= '0' && *p <= '9'))
69 return false;
70
71 // these must be the last in the string
72 while(*p >= '0' && *p <= '9')
73 ++p;
74
75 return (*p == 0);
76 }
77 else
78 {
79 return false;
80 }
81 }
82 return true;
83 }
84
85 /**
86 Fast integer string validation.
87 No trimming applied, so the input must match regex /^-?[0-9]*$/
88 The following are allowed as edge cases: "" and "-"
89 */
90 inline bool LegitIntegerString(const char* text)
91 {
92 const char* p = text;
93 if (*p == '-')
94 p++;
95 while (*p != 0)
96 {
97 if (*p >= '0' && *p <= '9')
98 ++p;
99 else
100 return false;
101 }
102 return true;
103 }
104
105 /*
106 Fast string --> double conversion.
107 Must pass the LegitDoubleString test
108
109 String to doubles with at most 18 digits
110 */
111 inline bool StringToDouble(double& r, const char* text)
112 {
113 if(!LegitDoubleString(text))
114 return false;
115
116 static const double FRAC_FACTORS[] =
117 {
118 1.0,
119 0.1,
120 0.01,
121 0.001,
122 0.0001,
123 0.00001,
124 0.000001,
125 0.0000001,
126 0.00000001,
127 0.000000001,
128 0.0000000001,
129 0.00000000001,
130 0.000000000001,
131 0.0000000000001,
132 0.00000000000001,
133 0.000000000000001,
134 0.0000000000000001,
135 0.00000000000000001,
136 0.000000000000000001,
137 0.0000000000000000001
138 };
139 const size_t FRAC_FACTORS_LEN = sizeof(FRAC_FACTORS)/sizeof(double);
140
141 r = 0.0;
142 double neg = 1.0;
143 const char* p = text;
144
145 if (*p == '-')
146 {
147 neg = -1.0;
148 ++p;
149 }
150 // 12345.67890
151 while (*p >= '0' && *p <= '9')
152 {
153 r = (r*10.0) + (*p - '0'); // 1 12 123 123 12345
154 ++p;
155 }
156 if (*p == '.')
157 {
158 double f = 0.0;
159 size_t n = 1;
160 ++p;
161 while (*p >= '0' && *p <= '9' && n < FRAC_FACTORS_LEN)
162 {
163 f += (*p - '0') * FRAC_FACTORS[n];
164 ++p;
165 ++n;
166 }
167 r += f;
168 }
169 r *= neg;
170
171 // skip the remaining numbers until we reach not-a-digit (either the
172 // end of the string OR the scientific notation symbol)
173 while ((*p >= '0' && *p <= '9'))
174 ++p;
175
176 if (*p == 0 )
177 {
178 return true;
179 }
180 else if ((*p == 'e') || (*p == 'E'))
181 {
182 // process the scientific notation
183 double sign; // no init is safe (read below)
184 ++p;
185 if (*p == '-')
186 {
187 sign = -1.0;
188 // point to first number
189 ++p;
190 }
191 else if (*p == '+')
192 {
193 sign = 1.0;
194 // point to first number
195 ++p;
196 }
197 else if (*p >= '0' && *p <= '9')
198 {
199 sign = 1.0;
200 }
201 else
202 {
203 // only a sign char or a number is allowed
204 return false;
205 }
206 // now p points to the absolute value of the exponent
207 double exp = 0;
208 while (*p >= '0' && *p <= '9')
209 {
210 exp = (exp * 10.0) + static_cast<double>(*p - '0'); // 1 12 123 123 12345
211 ++p;
212 }
213 // now we have our exponent. put a sign on it.
214 exp *= sign;
215 double scFac = ::pow(10.0, exp);
216 r *= scFac;
217
218 // only allowed symbol here is EOS
219 return (*p == 0);
220 }
221 else
222 {
223 // not allowed
224 return false;
225 }
226 }
227
228 inline bool StringToDouble(double& r, const std::string& text)
229 {
230 return StringToDouble(r, text.c_str());
231 }
232
233 /**
234 Fast string to integer conversion. Leading zeroes and minus are accepted,
235 but a leading + sign is NOT.
236 Must pass the LegitIntegerString function test.
237 In addition, an empty string (or lone minus sign) yields 0.
238 */
239
240 template<typename T>
241 inline bool StringToInteger(T& r, const char* text)
242 {
243 if (!LegitIntegerString(text))
244 return false;
245
246 r = 0;
247 T neg = 1;
248 const char* p = text;
249
250 if (*p == '-')
251 {
252 neg = -1;
253 ++p;
254 }
255 while (*p >= '0' && *p <= '9')
256 {
257 r = (r * 10) + (*p - '0'); // 1 12 123 123 12345
258 ++p;
259 }
260 r *= neg;
261 if (*p == 0)
262 return true;
263 else
264 return false;
265 }
266
267 template<typename T>
268 inline bool StringToInteger(T& r, const std::string& text)
269 {
270 return StringToInteger<T>(r, text.c_str());
271 }
272
273 /**
274 if input is "rgb(12,23,255)" --> function fills `red`, `green` and `blue` and returns true
275 else ("everything else") --> function returns false and leaves all values untouched
276 */
277 bool GetRgbValuesFromString(uint8_t& red, uint8_t& green, uint8_t& blue, const char* text);
278
279 /**
280 See main overload
281 */
282 inline bool GetRgbValuesFromString(uint8_t& red, uint8_t& green, uint8_t& blue, const std::string& text)
283 {
284 return GetRgbValuesFromString(red, green, blue, text.c_str());
285 }
286
287 /**
288 Same as GetRgbValuesFromString
289 */
290 bool GetRgbaValuesFromString(uint8_t& red,
291 uint8_t& green,
292 uint8_t& blue,
293 uint8_t& alpha,
294 const char* text);
295
296 /**
297 Same as GetRgbValuesFromString
298 */
299 inline bool GetRgbaValuesFromString(uint8_t& red,
300 uint8_t& green,
301 uint8_t& blue,
302 uint8_t& alpha,
303 const std::string& text)
304 {
305 return GetRgbaValuesFromString(red, green, blue, alpha, text.c_str());
306 }
307 }
308 }