Branch data Line data Source code
1 : : #ifndef PPARSEFP_H
2 : : #define PPARSEFP_H
3 : :
4 : : /*
5 : : * Parses a float or double number and returns the length parsed if
6 : : * successful. The length argument is of limited value due to dependency
7 : : * on `strtod` - buf[len] must be accessible and must not be part of
8 : : * a valid number, including hex float numbers..
9 : : *
10 : : * Unlike strtod, whitespace is not parsed.
11 : : *
12 : : * May return:
13 : : * - null on error,
14 : : * - buffer start if first character does not start a number,
15 : : * - or end of parse on success.
16 : : *
17 : : */
18 : :
19 : : #define PDIAGNOSTIC_IGNORE_UNUSED_FUNCTION
20 : : #include "pdiagnostic_push.h"
21 : :
22 : : /*
23 : : * isinf is needed in order to stay compatible with strtod's
24 : : * over/underflow handling but isinf has some portability issues.
25 : : *
26 : : * Use the parse_double/float_is_range_error instead of isinf directly.
27 : : * This ensures optimizations can be added when not using strtod.
28 : : *
29 : : * On gcc, clang and msvc we can use isinf or equivalent directly.
30 : : * Other compilers such as xlc may require linking with -lm which may not
31 : : * be convienent so a default isinf is provided. If isinf is available
32 : : * and there is a noticable performance issue, define
33 : : * `PORTABLE_USE_ISINF`.
34 : : */
35 : : #if defined(__GNUC__) || defined(__clang__) || defined(_MSC_VER) || defined(PORTABLE_USE_ISINF)
36 : : #include <math.h>
37 : : #if defined(_MSC_VER) && !defined(isinf)
38 : : #include <float.h>
39 : : #define isnan _isnan
40 : : #define isinf(x) (!_finite(x))
41 : : #endif
42 : : #define parse_double_isinf isinf
43 : : #define parse_float_isinf isinf
44 : : #else
45 : :
46 : : #ifndef UINT8_MAX
47 : : #include <stdint.h>
48 : : #endif
49 : :
50 : : /* Avoid linking with libmath but depends on float/double being IEEE754 */
51 : : static inline int parse_double_isinf(double x)
52 : : {
53 : : union { uint64_t u64; double f64; } v;
54 : : v.f64 = x;
55 : : return (v.u64 & 0x7fffffff00000000ULL) == 0x7ff0000000000000ULL;
56 : : }
57 : :
58 : : static inline int parse_float_isinf(float x)
59 : : {
60 : : union { uint32_t u32; float f32; } v;
61 : : v.f32 = x;
62 : : return (v.u32 & 0x7fffffff) == 0x7f800000;
63 : : }
64 : : #endif
65 : :
66 : : /* Returns 0 when in range, 1 on overflow, and -1 on underflow. */
67 : : static inline int parse_double_is_range_error(double x)
68 : : {
69 [ # # ][ # # ]: 0 : return parse_double_isinf(x) ? (x < 0.0 ? -1 : 1) : 0;
70 : : }
71 : :
72 : : static inline int parse_float_is_range_error(float x)
73 : : {
74 [ # # ][ # # ]: 0 : return parse_float_isinf(x) ? (x < 0.0f ? -1 : 1) : 0;
75 : : }
76 : :
77 : : #ifndef PORTABLE_USE_GRISU3
78 : : #define PORTABLE_USE_GRISU3 1
79 : : #endif
80 : :
81 : : #if PORTABLE_USE_GRISU3
82 : : #include "grisu3_parse.h"
83 : : #endif
84 : :
85 : : #ifdef grisu3_parse_double_is_defined
86 : : static inline const char *parse_double(const char *buf, int len, double *result)
87 : : {
88 : 5 : return grisu3_parse_double(buf, len, result);
89 : : }
90 : : #else
91 : : #include <stdio.h>
92 : : static inline const char *parse_double(const char *buf, int len, double *result)
93 : : {
94 : : char *end;
95 : :
96 : : (void)len;
97 : : *result = strtod(buf, &end);
98 : : return end;
99 : : }
100 : : #endif
101 : :
102 : : static inline const char *parse_float(const char *buf, int len, float *result)
103 : : {
104 : : const char *end;
105 : : double v;
106 : :
107 : : end = parse_double(buf, len, &v);
108 : 3 : *result = (float)v;
109 : : return end;
110 : : }
111 : :
112 : : #include "pdiagnostic_pop.h"
113 : : #endif /* PPARSEFP_H */
|