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
16namespace duckdb {
17
18template <class SRC, class DST>
19static 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
65template <class SRC, class T>
66bool 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
78template <>
79bool TryCastWithOverflowCheck(float value, int8_t &result) {
80 return TryCastWithOverflowCheckFloat<float, int8_t>(value, result, min: -128.0f, max: 128.0f);
81}
82
83template <>
84bool TryCastWithOverflowCheck(float value, int16_t &result) {
85 return TryCastWithOverflowCheckFloat<float, int16_t>(value, result, min: -32768.0f, max: 32768.0f);
86}
87
88template <>
89bool TryCastWithOverflowCheck(float value, int32_t &result) {
90 return TryCastWithOverflowCheckFloat<float, int32_t>(value, result, min: -2147483648.0f, max: 2147483648.0f);
91}
92
93template <>
94bool TryCastWithOverflowCheck(float value, int64_t &result) {
95 return TryCastWithOverflowCheckFloat<float, int64_t>(value, result, min: -9223372036854775808.0f,
96 max: 9223372036854775808.0f);
97}
98
99template <>
100bool TryCastWithOverflowCheck(float value, uint8_t &result) {
101 return TryCastWithOverflowCheckFloat<float, uint8_t>(value, result, min: 0.0f, max: 256.0f);
102}
103
104template <>
105bool TryCastWithOverflowCheck(float value, uint16_t &result) {
106 return TryCastWithOverflowCheckFloat<float, uint16_t>(value, result, min: 0.0f, max: 65536.0f);
107}
108
109template <>
110bool TryCastWithOverflowCheck(float value, uint32_t &result) {
111 return TryCastWithOverflowCheckFloat<float, uint32_t>(value, result, min: 0.0f, max: 4294967296.0f);
112}
113
114template <>
115bool TryCastWithOverflowCheck(float value, uint64_t &result) {
116 return TryCastWithOverflowCheckFloat<float, uint64_t>(value, result, min: 0.0f, max: 18446744073709551616.0f);
117}
118
119template <>
120bool TryCastWithOverflowCheck(double value, int8_t &result) {
121 return TryCastWithOverflowCheckFloat<double, int8_t>(value, result, min: -128.0, max: 128.0);
122}
123
124template <>
125bool TryCastWithOverflowCheck(double value, int16_t &result) {
126 return TryCastWithOverflowCheckFloat<double, int16_t>(value, result, min: -32768.0, max: 32768.0);
127}
128
129template <>
130bool TryCastWithOverflowCheck(double value, int32_t &result) {
131 return TryCastWithOverflowCheckFloat<double, int32_t>(value, result, min: -2147483648.0, max: 2147483648.0);
132}
133
134template <>
135bool TryCastWithOverflowCheck(double value, int64_t &result) {
136 return TryCastWithOverflowCheckFloat<double, int64_t>(value, result, min: -9223372036854775808.0, max: 9223372036854775808.0);
137}
138
139template <>
140bool TryCastWithOverflowCheck(double value, uint8_t &result) {
141 return TryCastWithOverflowCheckFloat<double, uint8_t>(value, result, min: 0.0, max: 256.0);
142}
143
144template <>
145bool TryCastWithOverflowCheck(double value, uint16_t &result) {
146 return TryCastWithOverflowCheckFloat<double, uint16_t>(value, result, min: 0.0, max: 65536.0);
147}
148
149template <>
150bool TryCastWithOverflowCheck(double value, uint32_t &result) {
151 return TryCastWithOverflowCheckFloat<double, uint32_t>(value, result, min: 0.0, max: 4294967296.0);
152}
153
154template <>
155bool TryCastWithOverflowCheck(double value, uint64_t &result) {
156 return TryCastWithOverflowCheckFloat<double, uint64_t>(value, result, min: 0.0, max: 18446744073709551615.0);
157}
158template <>
159bool TryCastWithOverflowCheck(float input, float &result) {
160 result = input;
161 return true;
162}
163template <>
164bool TryCastWithOverflowCheck(float input, double &result) {
165 result = double(input);
166 return true;
167}
168template <>
169bool TryCastWithOverflowCheck(double input, double &result) {
170 result = input;
171 return true;
172}
173
174template <>
175bool 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//===--------------------------------------------------------------------===//
191template <>
192bool TryCastWithOverflowCheck(bool value, bool &result) {
193 result = bool(value);
194 return true;
195}
196
197template <>
198bool TryCastWithOverflowCheck(int8_t value, bool &result) {
199 result = bool(value);
200 return true;
201}
202
203template <>
204bool TryCastWithOverflowCheck(int16_t value, bool &result) {
205 result = bool(value);
206 return true;
207}
208
209template <>
210bool TryCastWithOverflowCheck(int32_t value, bool &result) {
211 result = bool(value);
212 return true;
213}
214
215template <>
216bool TryCastWithOverflowCheck(int64_t value, bool &result) {
217 result = bool(value);
218 return true;
219}
220
221template <>
222bool TryCastWithOverflowCheck(uint8_t value, bool &result) {
223 result = bool(value);
224 return true;
225}
226
227template <>
228bool TryCastWithOverflowCheck(uint16_t value, bool &result) {
229 result = bool(value);
230 return true;
231}
232
233template <>
234bool TryCastWithOverflowCheck(uint32_t value, bool &result) {
235 result = bool(value);
236 return true;
237}
238
239template <>
240bool TryCastWithOverflowCheck(uint64_t value, bool &result) {
241 result = bool(value);
242 return true;
243}
244
245template <>
246bool TryCastWithOverflowCheck(float value, bool &result) {
247 result = bool(value);
248 return true;
249}
250
251template <>
252bool TryCastWithOverflowCheck(double value, bool &result) {
253 result = bool(value);
254 return true;
255}
256
257template <>
258bool 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//===--------------------------------------------------------------------===//
266template <>
267bool TryCastWithOverflowCheck(bool value, int8_t &result) {
268 result = int8_t(value);
269 return true;
270}
271
272template <>
273bool TryCastWithOverflowCheck(bool value, int16_t &result) {
274 result = int16_t(value);
275 return true;
276}
277
278template <>
279bool TryCastWithOverflowCheck(bool value, int32_t &result) {
280 result = int32_t(value);
281 return true;
282}
283
284template <>
285bool TryCastWithOverflowCheck(bool value, int64_t &result) {
286 result = int64_t(value);
287 return true;
288}
289
290template <>
291bool TryCastWithOverflowCheck(bool value, uint8_t &result) {
292 result = uint8_t(value);
293 return true;
294}
295
296template <>
297bool TryCastWithOverflowCheck(bool value, uint16_t &result) {
298 result = uint16_t(value);
299 return true;
300}
301
302template <>
303bool TryCastWithOverflowCheck(bool value, uint32_t &result) {
304 result = uint32_t(value);
305 return true;
306}
307
308template <>
309bool TryCastWithOverflowCheck(bool value, uint64_t &result) {
310 result = uint64_t(value);
311 return true;
312}
313
314template <>
315bool TryCastWithOverflowCheck(bool value, float &result) {
316 result = float(value);
317 return true;
318}
319
320template <>
321bool TryCastWithOverflowCheck(bool value, double &result) {
322 result = double(value);
323 return true;
324}
325
326template <>
327bool 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//===--------------------------------------------------------------------===//
336template <>
337bool TryCastWithOverflowCheck(int8_t value, hugeint_t &result) {
338 return Hugeint::TryConvert(value, result);
339}
340
341template <>
342bool TryCastWithOverflowCheck(int16_t value, hugeint_t &result) {
343 return Hugeint::TryConvert(value, result);
344}
345
346template <>
347bool TryCastWithOverflowCheck(int32_t value, hugeint_t &result) {
348 return Hugeint::TryConvert(value, result);
349}
350
351template <>
352bool TryCastWithOverflowCheck(int64_t value, hugeint_t &result) {
353 return Hugeint::TryConvert(value, result);
354}
355
356template <>
357bool TryCastWithOverflowCheck(uint8_t value, hugeint_t &result) {
358 return Hugeint::TryConvert(value, result);
359}
360
361template <>
362bool TryCastWithOverflowCheck(uint16_t value, hugeint_t &result) {
363 return Hugeint::TryConvert(value, result);
364}
365
366template <>
367bool TryCastWithOverflowCheck(uint32_t value, hugeint_t &result) {
368 return Hugeint::TryConvert(value, result);
369}
370
371template <>
372bool TryCastWithOverflowCheck(uint64_t value, hugeint_t &result) {
373 return Hugeint::TryConvert(value, result);
374}
375
376template <>
377bool TryCastWithOverflowCheck(float value, hugeint_t &result) {
378 return Hugeint::TryConvert(value: std::nearbyintf(x: value), result);
379}
380
381template <>
382bool TryCastWithOverflowCheck(double value, hugeint_t &result) {
383 return Hugeint::TryConvert(value: std::nearbyint(x: value), result);
384}
385
386template <>
387bool TryCastWithOverflowCheck(hugeint_t value, hugeint_t &result) {
388 result = value;
389 return true;
390}
391
392//===--------------------------------------------------------------------===//
393// Cast Hugeint -> Numeric
394//===--------------------------------------------------------------------===//
395template <>
396bool TryCastWithOverflowCheck(hugeint_t value, int8_t &result) {
397 return Hugeint::TryCast(input: value, result);
398}
399
400template <>
401bool TryCastWithOverflowCheck(hugeint_t value, int16_t &result) {
402 return Hugeint::TryCast(input: value, result);
403}
404
405template <>
406bool TryCastWithOverflowCheck(hugeint_t value, int32_t &result) {
407 return Hugeint::TryCast(input: value, result);
408}
409
410template <>
411bool TryCastWithOverflowCheck(hugeint_t value, int64_t &result) {
412 return Hugeint::TryCast(input: value, result);
413}
414
415template <>
416bool TryCastWithOverflowCheck(hugeint_t value, uint8_t &result) {
417 return Hugeint::TryCast(input: value, result);
418}
419
420template <>
421bool TryCastWithOverflowCheck(hugeint_t value, uint16_t &result) {
422 return Hugeint::TryCast(input: value, result);
423}
424
425template <>
426bool TryCastWithOverflowCheck(hugeint_t value, uint32_t &result) {
427 return Hugeint::TryCast(input: value, result);
428}
429
430template <>
431bool TryCastWithOverflowCheck(hugeint_t value, uint64_t &result) {
432 return Hugeint::TryCast(input: value, result);
433}
434
435template <>
436bool TryCastWithOverflowCheck(hugeint_t value, float &result) {
437 return Hugeint::TryCast(input: value, result);
438}
439
440template <>
441bool TryCastWithOverflowCheck(hugeint_t value, double &result) {
442 return Hugeint::TryCast(input: value, result);
443}
444
445struct 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
452struct 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