From 649550c5abd4d6d4b12f3ae2654a8e3bbaa3cd8d Mon Sep 17 00:00:00 2001 From: Alexey Milovidov Date: Sun, 25 Apr 2021 12:30:43 +0300 Subject: [PATCH] Attempt to normalize big integers --- base/common/DecomposedFloat.h | 199 ++++++++ base/common/arithmeticOverflow.h | 28 +- base/common/wide_integer_impl.h | 4 +- src/Common/FieldVisitorsAccurateComparison.h | 8 +- src/Common/HashTable/Hash.h | 46 +- .../tests/gtest_compressionCodec.cpp | 2 +- src/Core/AccurateComparison.h | 472 ++++-------------- src/Core/Field.h | 2 + src/Core/Types.h | 2 + src/DataStreams/MongoDBBlockInputStream.cpp | 2 +- src/DataTypes/DataTypeDecimalBase.h | 10 +- src/DataTypes/DataTypesDecimal.h | 4 +- .../Serializations/SerializationUUID.cpp | 8 +- src/Functions/FunctionBinaryArithmetic.h | 8 +- src/Functions/FunctionsConversion.h | 4 +- src/Functions/GatherUtils/Algorithms.h | 6 +- src/Functions/GatherUtils/ArraySinkVisitor.h | 2 +- .../GatherUtils/ArraySourceVisitor.h | 2 +- .../GatherUtils/ValueSourceVisitor.h | 2 +- src/Functions/GatherUtils/createArraySink.cpp | 2 +- .../GatherUtils/createArraySource.cpp | 2 +- .../GatherUtils/createValueSource.cpp | 2 +- src/Functions/array/arrayAggregation.cpp | 11 +- .../array/arrayCumSumNonNegative.cpp | 4 +- src/Functions/array/arrayDifference.cpp | 2 +- src/Functions/array/arrayIntersect.cpp | 2 + src/Functions/generateUUIDv4.cpp | 4 +- src/Functions/roundToExp2.cpp | 12 - src/IO/MMappedFileCache.h | 6 +- src/IO/ReadHelpers.h | 2 +- src/IO/WriteHelpers.h | 81 +-- src/Interpreters/ExpressionJIT.h | 1 + src/Interpreters/HashJoin.cpp | 2 +- src/Interpreters/convertFieldToType.cpp | 2 +- .../Transforms/LimitByTransform.cpp | 2 +- src/Processors/Transforms/LimitByTransform.h | 2 +- src/Processors/Transforms/WindowTransform.cpp | 11 +- src/Processors/Transforms/WindowTransform.h | 1 + .../MergeTree/MergeTreeDataPartUUID.cpp | 2 + src/Storages/System/StorageSystemQuotas.cpp | 2 +- src/Storages/System/StorageSystemRoles.cpp | 2 +- .../System/StorageSystemRowPolicies.cpp | 2 +- .../System/StorageSystemSettingsProfiles.cpp | 2 +- src/Storages/System/StorageSystemUsers.cpp | 2 +- 44 files changed, 414 insertions(+), 560 deletions(-) create mode 100644 base/common/DecomposedFloat.h diff --git a/base/common/DecomposedFloat.h b/base/common/DecomposedFloat.h new file mode 100644 index 00000000000..7a82bd1944b --- /dev/null +++ b/base/common/DecomposedFloat.h @@ -0,0 +1,199 @@ +#pragma once + +#include +#include +#include + + +/// Allows to check the internals of IEEE-754 floating point number. + +template struct FloatTraits; + +template <> +struct FloatTraits +{ + using UInt = uint32_t; + static constexpr size_t bits = 32; + static constexpr size_t exponent_bits = 8; + static constexpr size_t mantissa_bits = bits - exponent_bits - 1; +}; + +template <> +struct FloatTraits +{ + using UInt = uint64_t; + static constexpr size_t bits = 64; + static constexpr size_t exponent_bits = 11; + static constexpr size_t mantissa_bits = bits - exponent_bits - 1; +}; + + +/// x = sign * (2 ^ normalized_exponent) * (1 + mantissa * 2 ^ -mantissa_bits) +/// x = sign * (2 ^ normalized_exponent + mantissa * 2 ^ (normalized_exponent - mantissa_bits)) +template +struct DecomposedFloat +{ + using Traits = FloatTraits; + + DecomposedFloat(T x) + { + memcpy(&x_uint, &x, sizeof(x)); + } + + typename Traits::UInt x_uint; + + bool sign() const + { + return x_uint >> (Traits::bits - 1); + } + + uint16_t exponent() const + { + return (x_uint >> (Traits::mantissa_bits)) & (((1ull << (Traits::exponent_bits + 1)) - 1) >> 1); + } + + int16_t normalized_exponent() const + { + return int16_t(exponent()) - ((1ull << (Traits::exponent_bits - 1)) - 1); + } + + uint64_t mantissa() const + { + return x_uint & ((1ull << Traits::mantissa_bits) - 1); + } + + int64_t mantissa_with_sign() const + { + return sign() ? -mantissa() : mantissa(); + } + + /// NOTE Probably floating point instructions can be better. + bool is_integer_in_representable_range() const + { + return x_uint == 0 + || (normalized_exponent() >= 0 /// The number is not less than one + /// The number is inside the range where every integer has exact representation in float + && normalized_exponent() <= static_cast(Traits::mantissa_bits) + /// After multiplying by 2^exp, the fractional part becomes zero, means the number is integer + && ((mantissa() & ((1ULL << (Traits::mantissa_bits - normalized_exponent())) - 1)) == 0)); + } + + + template + bool equals(Int rhs) + { + /// Different signs + if ((rhs < 0) != sign()) + return false; + + if (rhs == 0 && x_uint == 0) + return true; + + /// Fractional number + if (normalized_exponent() < 0) + return false; + + /// Too large number + if (normalized_exponent() >= static_cast(8 * sizeof(Int) + is_signed_v)) + return false; + + using UInt = make_unsigned_t; + UInt uint_rhs = rhs < 0 ? -rhs : rhs; + + /// Smaller octave + if (uint_rhs < (static_cast(1) << normalized_exponent())) + return false; + + /// Larger octave + if (normalized_exponent() + 1 < static_cast(8 * sizeof(Int) + is_signed_v) + && uint_rhs >= (static_cast(1) << (normalized_exponent() + 1))) + return false; + + /// The same octave + /// uint_rhs == 2 ^ normalized_exponent + mantissa * 2 ^ (normalized_exponent - mantissa_bits) + + /// After multiplying by 2^exp, the fractional part becomes zero, means the number is integer + if ((mantissa() & ((1ULL << (Traits::mantissa_bits - normalized_exponent())) - 1)) != 0) + return false; + + /// uint_rhs - 2 ^ normalized_exponent == mantissa * 2 ^ (normalized_exponent - mantissa_bits) + return uint_rhs - (static_cast(1) << normalized_exponent()) == (mantissa() >> (Traits::mantissa_bits - normalized_exponent())); + } + + + template + bool less(Int rhs) + { + /// Different signs + if (sign() && rhs >= 0) + return true; + if (!sign() && rhs < 0) + return false; + if (rhs == 0) + return sign(); + + /// Fractional number + if (normalized_exponent() < 0) + { + if (!sign()) + return rhs > 0; + else + return rhs >= 0; + } + + /// Too large number + if (normalized_exponent() >= static_cast(8 * sizeof(Int) + is_signed_v)) + return sign(); + + using UInt = make_unsigned_t; + UInt uint_rhs = rhs < 0 ? -rhs : rhs; + + /// Smaller octave + if (uint_rhs < (static_cast(1) << normalized_exponent())) + return !sign(); + + /// Larger octave + if (normalized_exponent() + 1 < static_cast(8 * sizeof(Int) + is_signed_v) + && uint_rhs >= (static_cast(1) << (normalized_exponent() + 1))) + return sign(); + + /// The same octave + /// uint_rhs == 2 ^ normalized_exponent + mantissa * 2 ^ (normalized_exponent - mantissa_bits) + + typename Traits::UInt a = mantissa() >> (Traits::mantissa_bits - normalized_exponent()); + typename Traits::UInt b = uint_rhs - (static_cast(1) << normalized_exponent()); + + if (a < b) + return !sign(); + if (a > b) + return sign(); + + if ((mantissa() & ((1ULL << (Traits::mantissa_bits - normalized_exponent())) - 1)) == 0) + return !sign(); + else + return sign(); + } + + + template + bool greaterOrEquals(Int rhs) + { + return !less(rhs); + } + + template + bool lessOrEquals(Int rhs) + { + return less(rhs) || equals(rhs); + } + + template + bool greater(Int rhs) + { + return !lessOrEquals(rhs); + } +}; + + +using DecomposedFloat64 = DecomposedFloat; +using DecomposedFloat32 = DecomposedFloat; diff --git a/base/common/arithmeticOverflow.h b/base/common/arithmeticOverflow.h index f264b0be649..06a2ba216fb 100644 --- a/base/common/arithmeticOverflow.h +++ b/base/common/arithmeticOverflow.h @@ -56,12 +56,18 @@ namespace common } template <> - inline bool addOverflow(__int128 x, __int128 y, __int128 & res) + inline bool addOverflow(Int128 x, Int128 y, Int128 & res) { - static constexpr __int128 min_int128 = minInt128(); - static constexpr __int128 max_int128 = maxInt128(); res = addIgnoreOverflow(x, y); - return (y > 0 && x > max_int128 - y) || (y < 0 && x < min_int128 - y); + return (y > 0 && x > std::numeric_limits::max() - y) || + (y < 0 && x < std::numeric_limits::min() - y); + } + + template <> + inline bool addOverflow(UInt128 x, UInt128 y, UInt128 & res) + { + res = addIgnoreOverflow(x, y); + return x > std::numeric_limits::max() - y; } template <> @@ -104,12 +110,18 @@ namespace common } template <> - inline bool subOverflow(__int128 x, __int128 y, __int128 & res) + inline bool subOverflow(Int128 x, Int128 y, Int128 & res) { - static constexpr __int128 min_int128 = minInt128(); - static constexpr __int128 max_int128 = maxInt128(); res = subIgnoreOverflow(x, y); - return (y < 0 && x > max_int128 + y) || (y > 0 && x < min_int128 + y); + return (y < 0 && x > std::numeric_limits::max() + y) || + (y > 0 && x < std::numeric_limits::min() + y); + } + + template <> + inline bool subOverflow(UInt128 x, UInt128 y, UInt128 & res) + { + res = subIgnoreOverflow(x, y); + return x < y; } template <> diff --git a/base/common/wide_integer_impl.h b/base/common/wide_integer_impl.h index 1e1e3b2d359..fb1ab8141b6 100644 --- a/base/common/wide_integer_impl.h +++ b/base/common/wide_integer_impl.h @@ -433,7 +433,7 @@ private: for (unsigned i = 1; i < item_count; ++i) { - if (underflows[i-1]) + if (underflows[i - 1]) { base_type & res_item = res.items[little(i)]; if (res_item == 0) @@ -466,7 +466,7 @@ private: for (unsigned i = 1; i < item_count; ++i) { - if (overflows[i-1]) + if (overflows[i - 1]) { base_type & res_item = res.items[little(i)]; ++res_item; diff --git a/src/Common/FieldVisitorsAccurateComparison.h b/src/Common/FieldVisitorsAccurateComparison.h index 99f0e53d0ed..b3ff4331cae 100644 --- a/src/Common/FieldVisitorsAccurateComparison.h +++ b/src/Common/FieldVisitorsAccurateComparison.h @@ -40,10 +40,10 @@ public: return l == r; if constexpr (isDecimalField() && std::is_arithmetic_v) - return accurate::equalsOp(l.getValue(), r); + return l == DecimalField(Decimal256(r), 0); if constexpr (std::is_arithmetic_v && isDecimalField()) - return accurate::equalsOp(l, r.getValue()); + return DecimalField(Decimal256(l), 0) == r; if constexpr (std::is_same_v && std::is_arithmetic_v) { @@ -94,10 +94,10 @@ public: return l < r; if constexpr (isDecimalField() && std::is_arithmetic_v) - return accurate::lessOp(l.getValue(), r); + return l < DecimalField(Decimal256(r), 0); if constexpr (std::is_arithmetic_v && isDecimalField()) - return accurate::lessOp(l, r.getValue()); + return DecimalField(Decimal256(l), 0) < r; if constexpr (std::is_same_v && std::is_arithmetic_v) { diff --git a/src/Common/HashTable/Hash.h b/src/Common/HashTable/Hash.h index 81c778292bb..748b0775a0e 100644 --- a/src/Common/HashTable/Hash.h +++ b/src/Common/HashTable/Hash.h @@ -180,6 +180,28 @@ inline size_t DefaultHash64(std::enable_if_t<(sizeof(T) <= sizeof(UInt64)), T> k } +template +inline size_t DefaultHash64(std::enable_if_t<(sizeof(T) > sizeof(UInt64)), T> key) +{ + if constexpr (is_big_int_v && sizeof(T) == 16) + { + /// TODO This is classical antipattern. + return intHash64( + static_cast(key) ^ + static_cast(key >> 64)); + } + else if constexpr (is_big_int_v && sizeof(T) == 32) + { + return intHash64( + static_cast(key) ^ + static_cast(key >> 64) ^ + static_cast(key >> 128) ^ + static_cast(key >> 256)); + } + __builtin_unreachable(); +} + + template struct DefaultHash; @@ -197,7 +219,7 @@ struct DefaultHash>> { size_t operator() (T key) const { - return DefaultHash64(key); + return DefaultHash64(key.value); } }; @@ -322,28 +344,6 @@ template <> struct DefaultHash : public UInt256Hash {}; -template -inline size_t DefaultHash64(std::enable_if_t<(sizeof(T) > sizeof(UInt64)), T> key) -{ - if constexpr (std::is_same_v) - { - return intHash64(static_cast(key) ^ static_cast(key >> 64)); - } - if constexpr (std::is_same_v) - { - return intHash64(key.low ^ key.high); /// TODO This is classical antipattern. - } - else if constexpr (is_big_int_v && sizeof(T) == 32) - { - return intHash64(static_cast(key) ^ - static_cast(key >> 64) ^ - static_cast(key >> 128) ^ - static_cast(key >> 256)); - } - __builtin_unreachable(); -} - - /// It is reasonable to use for UInt8, UInt16 with sufficient hash table size. struct TrivialHash { diff --git a/src/Compression/tests/gtest_compressionCodec.cpp b/src/Compression/tests/gtest_compressionCodec.cpp index ae7930403ab..0acd15e48c3 100644 --- a/src/Compression/tests/gtest_compressionCodec.cpp +++ b/src/Compression/tests/gtest_compressionCodec.cpp @@ -1093,7 +1093,7 @@ INSTANTIATE_TEST_SUITE_P(RandomishFloat, ); // Double delta overflow case, deltas are out of bounds for target type -INSTANTIATE_TEST_SUITE_P(OverfloInt, +INSTANTIATE_TEST_SUITE_P(OverflowInt, CodecTest, ::testing::Combine( ::testing::Values( diff --git a/src/Core/AccurateComparison.h b/src/Core/AccurateComparison.h index c001b7f76a3..935a1bea3bc 100644 --- a/src/Core/AccurateComparison.h +++ b/src/Core/AccurateComparison.h @@ -2,8 +2,9 @@ #include #include -#include "Defines.h" -#include "Types.h" +#include +#include +#include #include #include @@ -16,403 +17,124 @@ namespace accurate using namespace DB; -/** Cases: - 1) Safe conversion (in case of default C++ operators) - a) int vs any int - b) uint vs any uint - c) float vs any float - 2) int vs uint - a) sizeof(int) <= sizeof(uint). Accurate comparison with MAX_INT tresholds - b) sizeof(int) > sizeof(uint). Casting to int - 3) integral_type vs floating_type - a) sizeof(integral_type) <= 4. Comparison via casting arguments to Float64 - b) sizeof(integral_type) == 8. Accurate comparison. Consider 3 sets of intervals: - 1) interval between adjacent floats less or equal 1 - 2) interval between adjacent floats greater then 2 - 3) float is outside [MIN_INT64; MAX_INT64] -*/ - -// Case 1. Is pair of floats or pair of ints or pair of uints -template -constexpr bool is_safe_conversion = (std::is_floating_point_v && std::is_floating_point_v) - || (is_integer_v && is_integer_v && !(is_signed_v ^ is_signed_v)); -template -using bool_if_safe_conversion = std::enable_if_t, bool>; -template -using bool_if_not_safe_conversion = std::enable_if_t, bool>; - - -/// Case 2. Are params IntXX and UIntYY ? -template -constexpr bool is_any_int_vs_uint - = is_integer_v && is_integer_v && is_signed_v && is_unsigned_v; - -// Case 2a. Are params IntXX and UIntYY and sizeof(IntXX) <= sizeof(UIntYY) (in such case will use accurate compare) -template -constexpr bool is_le_int_vs_uint = is_any_int_vs_uint && (sizeof(TInt) <= sizeof(TUInt)); - -static_assert(is_le_int_vs_uint); -static_assert(is_le_int_vs_uint); - -template -using bool_if_le_int_vs_uint_t = std::enable_if_t, bool>; - -template -inline bool_if_le_int_vs_uint_t greaterOpTmpl(TInt a, TUInt b) -{ - return static_cast(a) > b && a >= 0 && b <= static_cast(std::numeric_limits::max()); -} - -template -inline bool_if_le_int_vs_uint_t greaterOpTmpl(TUInt a, TInt b) -{ - return a > static_cast(b) || b < 0 || a > static_cast(std::numeric_limits::max()); -} - -template -inline bool_if_le_int_vs_uint_t equalsOpTmpl(TInt a, TUInt b) -{ - return static_cast(a) == b && a >= 0 && b <= static_cast(std::numeric_limits::max()); -} - -template -inline bool_if_le_int_vs_uint_t equalsOpTmpl(TUInt a, TInt b) -{ - return a == static_cast(b) && b >= 0 && a <= static_cast(std::numeric_limits::max()); -} - - -// Case 2b. Are params IntXX and UIntYY and sizeof(IntXX) > sizeof(UIntYY) (in such case will cast UIntYY to IntXX and compare) -template -constexpr bool is_gt_int_vs_uint = is_any_int_vs_uint && (sizeof(TInt) > sizeof(TUInt)); - -template -using bool_if_gt_int_vs_uint = std::enable_if_t, bool>; - -template -inline bool_if_gt_int_vs_uint greaterOpTmpl(TInt a, TUInt b) -{ - return static_cast(a) > static_cast(b); -} - -template -inline bool_if_gt_int_vs_uint greaterOpTmpl(TUInt a, TInt b) -{ - return static_cast(a) > static_cast(b); -} - -template -inline bool_if_gt_int_vs_uint equalsOpTmpl(TInt a, TUInt b) -{ - return static_cast(a) == static_cast(b); -} - -template -inline bool_if_gt_int_vs_uint equalsOpTmpl(TUInt a, TInt b) -{ - return static_cast(a) == static_cast(b); -} - - -// Case 3a. Comparison via conversion to double. -template -using bool_if_double_can_be_used - = std::enable_if_t && (sizeof(TAInt) <= 4) && std::is_floating_point_v, bool>; - -template -inline bool_if_double_can_be_used greaterOpTmpl(TAInt a, TAFloat b) -{ - return static_cast(a) > static_cast(b); -} - -template -inline bool_if_double_can_be_used greaterOpTmpl(TAFloat a, TAInt b) -{ - return static_cast(a) > static_cast(b); -} - -template -inline bool_if_double_can_be_used equalsOpTmpl(TAInt a, TAFloat b) -{ - return static_cast(a) == static_cast(b); -} - -template -inline bool_if_double_can_be_used equalsOpTmpl(TAFloat a, TAInt b) -{ - return static_cast(a) == static_cast(b); -} - -// Big integers vs Float (not equal in any case for now, until big floats are introduced?) -template -constexpr bool if_big_int_vs_float = (is_big_int_v && std::is_floating_point_v); - -template -using bool_if_big_int_vs_float = std::enable_if_t, bool>; - -template -inline bool_if_big_int_vs_float greaterOpTmpl(TAFloat, TABigInt) -{ - return false; -} - -template -inline bool_if_big_int_vs_float greaterOpTmpl(TABigInt, TAFloat) -{ - return false; -} - -template -inline bool_if_big_int_vs_float equalsOpTmpl(TAFloat, TABigInt) -{ - return false; -} - -template -inline bool_if_big_int_vs_float equalsOpTmpl(TABigInt, TAFloat) -{ - return false; -} - -/* Final implementations */ - template -inline bool greaterOp(A a, B b) +bool lessOp(A a, B b) { - return greaterOpTmpl(a, b); -} + /// float vs float + if constexpr (std::is_floating_point_v && std::is_floating_point_v) + return a < b; -// Case 3b. 64-bit integers vs floats comparison. -// See hint at https://github.com/JuliaLang/julia/issues/257 (but it doesn't work properly for -2**63) + /// anything vs NaN + if constexpr (std::is_floating_point_v || std::is_floating_point_v) + if (isNaN(a) || isNaN(b)) + return false; -constexpr Int64 MAX_INT64_WITH_EXACT_FLOAT64_REPR = 9007199254740992LL; // 2^53 + /// int vs int + if constexpr (is_integer_v && is_integer_v) + { + /// same signedness + if constexpr (is_signed_v == is_signed_v) + return a < b; -template <> -inline bool greaterOp(Float64 f, Int64 i) -{ - if (-MAX_INT64_WITH_EXACT_FLOAT64_REPR <= i && i <= MAX_INT64_WITH_EXACT_FLOAT64_REPR) - return f > static_cast(i); + /// different signedness - return (f >= static_cast(std::numeric_limits::max())) // rhs is 2**63 (not 2^63 - 1) - || (f > static_cast(std::numeric_limits::min()) && static_cast(f) > i); -} + if constexpr (is_signed_v && !is_signed_v) + return a < 0 || static_cast(a) < b; -template <> -inline bool greaterOp(Int64 i, Float64 f) -{ - if (-MAX_INT64_WITH_EXACT_FLOAT64_REPR <= i && i <= MAX_INT64_WITH_EXACT_FLOAT64_REPR) - return f < static_cast(i); + if constexpr (!is_signed_v && is_signed_v) + return b >= 0 && a < static_cast(b); + } - return (f < static_cast(std::numeric_limits::min())) - || (f < static_cast(std::numeric_limits::max()) && i > static_cast(f)); -} + /// int vs float + if constexpr (is_integer_v && std::is_floating_point_v) + { + if constexpr (sizeof(A) <= 4) + return static_cast(a) < static_cast(b); -template <> -inline bool greaterOp(Float64 f, UInt64 u) -{ - if (u <= static_cast(MAX_INT64_WITH_EXACT_FLOAT64_REPR)) - return f > static_cast(u); + return DecomposedFloat(b).greater(a); + } - return (f >= static_cast(std::numeric_limits::max())) - || (f >= 0 && static_cast(f) > u); -} + if constexpr (std::is_floating_point_v && is_integer_v) + { + if constexpr (sizeof(B) <= 4) + return static_cast(a) < static_cast(b); -template <> -inline bool greaterOp(UInt64 u, Float64 f) -{ - if (u <= static_cast(MAX_INT64_WITH_EXACT_FLOAT64_REPR)) - return static_cast(u) > f; - - return (f < 0) - || (f < static_cast(std::numeric_limits::max()) && u > static_cast(f)); -} - -// Case 3b for float32 -template <> inline bool greaterOp(Float32 f, Int64 i) { return greaterOp(static_cast(f), i); } -template <> inline bool greaterOp(Float32 f, Int128 i) { return greaterOp(static_cast(f), i); } -template <> inline bool greaterOp(Float32 f, Int256 i) { return greaterOp(static_cast(f), i); } -template <> inline bool greaterOp(Float32 f, UInt64 i) { return greaterOp(static_cast(f), i); } -template <> inline bool greaterOp(Float32 f, UInt128 i) { return greaterOp(static_cast(f), i); } -template <> inline bool greaterOp(Float32 f, UInt256 i) { return greaterOp(static_cast(f), i); } - -template <> inline bool greaterOp(Int64 i, Float32 f) { return greaterOp(i, static_cast(f)); } -template <> inline bool greaterOp(Int128 i, Float32 f) { return greaterOp(i, static_cast(f)); } -template <> inline bool greaterOp(Int256 i, Float32 f) { return greaterOp(i, static_cast(f)); } -template <> inline bool greaterOp(UInt64 i, Float32 f) { return greaterOp(i, static_cast(f)); } -template <> inline bool greaterOp(UInt128 i, Float32 f) { return greaterOp(i, static_cast(f)); } -template <> inline bool greaterOp(UInt256 i, Float32 f) { return greaterOp(i, static_cast(f)); } - - -template -inline bool_if_not_safe_conversion equalsOp(A a, B b) -{ - return equalsOpTmpl(a, b); + return DecomposedFloat(a).less(b); + } } template -inline bool_if_safe_conversion equalsOp(A a, B b) +bool greaterOp(A a, B b) { - using LargestType = std::conditional_t<(sizeof(A) >= sizeof(B)), A, B>; - - return static_cast(a) == static_cast(b); + return lessOp(b, a); } -template <> -inline bool equalsOp(DB::Float64 f, DB::UInt64 u) -{ - /// Maximum exactly representable integer. - return u <= (1ULL << std::numeric_limits::digits) - && f == static_cast(u); -} - -template <> -inline bool equalsOp(DB::UInt64 u, DB::Float64 f) -{ - return equalsOp(f, u); -} - -template <> -inline bool equalsOp(DB::Float64 f, DB::Int64 u) -{ - return u <= (1LL << std::numeric_limits::digits) - && u >= -(1LL << std::numeric_limits::digits) - && f == static_cast(u); -} - -template <> -inline bool equalsOp(DB::Int64 u, DB::Float64 f) -{ - return equalsOp(f, u); -} - -template <> -inline bool equalsOp(DB::Float32 f, DB::UInt64 u) -{ - return u <= (1ULL << std::numeric_limits::digits) - && f == static_cast(u); -} - -template <> -inline bool equalsOp(DB::UInt64 u, DB::Float32 f) -{ - return equalsOp(f, u); -} - -template <> -inline bool equalsOp(DB::Float32 f, DB::Int64 u) -{ - return u <= (1LL << std::numeric_limits::digits) - && u >= -(1LL << std::numeric_limits::digits) - && f == static_cast(u); -} - -template <> -inline bool equalsOp(DB::Int64 u, DB::Float32 f) -{ - return equalsOp(f, u); -} - -template <> -inline bool equalsOp(DB::UInt128 u, DB::Float64 f) -{ - /// TODO: This is wrong. - return u.items[0] == 0 && equalsOp(static_cast(u.items[1]), f); -} - -template <> -inline bool equalsOp(UInt128 u, Float32 f) -{ - return equalsOp(u, static_cast(f)); -} - -template <> -inline bool equalsOp(Float64 f, UInt128 u) -{ - return equalsOp(u, f); -} - -template <> -inline bool equalsOp(Float32 f, UInt128 u) -{ - return equalsOp(static_cast(f), u); -} - -inline bool NO_SANITIZE_UNDEFINED greaterOp(Int128 i, Float64 f) -{ - static constexpr Int128 min_int128 = minInt128(); - static constexpr Int128 max_int128 = maxInt128(); - - if (-MAX_INT64_WITH_EXACT_FLOAT64_REPR <= i && i <= MAX_INT64_WITH_EXACT_FLOAT64_REPR) - return static_cast(i) > f; - - return (f < static_cast(min_int128)) - || (f < static_cast(max_int128) && i > static_cast(f)); -} - -inline bool NO_SANITIZE_UNDEFINED greaterOp(Float64 f, Int128 i) -{ - static constexpr Int128 min_int128 = minInt128(); - static constexpr Int128 max_int128 = maxInt128(); - - if (-MAX_INT64_WITH_EXACT_FLOAT64_REPR <= i && i <= MAX_INT64_WITH_EXACT_FLOAT64_REPR) - return f > static_cast(i); - - return (f >= static_cast(max_int128)) - || (f > static_cast(min_int128) && static_cast(f) > i); -} - -inline bool greaterOp(Int128 i, Float32 f) { return greaterOp(i, static_cast(f)); } -inline bool greaterOp(Float32 f, Int128 i) { return greaterOp(static_cast(f), i); } - -inline bool NO_SANITIZE_UNDEFINED equalsOp(Int128 i, Float64 f) { return i == static_cast(f) && static_cast(i) == f; } -inline bool NO_SANITIZE_UNDEFINED equalsOp(Int128 i, Float32 f) { return i == static_cast(f) && static_cast(i) == f; } -inline bool equalsOp(Float64 f, Int128 i) { return equalsOp(i, f); } -inline bool equalsOp(Float32 f, Int128 i) { return equalsOp(i, f); } - template -inline bool notEqualsOp(A a, B b) +bool greaterOrEqualsOp(A a, B b) +{ + return !lessOp(a, b); +} + +template +bool lessOrEqualsOp(A a, B b) +{ + return !lessOp(b, a); +} + +template +bool equalsOp(A a, B b) +{ + /// float vs float + if constexpr (std::is_floating_point_v && std::is_floating_point_v) + return a == b; + + /// anything vs NaN + if constexpr (std::is_floating_point_v || std::is_floating_point_v) + if (isNaN(a) || isNaN(b)) + return false; + + /// int vs int + if constexpr (is_integer_v && is_integer_v) + { + /// same signedness + if constexpr (is_signed_v == is_signed_v) + return a == b; + + /// different signedness + + if constexpr (is_signed_v && !is_signed_v) + return a >= 0 && static_cast(a) == b; + + if constexpr (!is_signed_v && is_signed_v) + return b >= 0 && a == static_cast(b); + } + + /// int vs float + if constexpr (is_integer_v && std::is_floating_point_v) + { + if constexpr (sizeof(A) <= 4) + return static_cast(a) == static_cast(b); + + return DecomposedFloat(b).equals(a); + } + + if constexpr (std::is_floating_point_v && is_integer_v) + { + if constexpr (sizeof(B) <= 4) + return static_cast(a) == static_cast(b); + + return DecomposedFloat(a).equals(b); + } +} + +template +bool notEqualsOp(A a, B b) { return !equalsOp(a, b); } -template -inline bool lessOp(A a, B b) -{ - return greaterOp(b, a); -} - - -template -inline bool_if_not_safe_conversion lessOrEqualsOp(A a, B b) -{ - if (isNaN(a) || isNaN(b)) - return false; - return !greaterOp(a, b); -} - -template -inline bool_if_safe_conversion lessOrEqualsOp(A a, B b) -{ - return a <= b; -} - - -template -inline bool_if_not_safe_conversion greaterOrEqualsOp(A a, B b) -{ - if (isNaN(a) || isNaN(b)) - return false; - return !greaterOp(b, a); -} - -template -inline bool_if_safe_conversion greaterOrEqualsOp(A a, B b) -{ - return a >= b; -} - /// Converts numeric to an equal numeric of other type. template inline bool NO_SANITIZE_UNDEFINED convertNumeric(From value, To & result) diff --git a/src/Core/Field.h b/src/Core/Field.h index d30ec344700..7405b57b971 100644 --- a/src/Core/Field.h +++ b/src/Core/Field.h @@ -845,6 +845,8 @@ decltype(auto) castToNearestFieldType(T && x) using U = NearestFieldType>; if constexpr (std::is_same_v, U>) return std::forward(x); + else if constexpr (std::is_same_v, UUID>) + return U(x.toUnderType()); else return U(x); } diff --git a/src/Core/Types.h b/src/Core/Types.h index 8d77a7d70b7..7dd11f55166 100644 --- a/src/Core/Types.h +++ b/src/Core/Types.h @@ -180,6 +180,8 @@ struct Decimal template inline bool operator< (const Decimal & x, const Decimal & y) { return x.value < y.value; } template inline bool operator> (const Decimal & x, const Decimal & y) { return x.value > y.value; } +template inline bool operator<= (const Decimal & x, const Decimal & y) { return x.value <= y.value; } +template inline bool operator>= (const Decimal & x, const Decimal & y) { return x.value >= y.value; } template inline bool operator== (const Decimal & x, const Decimal & y) { return x.value == y.value; } template inline bool operator!= (const Decimal & x, const Decimal & y) { return x.value != y.value; } diff --git a/src/DataStreams/MongoDBBlockInputStream.cpp b/src/DataStreams/MongoDBBlockInputStream.cpp index e4ddcd09ede..ef2c66ed507 100644 --- a/src/DataStreams/MongoDBBlockInputStream.cpp +++ b/src/DataStreams/MongoDBBlockInputStream.cpp @@ -290,7 +290,7 @@ namespace if (value.type() == Poco::MongoDB::ElementTraits::TypeId) { String string = static_cast &>(value).value(); - assert_cast(column).getData().push_back(parse(string)); + assert_cast(column).getData().push_back(parse(string).toUnderType()); } else throw Exception{"Type mismatch, expected String (UUID), got type id = " + toString(value.type()) + " for column " diff --git a/src/DataTypes/DataTypeDecimalBase.h b/src/DataTypes/DataTypeDecimalBase.h index 9e44310a0ff..2976a50d7b4 100644 --- a/src/DataTypes/DataTypeDecimalBase.h +++ b/src/DataTypes/DataTypeDecimalBase.h @@ -113,15 +113,15 @@ public: T maxWholeValue() const { return getScaleMultiplier(precision - scale) - T(1); } - template + template bool canStoreWhole(U x) const { - static_assert(std::is_signed_v); + static_assert(is_signed_v); T max = maxWholeValue(); - if constexpr (std::is_signed_v) - return -max <= x && x <= max; + if constexpr (is_signed_v) + return -max.value <= x && x <= max.value; else - return x <= static_cast>(max.value); + return x <= static_cast>(max.value); } /// @returns multiplier for U to become T with correct scale diff --git a/src/DataTypes/DataTypesDecimal.h b/src/DataTypes/DataTypesDecimal.h index 5aeac78b2ef..622323e530b 100644 --- a/src/DataTypes/DataTypesDecimal.h +++ b/src/DataTypes/DataTypesDecimal.h @@ -235,9 +235,9 @@ convertToDecimalImpl(const typename FromDataType::FieldType & value, UInt32 scal if constexpr (is_big_int_v) return ReturnType(convertDecimalsImpl, ToDataType, ReturnType>(static_cast(value), 0, scale, result)); else if constexpr (std::is_same_v) - return ReturnType(convertDecimalsImpl, ToDataType, ReturnType>(value, 0, scale, result)); + return ReturnType(convertDecimalsImpl, ToDataType, ReturnType>(static_cast(value), 0, scale, result)); else - return ReturnType(convertDecimalsImpl, ToDataType, ReturnType>(value, 0, scale, result)); + return ReturnType(convertDecimalsImpl, ToDataType, ReturnType>(static_cast(value), 0, scale, result)); } } diff --git a/src/DataTypes/Serializations/SerializationUUID.cpp b/src/DataTypes/Serializations/SerializationUUID.cpp index 1a0640a5e69..0e89f2f7c30 100644 --- a/src/DataTypes/Serializations/SerializationUUID.cpp +++ b/src/DataTypes/Serializations/SerializationUUID.cpp @@ -18,7 +18,7 @@ void SerializationUUID::deserializeText(IColumn & column, ReadBuffer & istr, con { UUID x; readText(x, istr); - assert_cast(column).getData().push_back(x); + assert_cast(column).getData().push_back(x.toUnderType()); } void SerializationUUID::deserializeTextEscaped(IColumn & column, ReadBuffer & istr, const FormatSettings & settings) const @@ -44,7 +44,7 @@ void SerializationUUID::deserializeTextQuoted(IColumn & column, ReadBuffer & ist assertChar('\'', istr); readText(x, istr); assertChar('\'', istr); - assert_cast(column).getData().push_back(x); /// It's important to do this at the end - for exception safety. + assert_cast(column).getData().push_back(x.toUnderType()); /// It's important to do this at the end - for exception safety. } void SerializationUUID::serializeTextJSON(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const @@ -60,7 +60,7 @@ void SerializationUUID::deserializeTextJSON(IColumn & column, ReadBuffer & istr, assertChar('"', istr); readText(x, istr); assertChar('"', istr); - assert_cast(column).getData().push_back(x); + assert_cast(column).getData().push_back(x.toUnderType()); } void SerializationUUID::serializeTextCSV(const IColumn & column, size_t row_num, WriteBuffer & ostr, const FormatSettings & settings) const @@ -74,7 +74,7 @@ void SerializationUUID::deserializeTextCSV(IColumn & column, ReadBuffer & istr, { UUID value; readCSV(value, istr); - assert_cast(column).getData().push_back(value); + assert_cast(column).getData().push_back(value.toUnderType()); } } diff --git a/src/Functions/FunctionBinaryArithmetic.h b/src/Functions/FunctionBinaryArithmetic.h index ef9d05b4b5e..37531ecb787 100644 --- a/src/Functions/FunctionBinaryArithmetic.h +++ b/src/Functions/FunctionBinaryArithmetic.h @@ -782,7 +782,7 @@ class FunctionBinaryArithmetic : public IFunction return function->execute(new_arguments, result_type, input_rows_count); } - template + template static auto helperGetOrConvert(const CC & col_const, const C & col) { using ResultType = typename ResultDataType::FieldType; @@ -790,12 +790,14 @@ class FunctionBinaryArithmetic : public IFunction if constexpr (IsFloatingPoint && IsDecimalNumber) return DecimalUtils::convertTo(col_const->template getValue(), col.getScale()); + else if constexpr (IsDecimalNumber) + return col_const->template getValue().value; else return col_const->template getValue(); } - template + template void helperInvokeEither(const L& left, const R& right, VR& vec_res, SA scale_a, SB scale_b) const { if (check_decimal_overflow) diff --git a/src/Functions/FunctionsConversion.h b/src/Functions/FunctionsConversion.h index 1cd308c774d..2915816ffd1 100644 --- a/src/Functions/FunctionsConversion.h +++ b/src/Functions/FunctionsConversion.h @@ -784,7 +784,7 @@ inline void parseImpl(DataTypeUUID::FieldType & x, ReadBuffer & rb { UUID tmp; readUUIDText(tmp, rb); - x = tmp; + x = tmp.toUnderType(); } @@ -824,7 +824,7 @@ inline bool tryParseImpl(DataTypeUUID::FieldType & x, ReadBuffer & if (!tryReadUUIDText(tmp, rb)) return false; - x = tmp; + x = tmp.toUnderType(); return true; } diff --git a/src/Functions/GatherUtils/Algorithms.h b/src/Functions/GatherUtils/Algorithms.h index 1a962089d0c..25a755079fb 100644 --- a/src/Functions/GatherUtils/Algorithms.h +++ b/src/Functions/GatherUtils/Algorithms.h @@ -45,11 +45,7 @@ void writeSlice(const NumericArraySlice & slice, NumericArraySink & sink) if constexpr (OverBigInt || OverBigInt) { - if constexpr (std::is_same_v) - { - throw Exception("No conversion between UInt128 and " + demangle(typeid(T).name()), ErrorCodes::NOT_IMPLEMENTED); - } - else if constexpr (IsDecimalNumber) + if constexpr (IsDecimalNumber) dst = static_cast(src.value); else dst = static_cast(src); diff --git a/src/Functions/GatherUtils/ArraySinkVisitor.h b/src/Functions/GatherUtils/ArraySinkVisitor.h index b146780924f..8784191fb0d 100644 --- a/src/Functions/GatherUtils/ArraySinkVisitor.h +++ b/src/Functions/GatherUtils/ArraySinkVisitor.h @@ -14,7 +14,7 @@ struct GenericArraySink; template struct NullableArraySink; -using NumericArraySinks = typename TypeListMap::Type; +using NumericArraySinks = typename TypeListMap::Type; using BasicArraySinks = typename AppendToTypeList::Type; using NullableArraySinks = typename TypeListMap::Type; using TypeListArraySinks = typename TypeListConcat::Type; diff --git a/src/Functions/GatherUtils/ArraySourceVisitor.h b/src/Functions/GatherUtils/ArraySourceVisitor.h index 260e9a87161..9e345d25cd8 100644 --- a/src/Functions/GatherUtils/ArraySourceVisitor.h +++ b/src/Functions/GatherUtils/ArraySourceVisitor.h @@ -17,7 +17,7 @@ struct NullableArraySource; template struct ConstSource; -using NumericArraySources = typename TypeListMap::Type; +using NumericArraySources = typename TypeListMap::Type; using BasicArraySources = typename AppendToTypeList::Type; class ArraySourceVisitor : public ApplyTypeListForClass::Type diff --git a/src/Functions/GatherUtils/ValueSourceVisitor.h b/src/Functions/GatherUtils/ValueSourceVisitor.h index 538ee156e5d..2646d6b5ca3 100644 --- a/src/Functions/GatherUtils/ValueSourceVisitor.h +++ b/src/Functions/GatherUtils/ValueSourceVisitor.h @@ -17,7 +17,7 @@ struct NullableValueSource; template struct ConstSource; -using NumericValueSources = typename TypeListMap::Type; +using NumericValueSources = typename TypeListMap::Type; using BasicValueSources = typename AppendToTypeList::Type; using NullableValueSources = typename TypeListMap::Type; using BasicAndNullableValueSources = typename TypeListConcat::Type; diff --git a/src/Functions/GatherUtils/createArraySink.cpp b/src/Functions/GatherUtils/createArraySink.cpp index 00b33cf9821..c0ffe50cbc8 100644 --- a/src/Functions/GatherUtils/createArraySink.cpp +++ b/src/Functions/GatherUtils/createArraySink.cpp @@ -55,7 +55,7 @@ struct ArraySinkCreator<> std::unique_ptr createArraySink(ColumnArray & col, size_t column_size) { - using Creator = ApplyTypeListForClass::Type; + using Creator = ApplyTypeListForClass::Type; return Creator::create(col.getData(), col.getOffsets(), column_size); } } diff --git a/src/Functions/GatherUtils/createArraySource.cpp b/src/Functions/GatherUtils/createArraySource.cpp index 0744e2f2ea3..3af06f8a8ac 100644 --- a/src/Functions/GatherUtils/createArraySource.cpp +++ b/src/Functions/GatherUtils/createArraySource.cpp @@ -58,7 +58,7 @@ struct ArraySourceCreator<> std::unique_ptr createArraySource(const ColumnArray & col, bool is_const, size_t total_rows) { - using Creator = typename ApplyTypeListForClass::Type; + using Creator = typename ApplyTypeListForClass::Type; if (const auto * column_nullable = typeid_cast(&col.getData())) { auto column = ColumnArray::create(column_nullable->getNestedColumnPtr(), col.getOffsetsPtr()); diff --git a/src/Functions/GatherUtils/createValueSource.cpp b/src/Functions/GatherUtils/createValueSource.cpp index 20110066214..9680c71bfba 100644 --- a/src/Functions/GatherUtils/createValueSource.cpp +++ b/src/Functions/GatherUtils/createValueSource.cpp @@ -58,7 +58,7 @@ struct ValueSourceCreator<> std::unique_ptr createValueSource(const IColumn & col, bool is_const, size_t total_rows) { - using Creator = typename ApplyTypeListForClass::Type; + using Creator = typename ApplyTypeListForClass::Type; if (const auto * column_nullable = typeid_cast(&col)) { return Creator::create(column_nullable->getNestedColumn(), &column_nullable->getNullMapData(), is_const, total_rows); diff --git a/src/Functions/array/arrayAggregation.cpp b/src/Functions/array/arrayAggregation.cpp index e0e246b8af4..30b67e2271d 100644 --- a/src/Functions/array/arrayAggregation.cpp +++ b/src/Functions/array/arrayAggregation.cpp @@ -167,7 +167,7 @@ struct ArrayAggregateImpl { size_t array_size = offsets[i] - pos; /// Just multiply the value by array size. - res[i] = x * array_size; + res[i] = x * Result(array_size); } else if constexpr (aggregate_operation == AggregateOperation::min || aggregate_operation == AggregateOperation::max) @@ -206,12 +206,15 @@ struct ArrayAggregateImpl size_t pos = 0; for (size_t i = 0; i < offsets.size(); ++i) { - AggregationType s = 0; + AggregationType s{}; /// Array is empty if (offsets[i] == pos) { - res[i] = s; + if constexpr (IsDecimalNumber) + res[i] = s.value; + else + res[i] = s; continue; } @@ -250,7 +253,7 @@ struct ArrayAggregateImpl { if constexpr (IsDecimalNumber) { - s = s / count; + s = s / AggregationType(count); res[i] = DecimalUtils::convertTo(s, data.getScale()); } else diff --git a/src/Functions/array/arrayCumSumNonNegative.cpp b/src/Functions/array/arrayCumSumNonNegative.cpp index 2c7362a1605..288422c1c9c 100644 --- a/src/Functions/array/arrayCumSumNonNegative.cpp +++ b/src/Functions/array/arrayCumSumNonNegative.cpp @@ -60,8 +60,8 @@ struct ArrayCumSumNonNegativeImpl for (; pos < offset; ++pos) { accumulated += src_values[pos]; - if (accumulated < 0) - accumulated = 0; + if (accumulated < Dst{}) + accumulated = {}; res_values[pos] = accumulated; } } diff --git a/src/Functions/array/arrayDifference.cpp b/src/Functions/array/arrayDifference.cpp index b4b30079a4e..ced865a4156 100644 --- a/src/Functions/array/arrayDifference.cpp +++ b/src/Functions/array/arrayDifference.cpp @@ -57,7 +57,7 @@ struct ArrayDifferenceImpl { if (pos == begin) { - dst[pos] = 0; + dst[pos] = {}; prev = src[pos]; } else diff --git a/src/Functions/array/arrayIntersect.cpp b/src/Functions/array/arrayIntersect.cpp index 7275a1395c0..05bb4351c3e 100644 --- a/src/Functions/array/arrayIntersect.cpp +++ b/src/Functions/array/arrayIntersect.cpp @@ -518,7 +518,9 @@ ColumnPtr FunctionArrayIntersect::execute(const UnpackedArrays & arrays, Mutable typename Map::mapped_type * value = nullptr; if constexpr (is_numeric_column) + { value = &map[columns[arg_num]->getElement(i)]; + } else if constexpr (std::is_same::value || std::is_same::value) value = &map[columns[arg_num]->getDataAt(i)]; else diff --git a/src/Functions/generateUUIDv4.cpp b/src/Functions/generateUUIDv4.cpp index a1e50e3c54f..160afc7ea64 100644 --- a/src/Functions/generateUUIDv4.cpp +++ b/src/Functions/generateUUIDv4.cpp @@ -45,8 +45,8 @@ public: { /** https://tools.ietf.org/html/rfc4122#section-4.4 */ - uuid.low = (uuid.low & 0xffffffffffff0fffull) | 0x0000000000004000ull; - uuid.high = (uuid.high & 0x3fffffffffffffffull) | 0x8000000000000000ull; + uuid.items[0] = (uuid.items[0] & 0xffffffffffff0fffull) | 0x0000000000004000ull; + uuid.items[1] = (uuid.items[1] & 0x3fffffffffffffffull) | 0x8000000000000000ull; } return col_res; diff --git a/src/Functions/roundToExp2.cpp b/src/Functions/roundToExp2.cpp index 50a548e095e..2abe94b2b26 100644 --- a/src/Functions/roundToExp2.cpp +++ b/src/Functions/roundToExp2.cpp @@ -27,18 +27,6 @@ roundDownToPowerOfTwo(T x) return x <= 0 ? 0 : (T(1) << (63 - __builtin_clzll(x))); } -template -inline std::enable_if_t, T> -roundDownToPowerOfTwo(T x) -{ - if (x <= 0) - return 0; - - if (Int64 x64 = Int64(x >> 64)) - return Int128(roundDownToPowerOfTwo(x64)) << 64; - return roundDownToPowerOfTwo(Int64(x)); -} - template inline std::enable_if_t, T> roundDownToPowerOfTwo(T x) diff --git a/src/IO/MMappedFileCache.h b/src/IO/MMappedFileCache.h index cbd1977350b..adbb85a18cf 100644 --- a/src/IO/MMappedFileCache.h +++ b/src/IO/MMappedFileCache.h @@ -1,8 +1,9 @@ #pragma once +#include +#include #include #include -#include #include #include @@ -39,8 +40,7 @@ public: hash.update(offset); hash.update(length); - hash.get128(key.low, key.high); - + hash.get128(key); return key; } diff --git a/src/IO/ReadHelpers.h b/src/IO/ReadHelpers.h index a9e0e9527b9..885800ed02b 100644 --- a/src/IO/ReadHelpers.h +++ b/src/IO/ReadHelpers.h @@ -303,7 +303,7 @@ ReturnType readIntTextImpl(T & x, ReadBuffer & buf) case '8': [[fallthrough]]; case '9': { - if constexpr (check_overflow == ReadIntTextCheckOverflow::CHECK_OVERFLOW) + if constexpr (check_overflow == ReadIntTextCheckOverflow::CHECK_OVERFLOW && !is_big_int_v) { /// Perform relativelly slow overflow check only when /// number of decimal digits so far is close to the max for given type. diff --git a/src/IO/WriteHelpers.h b/src/IO/WriteHelpers.h index 9d89298f00b..9d73433b80b 100644 --- a/src/IO/WriteHelpers.h +++ b/src/IO/WriteHelpers.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -137,81 +138,6 @@ inline void writeBoolText(bool x, WriteBuffer & buf) } -struct DecomposedFloat64 -{ - DecomposedFloat64(double x) - { - memcpy(&x_uint, &x, sizeof(x)); - } - - uint64_t x_uint; - - bool sign() const - { - return x_uint >> 63; - } - - uint16_t exponent() const - { - return (x_uint >> 52) & 0x7FF; - } - - int16_t normalized_exponent() const - { - return int16_t(exponent()) - 1023; - } - - uint64_t mantissa() const - { - return x_uint & 0x5affffffffffffful; - } - - /// NOTE Probably floating point instructions can be better. - bool is_inside_int64() const - { - return x_uint == 0 - || (normalized_exponent() >= 0 && normalized_exponent() <= 52 - && ((mantissa() & ((1ULL << (52 - normalized_exponent())) - 1)) == 0)); - } -}; - -struct DecomposedFloat32 -{ - DecomposedFloat32(float x) - { - memcpy(&x_uint, &x, sizeof(x)); - } - - uint32_t x_uint; - - bool sign() const - { - return x_uint >> 31; - } - - uint16_t exponent() const - { - return (x_uint >> 23) & 0xFF; - } - - int16_t normalized_exponent() const - { - return int16_t(exponent()) - 127; - } - - uint32_t mantissa() const - { - return x_uint & 0x7fffff; - } - - bool is_inside_int32() const - { - return x_uint == 0 - || (normalized_exponent() >= 0 && normalized_exponent() <= 23 - && ((mantissa() & ((1ULL << (23 - normalized_exponent())) - 1)) == 0)); - } -}; - template inline size_t writeFloatTextFastPath(T x, char * buffer) { @@ -222,14 +148,14 @@ inline size_t writeFloatTextFastPath(T x, char * buffer) /// The library Ryu has low performance on integers. /// This workaround improves performance 6..10 times. - if (DecomposedFloat64(x).is_inside_int64()) + if (DecomposedFloat64(x).is_integer_in_representable_range()) result = itoa(Int64(x), buffer) - buffer; else result = jkj::dragonbox::to_chars_n(x, buffer) - buffer; } else { - if (DecomposedFloat32(x).is_inside_int32()) + if (DecomposedFloat32(x).is_integer_in_representable_range()) result = itoa(Int32(x), buffer) - buffer; else result = jkj::dragonbox::to_chars_n(x, buffer) - buffer; @@ -909,6 +835,7 @@ inline void writeBinary(const Decimal128 & x, WriteBuffer & buf) { writePODBinar inline void writeBinary(const Decimal256 & x, WriteBuffer & buf) { writePODBinary(x.value, buf); } inline void writeBinary(const LocalDate & x, WriteBuffer & buf) { writePODBinary(x, buf); } inline void writeBinary(const LocalDateTime & x, WriteBuffer & buf) { writePODBinary(x, buf); } +inline void writeBinary(const UUID & x, WriteBuffer & buf) { writePODBinary(x, buf); } /// Methods for outputting the value in text form for a tab-separated format. template diff --git a/src/Interpreters/ExpressionJIT.h b/src/Interpreters/ExpressionJIT.h index 793c19b4fe7..4dde450a02c 100644 --- a/src/Interpreters/ExpressionJIT.h +++ b/src/Interpreters/ExpressionJIT.h @@ -10,6 +10,7 @@ # include # include # include +# include namespace DB diff --git a/src/Interpreters/HashJoin.cpp b/src/Interpreters/HashJoin.cpp index c79cf874da5..abc89a486ec 100644 --- a/src/Interpreters/HashJoin.cpp +++ b/src/Interpreters/HashJoin.cpp @@ -384,7 +384,7 @@ template struct KeyGetterForTypeImpl struct KeyGetterForTypeImpl { - using Type = ColumnsHashing::HashMethodKeysFixed; + using Type = ColumnsHashing::HashMethodKeysFixed; }; template struct KeyGetterForTypeImpl { diff --git a/src/Interpreters/convertFieldToType.cpp b/src/Interpreters/convertFieldToType.cpp index 529caec9c80..d187f581e2e 100644 --- a/src/Interpreters/convertFieldToType.cpp +++ b/src/Interpreters/convertFieldToType.cpp @@ -80,7 +80,7 @@ static Field convertIntToDecimalType(const Field & from, const DataTypeDecimal(value); return DecimalField(scaled_value, type.getScale()); } diff --git a/src/Processors/Transforms/LimitByTransform.cpp b/src/Processors/Transforms/LimitByTransform.cpp index c4700e5605e..cb2804007bd 100644 --- a/src/Processors/Transforms/LimitByTransform.cpp +++ b/src/Processors/Transforms/LimitByTransform.cpp @@ -33,7 +33,7 @@ void LimitByTransform::transform(Chunk & chunk) for (UInt64 row = 0; row < num_rows; ++row) { - UInt128 key(0, 0); + UInt128 key{}; SipHash hash; for (auto position : key_positions) diff --git a/src/Processors/Transforms/LimitByTransform.h b/src/Processors/Transforms/LimitByTransform.h index 9773f637f40..8c2b46af69e 100644 --- a/src/Processors/Transforms/LimitByTransform.h +++ b/src/Processors/Transforms/LimitByTransform.h @@ -1,7 +1,7 @@ #pragma once #include #include -#include + namespace DB { diff --git a/src/Processors/Transforms/WindowTransform.cpp b/src/Processors/Transforms/WindowTransform.cpp index df92f911325..24bade4ce3a 100644 --- a/src/Processors/Transforms/WindowTransform.cpp +++ b/src/Processors/Transforms/WindowTransform.cpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -67,15 +68,9 @@ static int compareValuesWithOffset(const IColumn * _compared_column, bool is_overflow; if (offset_is_preceding) - { - is_overflow = __builtin_sub_overflow(reference_value, offset, - &reference_value); - } + is_overflow = common::subOverflow(reference_value, offset, reference_value); else - { - is_overflow = __builtin_add_overflow(reference_value, offset, - &reference_value); - } + is_overflow = common::addOverflow(reference_value, offset, reference_value); // fmt::print(stderr, // "compared [{}] = {}, old ref {}, shifted ref [{}] = {}, offset {} preceding {} overflow {} to negative {}\n", diff --git a/src/Processors/Transforms/WindowTransform.h b/src/Processors/Transforms/WindowTransform.h index 882bf429c0a..611b03ebf72 100644 --- a/src/Processors/Transforms/WindowTransform.h +++ b/src/Processors/Transforms/WindowTransform.h @@ -8,6 +8,7 @@ #include + namespace DB { diff --git a/src/Storages/MergeTree/MergeTreeDataPartUUID.cpp b/src/Storages/MergeTree/MergeTreeDataPartUUID.cpp index 17d19855798..3c3a6ecee7f 100644 --- a/src/Storages/MergeTree/MergeTreeDataPartUUID.cpp +++ b/src/Storages/MergeTree/MergeTreeDataPartUUID.cpp @@ -1,5 +1,7 @@ +#include #include + namespace DB { diff --git a/src/Storages/System/StorageSystemQuotas.cpp b/src/Storages/System/StorageSystemQuotas.cpp index 4bba082f66e..84c884e00a1 100644 --- a/src/Storages/System/StorageSystemQuotas.cpp +++ b/src/Storages/System/StorageSystemQuotas.cpp @@ -80,7 +80,7 @@ void StorageSystemQuotas::fillData(MutableColumns & res_columns, ContextPtr cont const RolesOrUsersSet & apply_to) { column_name.insertData(name.data(), name.length()); - column_id.push_back(id); + column_id.push_back(id.toUnderType()); column_storage.insertData(storage_name.data(), storage_name.length()); if (key_type != KeyType::NONE) diff --git a/src/Storages/System/StorageSystemRoles.cpp b/src/Storages/System/StorageSystemRoles.cpp index 65ae74887a7..4fd7eece020 100644 --- a/src/Storages/System/StorageSystemRoles.cpp +++ b/src/Storages/System/StorageSystemRoles.cpp @@ -39,7 +39,7 @@ void StorageSystemRoles::fillData(MutableColumns & res_columns, ContextPtr conte const String & storage_name) { column_name.insertData(name.data(), name.length()); - column_id.push_back(id); + column_id.push_back(id.toUnderType()); column_storage.insertData(storage_name.data(), storage_name.length()); }; diff --git a/src/Storages/System/StorageSystemRowPolicies.cpp b/src/Storages/System/StorageSystemRowPolicies.cpp index f9d6b14957e..7845dbe9792 100644 --- a/src/Storages/System/StorageSystemRowPolicies.cpp +++ b/src/Storages/System/StorageSystemRowPolicies.cpp @@ -93,7 +93,7 @@ void StorageSystemRowPolicies::fillData(MutableColumns & res_columns, ContextPtr column_short_name.insertData(name_parts.short_name.data(), name_parts.short_name.length()); column_database.insertData(name_parts.database.data(), name_parts.database.length()); column_table.insertData(name_parts.table_name.data(), name_parts.table_name.length()); - column_id.push_back(id); + column_id.push_back(id.toUnderType()); column_storage.insertData(storage_name.data(), storage_name.length()); for (auto condition_type : ext::range(MAX_CONDITION_TYPE)) diff --git a/src/Storages/System/StorageSystemSettingsProfiles.cpp b/src/Storages/System/StorageSystemSettingsProfiles.cpp index c726f54a324..b64f1cb4bae 100644 --- a/src/Storages/System/StorageSystemSettingsProfiles.cpp +++ b/src/Storages/System/StorageSystemSettingsProfiles.cpp @@ -54,7 +54,7 @@ void StorageSystemSettingsProfiles::fillData(MutableColumns & res_columns, Conte const RolesOrUsersSet & apply_to) { column_name.insertData(name.data(), name.length()); - column_id.push_back(id); + column_id.push_back(id.toUnderType()); column_storage.insertData(storage_name.data(), storage_name.length()); column_num_elements.push_back(elements.size()); diff --git a/src/Storages/System/StorageSystemUsers.cpp b/src/Storages/System/StorageSystemUsers.cpp index e60f1372df9..77888820d28 100644 --- a/src/Storages/System/StorageSystemUsers.cpp +++ b/src/Storages/System/StorageSystemUsers.cpp @@ -95,7 +95,7 @@ void StorageSystemUsers::fillData(MutableColumns & res_columns, ContextPtr conte const RolesOrUsersSet & grantees) { column_name.insertData(name.data(), name.length()); - column_id.push_back(id); + column_id.push_back(id.toUnderType()); column_storage.insertData(storage_name.data(), storage_name.length()); column_auth_type.push_back(static_cast(authentication.getType()));