1 | //===----------------------------------------------------------------------===// |
2 | // DuckDB |
3 | // |
4 | // duckdb/common/operator/numeric_cast.hpp |
5 | // |
6 | // |
7 | //===----------------------------------------------------------------------===// |
8 | |
9 | #pragma once |
10 | |
11 | #include "duckdb/common/operator/cast_operators.hpp" |
12 | #include "duckdb/common/types/hugeint.hpp" |
13 | #include "duckdb/common/types/value.hpp" |
14 | #include <cmath> |
15 | |
16 | namespace duckdb { |
17 | |
18 | template <class SRC, class DST> |
19 | static bool TryCastWithOverflowCheck(SRC value, DST &result) { |
20 | if (!Value::IsFinite<SRC>(value)) { |
21 | return false; |
22 | } |
23 | if (NumericLimits<SRC>::IsSigned() != NumericLimits<DST>::IsSigned()) { |
24 | if (NumericLimits<SRC>::IsSigned()) { |
25 | // signed to unsigned conversion |
26 | if (NumericLimits<SRC>::Digits() > NumericLimits<DST>::Digits()) { |
27 | if (value < 0 || value > (SRC)NumericLimits<DST>::Maximum()) { |
28 | return false; |
29 | } |
30 | } else { |
31 | if (value < 0) { |
32 | return false; |
33 | } |
34 | } |
35 | result = (DST)value; |
36 | return true; |
37 | } else { |
38 | // unsigned to signed conversion |
39 | if (NumericLimits<SRC>::Digits() >= NumericLimits<DST>::Digits()) { |
40 | if (value <= (SRC)NumericLimits<DST>::Maximum()) { |
41 | result = (DST)value; |
42 | return true; |
43 | } |
44 | return false; |
45 | } else { |
46 | result = (DST)value; |
47 | return true; |
48 | } |
49 | } |
50 | } else { |
51 | // same sign conversion |
52 | if (NumericLimits<DST>::Digits() >= NumericLimits<SRC>::Digits()) { |
53 | result = (DST)value; |
54 | return true; |
55 | } else { |
56 | if (value < SRC(NumericLimits<DST>::Minimum()) || value > SRC(NumericLimits<DST>::Maximum())) { |
57 | return false; |
58 | } |
59 | result = (DST)value; |
60 | return true; |
61 | } |
62 | } |
63 | } |
64 | |
65 | template <class SRC, class T> |
66 | bool TryCastWithOverflowCheckFloat(SRC value, T &result, SRC min, SRC max) { |
67 | if (!Value::IsFinite<SRC>(value)) { |
68 | return false; |
69 | } |
70 | if (!(value >= min && value < max)) { |
71 | return false; |
72 | } |
73 | // PG FLOAT => INT casts use statistical rounding. |
74 | result = std::nearbyint(value); |
75 | return true; |
76 | } |
77 | |
78 | template <> |
79 | bool TryCastWithOverflowCheck(float value, int8_t &result) { |
80 | return TryCastWithOverflowCheckFloat<float, int8_t>(value, result, min: -128.0f, max: 128.0f); |
81 | } |
82 | |
83 | template <> |
84 | bool TryCastWithOverflowCheck(float value, int16_t &result) { |
85 | return TryCastWithOverflowCheckFloat<float, int16_t>(value, result, min: -32768.0f, max: 32768.0f); |
86 | } |
87 | |
88 | template <> |
89 | bool TryCastWithOverflowCheck(float value, int32_t &result) { |
90 | return TryCastWithOverflowCheckFloat<float, int32_t>(value, result, min: -2147483648.0f, max: 2147483648.0f); |
91 | } |
92 | |
93 | template <> |
94 | bool TryCastWithOverflowCheck(float value, int64_t &result) { |
95 | return TryCastWithOverflowCheckFloat<float, int64_t>(value, result, min: -9223372036854775808.0f, |
96 | max: 9223372036854775808.0f); |
97 | } |
98 | |
99 | template <> |
100 | bool TryCastWithOverflowCheck(float value, uint8_t &result) { |
101 | return TryCastWithOverflowCheckFloat<float, uint8_t>(value, result, min: 0.0f, max: 256.0f); |
102 | } |
103 | |
104 | template <> |
105 | bool TryCastWithOverflowCheck(float value, uint16_t &result) { |
106 | return TryCastWithOverflowCheckFloat<float, uint16_t>(value, result, min: 0.0f, max: 65536.0f); |
107 | } |
108 | |
109 | template <> |
110 | bool TryCastWithOverflowCheck(float value, uint32_t &result) { |
111 | return TryCastWithOverflowCheckFloat<float, uint32_t>(value, result, min: 0.0f, max: 4294967296.0f); |
112 | } |
113 | |
114 | template <> |
115 | bool TryCastWithOverflowCheck(float value, uint64_t &result) { |
116 | return TryCastWithOverflowCheckFloat<float, uint64_t>(value, result, min: 0.0f, max: 18446744073709551616.0f); |
117 | } |
118 | |
119 | template <> |
120 | bool TryCastWithOverflowCheck(double value, int8_t &result) { |
121 | return TryCastWithOverflowCheckFloat<double, int8_t>(value, result, min: -128.0, max: 128.0); |
122 | } |
123 | |
124 | template <> |
125 | bool TryCastWithOverflowCheck(double value, int16_t &result) { |
126 | return TryCastWithOverflowCheckFloat<double, int16_t>(value, result, min: -32768.0, max: 32768.0); |
127 | } |
128 | |
129 | template <> |
130 | bool TryCastWithOverflowCheck(double value, int32_t &result) { |
131 | return TryCastWithOverflowCheckFloat<double, int32_t>(value, result, min: -2147483648.0, max: 2147483648.0); |
132 | } |
133 | |
134 | template <> |
135 | bool TryCastWithOverflowCheck(double value, int64_t &result) { |
136 | return TryCastWithOverflowCheckFloat<double, int64_t>(value, result, min: -9223372036854775808.0, max: 9223372036854775808.0); |
137 | } |
138 | |
139 | template <> |
140 | bool TryCastWithOverflowCheck(double value, uint8_t &result) { |
141 | return TryCastWithOverflowCheckFloat<double, uint8_t>(value, result, min: 0.0, max: 256.0); |
142 | } |
143 | |
144 | template <> |
145 | bool TryCastWithOverflowCheck(double value, uint16_t &result) { |
146 | return TryCastWithOverflowCheckFloat<double, uint16_t>(value, result, min: 0.0, max: 65536.0); |
147 | } |
148 | |
149 | template <> |
150 | bool TryCastWithOverflowCheck(double value, uint32_t &result) { |
151 | return TryCastWithOverflowCheckFloat<double, uint32_t>(value, result, min: 0.0, max: 4294967296.0); |
152 | } |
153 | |
154 | template <> |
155 | bool TryCastWithOverflowCheck(double value, uint64_t &result) { |
156 | return TryCastWithOverflowCheckFloat<double, uint64_t>(value, result, min: 0.0, max: 18446744073709551615.0); |
157 | } |
158 | template <> |
159 | bool TryCastWithOverflowCheck(float input, float &result) { |
160 | result = input; |
161 | return true; |
162 | } |
163 | template <> |
164 | bool TryCastWithOverflowCheck(float input, double &result) { |
165 | result = double(input); |
166 | return true; |
167 | } |
168 | template <> |
169 | bool TryCastWithOverflowCheck(double input, double &result) { |
170 | result = input; |
171 | return true; |
172 | } |
173 | |
174 | template <> |
175 | bool TryCastWithOverflowCheck(double input, float &result) { |
176 | if (!Value::IsFinite(input)) { |
177 | result = float(input); |
178 | return true; |
179 | } |
180 | auto res = float(input); |
181 | if (!Value::FloatIsFinite(value: input)) { |
182 | return false; |
183 | } |
184 | result = res; |
185 | return true; |
186 | } |
187 | |
188 | //===--------------------------------------------------------------------===// |
189 | // Cast Numeric -> bool |
190 | //===--------------------------------------------------------------------===// |
191 | template <> |
192 | bool TryCastWithOverflowCheck(bool value, bool &result) { |
193 | result = bool(value); |
194 | return true; |
195 | } |
196 | |
197 | template <> |
198 | bool TryCastWithOverflowCheck(int8_t value, bool &result) { |
199 | result = bool(value); |
200 | return true; |
201 | } |
202 | |
203 | template <> |
204 | bool TryCastWithOverflowCheck(int16_t value, bool &result) { |
205 | result = bool(value); |
206 | return true; |
207 | } |
208 | |
209 | template <> |
210 | bool TryCastWithOverflowCheck(int32_t value, bool &result) { |
211 | result = bool(value); |
212 | return true; |
213 | } |
214 | |
215 | template <> |
216 | bool TryCastWithOverflowCheck(int64_t value, bool &result) { |
217 | result = bool(value); |
218 | return true; |
219 | } |
220 | |
221 | template <> |
222 | bool TryCastWithOverflowCheck(uint8_t value, bool &result) { |
223 | result = bool(value); |
224 | return true; |
225 | } |
226 | |
227 | template <> |
228 | bool TryCastWithOverflowCheck(uint16_t value, bool &result) { |
229 | result = bool(value); |
230 | return true; |
231 | } |
232 | |
233 | template <> |
234 | bool TryCastWithOverflowCheck(uint32_t value, bool &result) { |
235 | result = bool(value); |
236 | return true; |
237 | } |
238 | |
239 | template <> |
240 | bool TryCastWithOverflowCheck(uint64_t value, bool &result) { |
241 | result = bool(value); |
242 | return true; |
243 | } |
244 | |
245 | template <> |
246 | bool TryCastWithOverflowCheck(float value, bool &result) { |
247 | result = bool(value); |
248 | return true; |
249 | } |
250 | |
251 | template <> |
252 | bool TryCastWithOverflowCheck(double value, bool &result) { |
253 | result = bool(value); |
254 | return true; |
255 | } |
256 | |
257 | template <> |
258 | bool TryCastWithOverflowCheck(hugeint_t input, bool &result) { |
259 | result = input.upper != 0 || input.lower != 0; |
260 | return true; |
261 | } |
262 | |
263 | //===--------------------------------------------------------------------===// |
264 | // Cast bool -> Numeric |
265 | //===--------------------------------------------------------------------===// |
266 | template <> |
267 | bool TryCastWithOverflowCheck(bool value, int8_t &result) { |
268 | result = int8_t(value); |
269 | return true; |
270 | } |
271 | |
272 | template <> |
273 | bool TryCastWithOverflowCheck(bool value, int16_t &result) { |
274 | result = int16_t(value); |
275 | return true; |
276 | } |
277 | |
278 | template <> |
279 | bool TryCastWithOverflowCheck(bool value, int32_t &result) { |
280 | result = int32_t(value); |
281 | return true; |
282 | } |
283 | |
284 | template <> |
285 | bool TryCastWithOverflowCheck(bool value, int64_t &result) { |
286 | result = int64_t(value); |
287 | return true; |
288 | } |
289 | |
290 | template <> |
291 | bool TryCastWithOverflowCheck(bool value, uint8_t &result) { |
292 | result = uint8_t(value); |
293 | return true; |
294 | } |
295 | |
296 | template <> |
297 | bool TryCastWithOverflowCheck(bool value, uint16_t &result) { |
298 | result = uint16_t(value); |
299 | return true; |
300 | } |
301 | |
302 | template <> |
303 | bool TryCastWithOverflowCheck(bool value, uint32_t &result) { |
304 | result = uint32_t(value); |
305 | return true; |
306 | } |
307 | |
308 | template <> |
309 | bool TryCastWithOverflowCheck(bool value, uint64_t &result) { |
310 | result = uint64_t(value); |
311 | return true; |
312 | } |
313 | |
314 | template <> |
315 | bool TryCastWithOverflowCheck(bool value, float &result) { |
316 | result = float(value); |
317 | return true; |
318 | } |
319 | |
320 | template <> |
321 | bool TryCastWithOverflowCheck(bool value, double &result) { |
322 | result = double(value); |
323 | return true; |
324 | } |
325 | |
326 | template <> |
327 | bool TryCastWithOverflowCheck(bool input, hugeint_t &result) { |
328 | result.upper = 0; |
329 | result.lower = input ? 1 : 0; |
330 | return true; |
331 | } |
332 | |
333 | //===--------------------------------------------------------------------===// |
334 | // Cast Numeric -> hugeint |
335 | //===--------------------------------------------------------------------===// |
336 | template <> |
337 | bool TryCastWithOverflowCheck(int8_t value, hugeint_t &result) { |
338 | return Hugeint::TryConvert(value, result); |
339 | } |
340 | |
341 | template <> |
342 | bool TryCastWithOverflowCheck(int16_t value, hugeint_t &result) { |
343 | return Hugeint::TryConvert(value, result); |
344 | } |
345 | |
346 | template <> |
347 | bool TryCastWithOverflowCheck(int32_t value, hugeint_t &result) { |
348 | return Hugeint::TryConvert(value, result); |
349 | } |
350 | |
351 | template <> |
352 | bool TryCastWithOverflowCheck(int64_t value, hugeint_t &result) { |
353 | return Hugeint::TryConvert(value, result); |
354 | } |
355 | |
356 | template <> |
357 | bool TryCastWithOverflowCheck(uint8_t value, hugeint_t &result) { |
358 | return Hugeint::TryConvert(value, result); |
359 | } |
360 | |
361 | template <> |
362 | bool TryCastWithOverflowCheck(uint16_t value, hugeint_t &result) { |
363 | return Hugeint::TryConvert(value, result); |
364 | } |
365 | |
366 | template <> |
367 | bool TryCastWithOverflowCheck(uint32_t value, hugeint_t &result) { |
368 | return Hugeint::TryConvert(value, result); |
369 | } |
370 | |
371 | template <> |
372 | bool TryCastWithOverflowCheck(uint64_t value, hugeint_t &result) { |
373 | return Hugeint::TryConvert(value, result); |
374 | } |
375 | |
376 | template <> |
377 | bool TryCastWithOverflowCheck(float value, hugeint_t &result) { |
378 | return Hugeint::TryConvert(value: std::nearbyintf(x: value), result); |
379 | } |
380 | |
381 | template <> |
382 | bool TryCastWithOverflowCheck(double value, hugeint_t &result) { |
383 | return Hugeint::TryConvert(value: std::nearbyint(x: value), result); |
384 | } |
385 | |
386 | template <> |
387 | bool TryCastWithOverflowCheck(hugeint_t value, hugeint_t &result) { |
388 | result = value; |
389 | return true; |
390 | } |
391 | |
392 | //===--------------------------------------------------------------------===// |
393 | // Cast Hugeint -> Numeric |
394 | //===--------------------------------------------------------------------===// |
395 | template <> |
396 | bool TryCastWithOverflowCheck(hugeint_t value, int8_t &result) { |
397 | return Hugeint::TryCast(input: value, result); |
398 | } |
399 | |
400 | template <> |
401 | bool TryCastWithOverflowCheck(hugeint_t value, int16_t &result) { |
402 | return Hugeint::TryCast(input: value, result); |
403 | } |
404 | |
405 | template <> |
406 | bool TryCastWithOverflowCheck(hugeint_t value, int32_t &result) { |
407 | return Hugeint::TryCast(input: value, result); |
408 | } |
409 | |
410 | template <> |
411 | bool TryCastWithOverflowCheck(hugeint_t value, int64_t &result) { |
412 | return Hugeint::TryCast(input: value, result); |
413 | } |
414 | |
415 | template <> |
416 | bool TryCastWithOverflowCheck(hugeint_t value, uint8_t &result) { |
417 | return Hugeint::TryCast(input: value, result); |
418 | } |
419 | |
420 | template <> |
421 | bool TryCastWithOverflowCheck(hugeint_t value, uint16_t &result) { |
422 | return Hugeint::TryCast(input: value, result); |
423 | } |
424 | |
425 | template <> |
426 | bool TryCastWithOverflowCheck(hugeint_t value, uint32_t &result) { |
427 | return Hugeint::TryCast(input: value, result); |
428 | } |
429 | |
430 | template <> |
431 | bool TryCastWithOverflowCheck(hugeint_t value, uint64_t &result) { |
432 | return Hugeint::TryCast(input: value, result); |
433 | } |
434 | |
435 | template <> |
436 | bool TryCastWithOverflowCheck(hugeint_t value, float &result) { |
437 | return Hugeint::TryCast(input: value, result); |
438 | } |
439 | |
440 | template <> |
441 | bool TryCastWithOverflowCheck(hugeint_t value, double &result) { |
442 | return Hugeint::TryCast(input: value, result); |
443 | } |
444 | |
445 | struct NumericTryCast { |
446 | template <class SRC, class DST> |
447 | static inline bool Operation(SRC input, DST &result, bool strict = false) { |
448 | return TryCastWithOverflowCheck(input, result); |
449 | } |
450 | }; |
451 | |
452 | struct NumericCast { |
453 | template <class SRC, class DST> |
454 | static inline DST Operation(SRC input) { |
455 | DST result; |
456 | if (!NumericTryCast::Operation(input, result)) { |
457 | throw InvalidInputException(CastExceptionText<SRC, DST>(input)); |
458 | } |
459 | return result; |
460 | } |
461 | }; |
462 | |
463 | } // namespace duckdb |
464 | |