11#include " decimal.h"
22
3+ namespace
4+ {
5+ using namespace clickhouse ;
6+
7+ #ifdef ABSL_HAVE_INTRINSIC_INT128
8+ template <typename T>
9+ inline bool addOverflow (const Int128 & l, const T & r, Int128 * result)
10+ {
11+ __int128 res;
12+ const auto ret_value = __builtin_add_overflow (static_cast <__int128>(l), static_cast <__int128>(r), &res);
13+
14+ *result = res;
15+ return ret_value;
16+ }
17+
18+ template <typename T>
19+ inline bool mulOverflow (const Int128 & l, const T & r, Int128 * result)
20+ {
21+ __int128 res;
22+ const auto ret_value = __builtin_mul_overflow (static_cast <__int128>(l), static_cast <__int128>(r), &res);
23+
24+ *result = res;
25+ return ret_value;
26+ }
27+
28+ #else
29+ template <typename T>
30+ inline bool getSignBit (const T & v)
31+ {
32+ return std::signbit (v);
33+ }
34+
35+ inline bool getSignBit (const Int128 & v)
36+ {
37+ // static constexpr Int128 zero {};
38+ // return v < zero;
39+
40+ // Sign of the whole absl::int128 value is determined by sign of higher 64 bits.
41+ return absl::Int128High64 (v) < 0 ;
42+ }
43+
44+ inline bool addOverflow (const Int128 & l, const Int128 & r, Int128 * result)
45+ {
46+ // *result = l + r;
47+ // const auto result_sign = getSignBit(*result);
48+ // return l_sign == r_sign && l_sign != result_sign;
49+
50+ // Based on code from:
51+ // https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow#INT32C.Ensurethatoperationsonsignedintegersdonotresultinoverflow-CompliantSolution
52+ const auto r_positive = !getSignBit (r);
53+
54+ if ((r_positive && (l > (std::numeric_limits<Int128>::max () - r))) ||
55+ (!r_positive && (l < (std::numeric_limits<Int128>::min () - r)))) {
56+ return true ;
57+ }
58+ *result = l + r;
59+
60+ return false ;
61+ }
62+
63+ template <typename T>
64+ inline bool mulOverflow (const Int128 & l, const T & r, Int128 * result)
65+ {
66+ // Based on code from:
67+ // https://wiki.sei.cmu.edu/confluence/display/c/INT32-C.+Ensure+that+operations+on+signed+integers+do+not+result+in+overflow#INT32C.Ensurethatoperationsonsignedintegersdonotresultinoverflow-CompliantSolution.3
68+ const auto l_positive = !getSignBit (l);
69+ const auto r_positive = !getSignBit (r);
70+
71+ if (l_positive) {
72+ if (r_positive) {
73+ if (r != 0 && l > (std::numeric_limits<Int128>::max () / r)) {
74+ return true ;
75+ }
76+ } else {
77+ if (l != 0 && r < (std::numeric_limits<Int128>::min () / l)) {
78+ return true ;
79+ }
80+ }
81+ } else {
82+ if (r_positive) {
83+ if (r != 0 && l < (std::numeric_limits<Int128>::min () / r)) {
84+ return true ;
85+ }
86+ } else {
87+ if (l != 0 && (r < (std::numeric_limits<Int128>::max () / l))) {
88+ return true ;
89+ }
90+ }
91+ }
92+
93+ *result = l * r;
94+ return false ;
95+ }
96+ #endif
97+
98+ }
99+
3100namespace clickhouse {
4101
5102ColumnDecimal::ColumnDecimal (size_t precision, size_t scale)
@@ -57,8 +154,8 @@ void ColumnDecimal::Append(const std::string& value) {
57154
58155 has_dot = true ;
59156 } else if (*c >= ' 0' && *c <= ' 9' ) {
60- if (__builtin_mul_overflow (int_value, 10 , &int_value) ||
61- __builtin_add_overflow (int_value, *c - ' 0' , &int_value)) {
157+ if (mulOverflow (int_value, 10 , &int_value) ||
158+ addOverflow (int_value, *c - ' 0' , &int_value)) {
62159 throw std::runtime_error (" value is too big for 128-bit integer" );
63160 }
64161 } else {
@@ -72,7 +169,7 @@ void ColumnDecimal::Append(const std::string& value) {
72169 }
73170
74171 while (zeros) {
75- if (__builtin_mul_overflow (int_value, 10 , &int_value)) {
172+ if (mulOverflow (int_value, 10 , &int_value)) {
76173 throw std::runtime_error (" value is too big for 128-bit integer" );
77174 }
78175 --zeros;
0 commit comments