YARP
Yet Another Robot Platform
numeric.h
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2006-2021 Istituto Italiano di Tecnologia (IIT)
3  * All rights reserved.
4  *
5  * This software may be modified and distributed under the terms of the
6  * BSD-3-Clause license. See the accompanying LICENSE file for details.
7  */
8 
9 #ifndef YARP_CONFIG_NUMERIC_H
10 #define YARP_CONFIG_NUMERIC_H
11 
12 #define YARP_HAS_SYS_TYPES_H
13 
14 #if defined(YARP_HAS_SYS_TYPES_H)
15 # include <sys/types.h>
16 #endif
17 
18 #include <cfloat>
19 #include <cinttypes>
20 #include <clocale>
21 #include <cstdint>
22 #include <cstddef>
23 #include <cstdlib>
24 #include <cstring>
25 #include <limits>
26 #include <sstream>
27 #include <string>
28 #if defined (_MSC_VER)
29 # include <BaseTsd.h>
30 #endif
31 
32 /* #undef YARP_BIG_ENDIAN */
33 #define YARP_LITTLE_ENDIAN
34 
35 #define YARP_HAS_FLOAT128_T
36 #define YARP_FLOAT32_IS_IEC559 1
37 #define YARP_FLOAT64_IS_IEC559 1
38 #define YARP_FLOAT128_IS_IEC559 1
39 
40 // Ensure that float32_t, float64_t, and float128_t are not defined by some
41 // other header, included before this one.
42 #if defined(float32_t)
43 # undef float32_t
44 #endif
45 #if defined(float64_t)
46 # undef float64_t
47 #endif
48 #if defined(float128_t)
49 # undef float128_t
50 #endif
51 
52 
53 #define YARP_FLT_EXP_DIG 3
54 #define YARP_DBL_EXP_DIG 4
55 #define YARP_LDBL_EXP_DIG 5
56 
57 /*
58  * The maximum string length for a 'double' printed as a string using ("%.*g", DECIMAL_DIG) will be:
59  * Initial +/- sign 1 char
60  * First digit for exponential notation 1 char
61  * '.' decimal separator char 1 char
62  * DECIMAL_DIG digits for the mantissa DECIMAL_DIG chars
63  * 'e+/-' 2 chars
64  * YARP_DBL_EXP_DIG for the exponential YARP_DBL_EXP_DIG chars (YARP_LDBL_EXP_DIG if 128 bit float is available)
65  * string terminator 1 char
66  * FILLER 10 chars (you know, for safety)
67  * -----------------------------------------------------
68  * TOTAL is 16 + DECIMAL_DIG + YARP_DBL_EXP_DIG
69  */
70 #if defined(YARP_HAS_FLOAT128_T)
71 # define YARP_DOUBLE_TO_STRING_MAX_LENGTH (16 + DECIMAL_DIG + YARP_LDBL_EXP_DIG)
72 #else
73 # define YARP_DOUBLE_TO_STRING_MAX_LENGTH (16 + DECIMAL_DIG + YARP_DBL_EXP_DIG)
74 #endif
75 
76 namespace yarp {
77 namespace conf {
78 
79 typedef float float32_t;
80 typedef double float64_t;
81 typedef std::int32_t vocab32_t;
82 #if defined(YARP_HAS_FLOAT128_T)
83 typedef long double float128_t;
84 #endif
85 
86 #if defined (_MSC_VER)
87 typedef ::SSIZE_T ssize_t;
88 #else
90 #endif
91 
92 // Define `clamp` algorithm, available in c++17
93 template<class T>
94 constexpr const T& clamp( const T& v, const T& lo, const T& hi )
95 {
96  // assert( !(hi < lo) );
97  return (v < lo) ? lo : (hi < v) ? hi : v;
98 }
99 
100 template<class T, class Compare>
101 constexpr const T& clamp( const T& v, const T& lo, const T& hi, Compare comp )
102 {
103  // assert( !comp(hi, lo) );
104  return comp(v, lo) ? lo : comp(hi, v) ? hi : v;
105 }
106 
107 namespace numeric {
108 
109 #if !defined(SWIG)
110 
111 /*
112  * Converts an integer number to a string
113  */
114 template <typename Integer,
115  std::enable_if_t<
116  std::is_integral<Integer>::value &&
117  !std::is_same<Integer, bool>::value, bool> = true>
118 inline std::string to_string(Integer x)
119 {
120  return std::to_string(x);
121 }
122 
123 /*
124  * Converts a boolean to a string
125  */
126 template <typename Bool,
127  std::enable_if_t<std::is_same<Bool, bool>::value, bool> = true>
128 inline std::string to_string(Bool x)
129 {
130  return {x ? "true" : "false"};
131 }
132 
133 /*
134  * Converts a floating point number to a string, dealing with locale issues
135  */
136 template <typename Floating,
137  std::enable_if_t<std::is_floating_point<Floating>::value, bool> = true>
138 inline std::string to_string(Floating x)
139 {
140  char buf[YARP_DOUBLE_TO_STRING_MAX_LENGTH]; // -> see comment at the top of the file
141  std::snprintf(buf, YARP_DOUBLE_TO_STRING_MAX_LENGTH, "%.*g", DECIMAL_DIG, x);
142  std::string str(buf);
143 
144  // If locale is set, the locale version of the decimal point is used.
145  // In this case we change it to the standard "."
146  // If there is no decimal point, and it is not being used the exponential
147  // notation (i.e. the number is in integer form, for example 100000 and not
148  // 1e5) we add ".0" to ensure that it will be interpreted as a double.
149  struct lconv* lc = localeconv();
150  size_t offset = str.find(lc->decimal_point);
151  if (offset != std::string::npos) {
152  str[offset] = '.';
153  } else if (str.find('e') == std::string::npos && str != "inf" && str != "-inf" && str != "nan") {
154  str += ".0";
155  }
156  return str;
157 }
158 
159 /*
160  * Converts a string to a signed integer number
161  */
162 template <typename Integer,
163  std::enable_if_t<
164  std::is_integral<Integer>::value &&
165  std::is_signed<Integer>::value &&
166  !std::is_same<Integer, bool>::value, bool> = true>
167 inline Integer from_string(const std::string& src, Integer defaultValue = static_cast<Integer>(0))
168 {
169  char *endptr = nullptr;
170  const char* startptr = src.c_str();
171  static constexpr int base = 10;
172 
173  errno = 0;
174  auto ret = std::strtoll(startptr, &endptr, base);
175 
176  if (errno != 0) {
177  // An error occurred
178  return defaultValue;
179  }
180 
181  if (endptr == startptr) {
182  // No digits were found
183  return defaultValue;
184  }
185 
186  if (endptr != startptr + src.size()) {
187  // Not all the string was interpreted
188  return defaultValue;
189  }
190 
191  if (ret < std::numeric_limits<Integer>::min() || ret > std::numeric_limits<Integer>::max()) {
192  // Out of bound
193  return defaultValue;
194  }
195 
196  return static_cast<Integer>(ret);
197 }
198 
199 /*
200  * Converts a string to an unsigned integer number
201  */
202 template <typename Integer,
203  std::enable_if_t<
204  std::is_integral<Integer>::value &&
205  !std::is_signed<Integer>::value &&
206  !std::is_same<Integer, bool>::value, bool> = true>
207 inline Integer from_string(const std::string& src, Integer defaultValue = static_cast<Integer>(0))
208 {
209  char *endptr = nullptr;
210  const char* startptr = src.c_str();
211  static constexpr int base = 10;
212 
213  errno = 0;
214  auto ret = std::strtoull(startptr, &endptr, base);
215 
216  if (errno != 0) {
217  // An error occurred
218  return defaultValue;
219  }
220 
221  if (endptr == startptr) {
222  // No digits were found
223  return defaultValue;
224  }
225 
226  if (endptr != startptr + src.size()) {
227  // Not all the string was interpreted
228  return defaultValue;
229  }
230 
231  if (ret > std::numeric_limits<Integer>::max()) {
232  // Out of bound
233  return defaultValue;
234  }
235 
236  if (ret > std::numeric_limits<long long>::max() && std::strtoll(startptr, &endptr, base) < 0) {
237  // This is a negative number silently converted to unsigned
238  return defaultValue;
239  }
240 
241  return static_cast<Integer>(ret);
242 }
243 
244 
245 /*
246  * Converts a string to a boolean
247  */
248 template <typename Bool,
249  std::enable_if_t<std::is_same<Bool, bool>::value, bool> = true>
250 inline Bool from_string(const std::string& src, Bool defaultValue = false)
251 {
252  if (src == "1") { return true; }
253  if (src == "true") { return true; }
254  if (src == "True") { return true; }
255  if (src == "TRUE") { return true; }
256  if (src == "yes") { return true; }
257  if (src == "Yes") { return true; }
258  if (src == "YES") { return true; }
259  if (src == "on") { return true; }
260  if (src == "On") { return true; }
261  if (src == "ON") { return true; }
262 
263  if (src == "0") { return false; }
264  if (src == "false") { return false; }
265  if (src == "False") { return false; }
266  if (src == "FALSE") { return false; }
267  if (src == "no") { return false; }
268  if (src == "No") { return false; }
269  if (src == "NO") { return false; }
270  if (src == "off") { return false; }
271  if (src == "Off") { return false; }
272  if (src == "OFF") { return false; }
273 
274  return defaultValue;
275 }
276 
277 /*
278  * Converts a string to a floating point number, dealing with locale issues
279  */
280 template <typename Floating,
281  std::enable_if_t<std::is_floating_point<Floating>::value, bool> = true>
282 inline Floating from_string(const std::string& src, Floating defaultValue = static_cast<Floating>(0.0))
283 {
284  if (src == "inf") {
285  return std::numeric_limits<Floating>::infinity();
286  }
287  if (src == "-inf") {
288  return -std::numeric_limits<Floating>::infinity();
289  }
290  if (src == "nan") {
291  return std::numeric_limits<Floating>::quiet_NaN();
292  }
293  // Need to deal with alternate versions of the decimal point.
294  // We need a copy of the string where the decimal point can be replaced.
295  std::string src_c = src;
296  size_t offset = src.find('.');
297  if (offset != std::string::npos) {
298  struct lconv* lc = localeconv();
299  src_c[offset] = lc->decimal_point[0];
300  }
301 
302  char *endptr = nullptr;
303  const char* startptr = src_c.c_str();
304  auto ret = static_cast<Floating>(strtod(startptr, &endptr));
305 
306  if (endptr == startptr) {
307  // No digits were found
308  return defaultValue;
309  }
310 
311  if (endptr != startptr + src.size()) {
312  // Not all the string was interpreted
313  return defaultValue;
314  }
315 
316  return ret;
317 }
318 
319 template <typename Integer,
320  std::enable_if_t<
321  std::is_integral<Integer>::value &&
322  sizeof(Integer) != 1 &&
323  !std::is_same<Integer, bool>::value, bool> = true>
324 std::string to_hex_string(Integer i)
325 {
326  std::stringstream stream;
327  stream << std::hex << i;
328  return stream.str();
329 }
330 
331 // FIXME C++17 use constexpr if
332 template <typename Integer,
333  std::enable_if_t<sizeof(Integer) == 1, bool> = true>
334 std::string to_hex_string(Integer i)
335 {
336  // char and unsigned char are interpreted as characters, and therefore
337  // printed as the corresponding character
338  return to_hex_string<int>(static_cast<int>(static_cast<uint8_t>(i)));
339 }
340 
341 #endif // !defined(SWIG)
342 
343 } // namespace numeric
344 } // namespace conf
345 } // namespace yarp
346 
347 
348 #ifndef YARP_NO_DEPRECATED // since YARP 3.0.0
349 #include <yarp/conf/api.h> // For YARP_DEPRECATED_TYPEDEF_MSG
350 YARP_DEPRECATED_TYPEDEF_MSG("Use std::int8_t instead") std::int8_t YARP_INT8;
351 YARP_DEPRECATED_TYPEDEF_MSG("Use std::int16_t instead") std::int16_t YARP_INT16;
352 YARP_DEPRECATED_TYPEDEF_MSG("Use std::int32_t instead") std::int32_t YARP_INT32;
353 YARP_DEPRECATED_TYPEDEF_MSG("Use std::int64_t instead") std::int64_t YARP_INT64;
357 #define YARP_INT32_FMT PRId32
358 #define YARP_INT64_FMT PRId64
359 #endif // YARP_NO_DEPRECATED
360 
361 
362 #endif
bool ret
yarp::rosmsg::std_msgs::Bool Bool
Definition: Bool.h:24
std::string to_string(Integer x)
Definition: numeric.h:118
Integer from_string(const std::string &src, Integer defaultValue=static_cast< Integer >(0))
Definition: numeric.h:167
std::string to_hex_string(Integer i)
Definition: numeric.h:324
std::string to_string(Floating x)
Definition: numeric.h:138
std::int32_t vocab32_t
Definition: numeric.h:81
::ssize_t ssize_t
Definition: numeric.h:89
double float64_t
Definition: numeric.h:80
long double float128_t
Definition: numeric.h:83
constexpr const T & clamp(const T &v, const T &lo, const T &hi)
Definition: numeric.h:94
float float32_t
Definition: numeric.h:79
The main, catch-all namespace for YARP.
Definition: environment.h:25
yarp::conf::float32_t YARP_FLOAT32
Definition: numeric.h:354
std::int8_t YARP_INT8
Definition: numeric.h:350
std::int64_t YARP_INT64
Definition: numeric.h:353
std::int16_t YARP_INT16
Definition: numeric.h:351
std::int32_t YARP_INT32
Definition: numeric.h:352
#define YARP_DOUBLE_TO_STRING_MAX_LENGTH
Definition: numeric.h:71
yarp::conf::ssize_t YARP_SSIZE_T
Definition: numeric.h:356
yarp::conf::float64_t YARP_FLOAT64
Definition: numeric.h:355
#define YARP_DEPRECATED_TYPEDEF_MSG(x)
Definition: api.h:102