1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) NGINX, Inc.
5 */
6
7 #ifndef _NJS_NUMBER_H_INCLUDED_
8 #define _NJS_NUMBER_H_INCLUDED_
9
10
11 #define NJS_MAX_LENGTH (0x1fffffffffffffLL)
12 #define NJS_INT64_DBL_MIN (-9.223372036854776e+18) /* closest to INT64_MIN */
13 #define NJS_INT64_DBL_MAX (9.223372036854776e+18) /* closest to INT64_MAX */
14
15
16 double njs_key_to_index(const njs_value_t *value);
17 double njs_number_dec_parse(const u_char **start, const u_char *end,
18 njs_bool_t literal);
19 uint64_t njs_number_oct_parse(const u_char **start, const u_char *end);
20 uint64_t njs_number_bin_parse(const u_char **start, const u_char *end);
21 uint64_t njs_number_hex_parse(const u_char **start, const u_char *end,
22 njs_bool_t literal);
23 int64_t njs_number_radix_parse(const u_char **start, const u_char *end,
24 uint8_t radix);
25 njs_int_t njs_number_to_string(njs_vm_t *vm, njs_value_t *string,
26 const njs_value_t *number);
27 njs_int_t njs_number_to_chain(njs_vm_t *vm, njs_chb_t *chain,
28 double number);
29 njs_int_t njs_number_global_is_nan(njs_vm_t *vm, njs_value_t *args,
30 njs_uint_t nargs, njs_index_t unused);
31 njs_int_t njs_number_global_is_finite(njs_vm_t *vm, njs_value_t *args,
32 njs_uint_t nargs, njs_index_t unused);
33 njs_int_t njs_number_parse_int(njs_vm_t *vm, njs_value_t *args,
34 njs_uint_t nargs, njs_index_t unused);
35 njs_int_t njs_number_parse_float(njs_vm_t *vm, njs_value_t *args,
36 njs_uint_t nargs, njs_index_t unused);
37
38
39 njs_inline njs_bool_t
njs_number_is_integer_index(double num)40 njs_number_is_integer_index(double num)
41 {
42 uint32_t u32;
43
44 u32 = num;
45
46 return (u32 == num && u32 != 0xffffffff);
47 }
48
49
50 njs_inline njs_bool_t
njs_key_is_integer_index(double num,const njs_value_t * value)51 njs_key_is_integer_index(double num, const njs_value_t *value)
52 {
53 return (njs_number_is_integer_index(num))
54 && !(njs_is_string(value) && num == 0 && signbit(num));
55 }
56
57
58 njs_inline int64_t
njs_number_to_integer(double num)59 njs_number_to_integer(double num)
60 {
61 if (njs_fast_path(!isnan(num))) {
62 if (num < NJS_INT64_DBL_MIN) {
63 return INT64_MIN;
64
65 } else if (num > NJS_INT64_DBL_MAX) {
66 return INT64_MAX;
67 }
68
69 return num;
70 }
71
72 return 0;
73 }
74
75
76 njs_inline int32_t
njs_number_to_int32(double num)77 njs_number_to_int32(double num)
78 {
79 uint32_t r;
80 uint64_t v;
81 njs_int_t exp;
82 njs_diyfp_conv_t conv;
83
84 conv.d = num;
85
86 exp = (conv.u64 & NJS_DBL_EXPONENT_MASK) >> NJS_DBL_SIGNIFICAND_SIZE;
87
88 if (njs_fast_path(exp < (NJS_DBL_EXPONENT_OFFSET + 31))) {
89 /* |num| < 2**31. */
90 return num;
91 }
92
93 if (exp < (NJS_DBL_EXPONENT_OFFSET + 31 + 53)) {
94 v = (conv.u64 & NJS_DBL_SIGNIFICAND_MASK) | NJS_DBL_HIDDEN_BIT;
95 v <<= (exp - NJS_DBL_EXPONENT_BIAS + 32);
96 r = v >> 32;
97
98 if (conv.u64 & NJS_DBL_SIGN_MASK) {
99 r = -r;
100 }
101
102 return r;
103 }
104
105 /*
106 * ES5.1: integer must be modulo 2^32.
107 * The distance between larger doubles
108 * (exp >= NJS_DBL_EXPONENT_OFFSET + 31 + 53) is a multiple of 2**32 => 0.
109 * This also handles NaN and Inf.
110 */
111
112 return 0;
113 }
114
115
116 njs_inline uint32_t
njs_number_to_uint32(double num)117 njs_number_to_uint32(double num)
118 {
119 return (uint32_t) njs_number_to_int32(num);
120 }
121
122
123 njs_inline uint16_t
njs_number_to_uint16(double num)124 njs_number_to_uint16(double num)
125 {
126 return (uint16_t) njs_number_to_int32(num);
127 }
128
129
130 njs_inline uint64_t
njs_number_to_length(double num)131 njs_number_to_length(double num)
132 {
133 if (isnan(num)) {
134 return 0;
135 }
136
137 if (num > NJS_MAX_LENGTH) {
138 return NJS_MAX_LENGTH;
139
140 } else if (num < 0.0) {
141 return 0;
142 }
143
144 return (uint64_t) num;
145 }
146
147
148 njs_inline njs_int_t
njs_char_to_hex(u_char c)149 njs_char_to_hex(u_char c)
150 {
151 c |= 0x20;
152
153 /* Values less than '0' become >= 208. */
154 c = c - '0';
155
156 if (c > 9) {
157 /* Values less than 'a' become >= 159. */
158 c = c - ('a' - '0');
159
160 if (njs_slow_path(c > 5)) {
161 return -1;
162 }
163
164 c += 10;
165 }
166
167 return c;
168 }
169
170
171 njs_inline void
njs_uint32_to_string(njs_value_t * value,uint32_t u32)172 njs_uint32_to_string(njs_value_t *value, uint32_t u32)
173 {
174 u_char *dst, *p;
175
176 dst = njs_string_short_start(value);
177 p = njs_sprintf(dst, dst + NJS_STRING_SHORT, "%uD", u32);
178
179 njs_string_short_set(value, p - dst, p - dst);
180 }
181
182
183 extern const njs_object_type_init_t njs_number_type_init;
184
185
186 #endif /* _NJS_NUMBER_H_INCLUDED_ */
187