mirror of
https://github.com/ClickHouse/ClickHouse.git
synced 2024-11-10 09:32:06 +00:00
Attempt to normalize big integers
This commit is contained in:
parent
60be962dca
commit
649550c5ab
199
base/common/DecomposedFloat.h
Normal file
199
base/common/DecomposedFloat.h
Normal file
@ -0,0 +1,199 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <common/extended_types.h>
|
||||
|
||||
|
||||
/// Allows to check the internals of IEEE-754 floating point number.
|
||||
|
||||
template <typename T> struct FloatTraits;
|
||||
|
||||
template <>
|
||||
struct FloatTraits<float>
|
||||
{
|
||||
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<double>
|
||||
{
|
||||
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 <typename T>
|
||||
struct DecomposedFloat
|
||||
{
|
||||
using Traits = FloatTraits<T>;
|
||||
|
||||
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<int16_t>(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 <typename Int>
|
||||
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<int16_t>(8 * sizeof(Int) + is_signed_v<Int>))
|
||||
return false;
|
||||
|
||||
using UInt = make_unsigned_t<Int>;
|
||||
UInt uint_rhs = rhs < 0 ? -rhs : rhs;
|
||||
|
||||
/// Smaller octave
|
||||
if (uint_rhs < (static_cast<UInt>(1) << normalized_exponent()))
|
||||
return false;
|
||||
|
||||
/// Larger octave
|
||||
if (normalized_exponent() + 1 < static_cast<int16_t>(8 * sizeof(Int) + is_signed_v<Int>)
|
||||
&& uint_rhs >= (static_cast<UInt>(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<UInt>(1) << normalized_exponent()) == (mantissa() >> (Traits::mantissa_bits - normalized_exponent()));
|
||||
}
|
||||
|
||||
|
||||
template <typename Int>
|
||||
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<int16_t>(8 * sizeof(Int) + is_signed_v<Int>))
|
||||
return sign();
|
||||
|
||||
using UInt = make_unsigned_t<Int>;
|
||||
UInt uint_rhs = rhs < 0 ? -rhs : rhs;
|
||||
|
||||
/// Smaller octave
|
||||
if (uint_rhs < (static_cast<UInt>(1) << normalized_exponent()))
|
||||
return !sign();
|
||||
|
||||
/// Larger octave
|
||||
if (normalized_exponent() + 1 < static_cast<int16_t>(8 * sizeof(Int) + is_signed_v<Int>)
|
||||
&& uint_rhs >= (static_cast<UInt>(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<UInt>(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 <typename Int>
|
||||
bool greaterOrEquals(Int rhs)
|
||||
{
|
||||
return !less(rhs);
|
||||
}
|
||||
|
||||
template <typename Int>
|
||||
bool lessOrEquals(Int rhs)
|
||||
{
|
||||
return less(rhs) || equals(rhs);
|
||||
}
|
||||
|
||||
template <typename Int>
|
||||
bool greater(Int rhs)
|
||||
{
|
||||
return !lessOrEquals(rhs);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
using DecomposedFloat64 = DecomposedFloat<double>;
|
||||
using DecomposedFloat32 = DecomposedFloat<float>;
|
@ -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<Int128>::max() - y) ||
|
||||
(y < 0 && x < std::numeric_limits<Int128>::min() - y);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool addOverflow(UInt128 x, UInt128 y, UInt128 & res)
|
||||
{
|
||||
res = addIgnoreOverflow(x, y);
|
||||
return x > std::numeric_limits<UInt128>::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<Int128>::max() + y) ||
|
||||
(y > 0 && x < std::numeric_limits<Int128>::min() + y);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool subOverflow(UInt128 x, UInt128 y, UInt128 & res)
|
||||
{
|
||||
res = subIgnoreOverflow(x, y);
|
||||
return x < y;
|
||||
}
|
||||
|
||||
template <>
|
||||
|
@ -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;
|
||||
|
@ -40,10 +40,10 @@ public:
|
||||
return l == r;
|
||||
|
||||
if constexpr (isDecimalField<T>() && std::is_arithmetic_v<U>)
|
||||
return accurate::equalsOp(l.getValue(), r);
|
||||
return l == DecimalField<Decimal256>(Decimal256(r), 0);
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T> && isDecimalField<U>())
|
||||
return accurate::equalsOp(l, r.getValue());
|
||||
return DecimalField<Decimal256>(Decimal256(l), 0) == r;
|
||||
|
||||
if constexpr (std::is_same_v<T, String> && std::is_arithmetic_v<U>)
|
||||
{
|
||||
@ -94,10 +94,10 @@ public:
|
||||
return l < r;
|
||||
|
||||
if constexpr (isDecimalField<T>() && std::is_arithmetic_v<U>)
|
||||
return accurate::lessOp(l.getValue(), r);
|
||||
return l < DecimalField<Decimal256>(Decimal256(r), 0);
|
||||
|
||||
if constexpr (std::is_arithmetic_v<T> && isDecimalField<U>())
|
||||
return accurate::lessOp(l, r.getValue());
|
||||
return DecimalField<Decimal256>(Decimal256(l), 0) < r;
|
||||
|
||||
if constexpr (std::is_same_v<T, String> && std::is_arithmetic_v<U>)
|
||||
{
|
||||
|
@ -180,6 +180,28 @@ inline size_t DefaultHash64(std::enable_if_t<(sizeof(T) <= sizeof(UInt64)), T> k
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline size_t DefaultHash64(std::enable_if_t<(sizeof(T) > sizeof(UInt64)), T> key)
|
||||
{
|
||||
if constexpr (is_big_int_v<T> && sizeof(T) == 16)
|
||||
{
|
||||
/// TODO This is classical antipattern.
|
||||
return intHash64(
|
||||
static_cast<UInt64>(key) ^
|
||||
static_cast<UInt64>(key >> 64));
|
||||
}
|
||||
else if constexpr (is_big_int_v<T> && sizeof(T) == 32)
|
||||
{
|
||||
return intHash64(
|
||||
static_cast<UInt64>(key) ^
|
||||
static_cast<UInt64>(key >> 64) ^
|
||||
static_cast<UInt64>(key >> 128) ^
|
||||
static_cast<UInt64>(key >> 256));
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
|
||||
template <typename T, typename Enable = void>
|
||||
struct DefaultHash;
|
||||
|
||||
@ -197,7 +219,7 @@ struct DefaultHash<T, std::enable_if_t<DB::IsDecimalNumber<T>>>
|
||||
{
|
||||
size_t operator() (T key) const
|
||||
{
|
||||
return DefaultHash64<typename T::NativeType>(key);
|
||||
return DefaultHash64<typename T::NativeType>(key.value);
|
||||
}
|
||||
};
|
||||
|
||||
@ -322,28 +344,6 @@ template <>
|
||||
struct DefaultHash<DB::UInt256> : public UInt256Hash {};
|
||||
|
||||
|
||||
template <typename T>
|
||||
inline size_t DefaultHash64(std::enable_if_t<(sizeof(T) > sizeof(UInt64)), T> key)
|
||||
{
|
||||
if constexpr (std::is_same_v<T, DB::Int128>)
|
||||
{
|
||||
return intHash64(static_cast<UInt64>(key) ^ static_cast<UInt64>(key >> 64));
|
||||
}
|
||||
if constexpr (std::is_same_v<T, DB::UInt128>)
|
||||
{
|
||||
return intHash64(key.low ^ key.high); /// TODO This is classical antipattern.
|
||||
}
|
||||
else if constexpr (is_big_int_v<T> && sizeof(T) == 32)
|
||||
{
|
||||
return intHash64(static_cast<UInt64>(key) ^
|
||||
static_cast<UInt64>(key >> 64) ^
|
||||
static_cast<UInt64>(key >> 128) ^
|
||||
static_cast<UInt64>(key >> 256));
|
||||
}
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
|
||||
/// It is reasonable to use for UInt8, UInt16 with sufficient hash table size.
|
||||
struct TrivialHash
|
||||
{
|
||||
|
@ -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(
|
||||
|
@ -2,8 +2,9 @@
|
||||
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include "Defines.h"
|
||||
#include "Types.h"
|
||||
#include <common/DecomposedFloat.h>
|
||||
#include <Core/Defines.h>
|
||||
#include <Core/Types.h>
|
||||
#include <common/extended_types.h>
|
||||
#include <Common/NaNUtils.h>
|
||||
|
||||
@ -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 <typename A, typename B>
|
||||
constexpr bool is_safe_conversion = (std::is_floating_point_v<A> && std::is_floating_point_v<B>)
|
||||
|| (is_integer_v<A> && is_integer_v<B> && !(is_signed_v<A> ^ is_signed_v<B>));
|
||||
bool lessOp(A a, B b)
|
||||
{
|
||||
/// float vs float
|
||||
if constexpr (std::is_floating_point_v<A> && std::is_floating_point_v<B>)
|
||||
return a < b;
|
||||
|
||||
/// anything vs NaN
|
||||
if constexpr (std::is_floating_point_v<A> || std::is_floating_point_v<B>)
|
||||
if (isNaN(a) || isNaN(b))
|
||||
return false;
|
||||
|
||||
/// int vs int
|
||||
if constexpr (is_integer_v<A> && is_integer_v<B>)
|
||||
{
|
||||
/// same signedness
|
||||
if constexpr (is_signed_v<A> == is_signed_v<B>)
|
||||
return a < b;
|
||||
|
||||
/// different signedness
|
||||
|
||||
if constexpr (is_signed_v<A> && !is_signed_v<B>)
|
||||
return a < 0 || static_cast<B>(a) < b;
|
||||
|
||||
if constexpr (!is_signed_v<A> && is_signed_v<B>)
|
||||
return b >= 0 && a < static_cast<A>(b);
|
||||
}
|
||||
|
||||
/// int vs float
|
||||
if constexpr (is_integer_v<A> && std::is_floating_point_v<B>)
|
||||
{
|
||||
if constexpr (sizeof(A) <= 4)
|
||||
return static_cast<double>(a) < static_cast<double>(b);
|
||||
|
||||
return DecomposedFloat<B>(b).greater(a);
|
||||
}
|
||||
|
||||
if constexpr (std::is_floating_point_v<A> && is_integer_v<B>)
|
||||
{
|
||||
if constexpr (sizeof(B) <= 4)
|
||||
return static_cast<double>(a) < static_cast<double>(b);
|
||||
|
||||
return DecomposedFloat<A>(a).less(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
using bool_if_safe_conversion = std::enable_if_t<is_safe_conversion<A, B>, bool>;
|
||||
bool greaterOp(A a, B b)
|
||||
{
|
||||
return lessOp(b, a);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
using bool_if_not_safe_conversion = std::enable_if_t<!is_safe_conversion<A, B>, bool>;
|
||||
|
||||
|
||||
/// Case 2. Are params IntXX and UIntYY ?
|
||||
template <typename TInt, typename TUInt>
|
||||
constexpr bool is_any_int_vs_uint
|
||||
= is_integer_v<TInt> && is_integer_v<TUInt> && is_signed_v<TInt> && is_unsigned_v<TUInt>;
|
||||
|
||||
// Case 2a. Are params IntXX and UIntYY and sizeof(IntXX) <= sizeof(UIntYY) (in such case will use accurate compare)
|
||||
template <typename TInt, typename TUInt>
|
||||
constexpr bool is_le_int_vs_uint = is_any_int_vs_uint<TInt, TUInt> && (sizeof(TInt) <= sizeof(TUInt));
|
||||
|
||||
static_assert(is_le_int_vs_uint<Int128, UInt128>);
|
||||
static_assert(is_le_int_vs_uint<Int128, UInt256>);
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
using bool_if_le_int_vs_uint_t = std::enable_if_t<is_le_int_vs_uint<TInt, TUInt>, bool>;
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> greaterOpTmpl(TInt a, TUInt b)
|
||||
bool greaterOrEqualsOp(A a, B b)
|
||||
{
|
||||
return static_cast<TUInt>(a) > b && a >= 0 && b <= static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
return !lessOp(a, b);
|
||||
}
|
||||
|
||||
template <typename TUInt, typename TInt>
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> greaterOpTmpl(TUInt a, TInt b)
|
||||
template <typename A, typename B>
|
||||
bool lessOrEqualsOp(A a, B b)
|
||||
{
|
||||
return a > static_cast<TUInt>(b) || b < 0 || a > static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
return !lessOp(b, a);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> equalsOpTmpl(TInt a, TUInt b)
|
||||
template <typename A, typename B>
|
||||
bool equalsOp(A a, B b)
|
||||
{
|
||||
return static_cast<TUInt>(a) == b && a >= 0 && b <= static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
}
|
||||
/// float vs float
|
||||
if constexpr (std::is_floating_point_v<A> && std::is_floating_point_v<B>)
|
||||
return a == b;
|
||||
|
||||
template <typename TUInt, typename TInt>
|
||||
inline bool_if_le_int_vs_uint_t<TInt, TUInt> equalsOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return a == static_cast<TUInt>(b) && b >= 0 && a <= static_cast<TUInt>(std::numeric_limits<TInt>::max());
|
||||
}
|
||||
/// anything vs NaN
|
||||
if constexpr (std::is_floating_point_v<A> || std::is_floating_point_v<B>)
|
||||
if (isNaN(a) || isNaN(b))
|
||||
return false;
|
||||
|
||||
/// int vs int
|
||||
if constexpr (is_integer_v<A> && is_integer_v<B>)
|
||||
{
|
||||
/// same signedness
|
||||
if constexpr (is_signed_v<A> == is_signed_v<B>)
|
||||
return a == b;
|
||||
|
||||
// Case 2b. Are params IntXX and UIntYY and sizeof(IntXX) > sizeof(UIntYY) (in such case will cast UIntYY to IntXX and compare)
|
||||
template <typename TInt, typename TUInt>
|
||||
constexpr bool is_gt_int_vs_uint = is_any_int_vs_uint<TInt, TUInt> && (sizeof(TInt) > sizeof(TUInt));
|
||||
/// different signedness
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
using bool_if_gt_int_vs_uint = std::enable_if_t<is_gt_int_vs_uint<TInt, TUInt>, bool>;
|
||||
if constexpr (is_signed_v<A> && !is_signed_v<B>)
|
||||
return a >= 0 && static_cast<B>(a) == b;
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> greaterOpTmpl(TInt a, TUInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) > static_cast<TInt>(b);
|
||||
}
|
||||
if constexpr (!is_signed_v<A> && is_signed_v<B>)
|
||||
return b >= 0 && a == static_cast<A>(b);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> greaterOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) > static_cast<TInt>(b);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> equalsOpTmpl(TInt a, TUInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) == static_cast<TInt>(b);
|
||||
}
|
||||
|
||||
template <typename TInt, typename TUInt>
|
||||
inline bool_if_gt_int_vs_uint<TInt, TUInt> equalsOpTmpl(TUInt a, TInt b)
|
||||
{
|
||||
return static_cast<TInt>(a) == static_cast<TInt>(b);
|
||||
}
|
||||
|
||||
|
||||
// Case 3a. Comparison via conversion to double.
|
||||
template <typename TAInt, typename TAFloat>
|
||||
using bool_if_double_can_be_used
|
||||
= std::enable_if_t<is_integer_v<TAInt> && (sizeof(TAInt) <= 4) && std::is_floating_point_v<TAFloat>, bool>;
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> greaterOpTmpl(TAInt a, TAFloat b)
|
||||
{
|
||||
return static_cast<double>(a) > static_cast<double>(b);
|
||||
}
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> greaterOpTmpl(TAFloat a, TAInt b)
|
||||
{
|
||||
return static_cast<double>(a) > static_cast<double>(b);
|
||||
}
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAInt a, TAFloat b)
|
||||
{
|
||||
/// int vs float
|
||||
if constexpr (is_integer_v<A> && std::is_floating_point_v<B>)
|
||||
{
|
||||
if constexpr (sizeof(A) <= 4)
|
||||
return static_cast<double>(a) == static_cast<double>(b);
|
||||
}
|
||||
|
||||
template <typename TAInt, typename TAFloat>
|
||||
inline bool_if_double_can_be_used<TAInt, TAFloat> equalsOpTmpl(TAFloat a, TAInt b)
|
||||
{
|
||||
return DecomposedFloat<B>(b).equals(a);
|
||||
}
|
||||
|
||||
if constexpr (std::is_floating_point_v<A> && is_integer_v<B>)
|
||||
{
|
||||
if constexpr (sizeof(B) <= 4)
|
||||
return static_cast<double>(a) == static_cast<double>(b);
|
||||
}
|
||||
|
||||
// Big integers vs Float (not equal in any case for now, until big floats are introduced?)
|
||||
template <typename TABigInt, typename TAFloat>
|
||||
constexpr bool if_big_int_vs_float = (is_big_int_v<TABigInt> && std::is_floating_point_v<TAFloat>);
|
||||
|
||||
template <typename TABigInt, typename TAFloat>
|
||||
using bool_if_big_int_vs_float = std::enable_if_t<if_big_int_vs_float<TABigInt, TAFloat>, bool>;
|
||||
|
||||
template <typename TABigInt, typename TAFloat>
|
||||
inline bool_if_big_int_vs_float<TABigInt, TAFloat> greaterOpTmpl(TAFloat, TABigInt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TABigInt, typename TAFloat>
|
||||
inline bool_if_big_int_vs_float<TABigInt, TAFloat> greaterOpTmpl(TABigInt, TAFloat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TABigInt, typename TAFloat>
|
||||
inline bool_if_big_int_vs_float<TABigInt, TAFloat> equalsOpTmpl(TAFloat, TABigInt)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename TABigInt, typename TAFloat>
|
||||
inline bool_if_big_int_vs_float<TABigInt, TAFloat> equalsOpTmpl(TABigInt, TAFloat)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Final implementations */
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool greaterOp(A a, B b)
|
||||
{
|
||||
return greaterOpTmpl(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)
|
||||
|
||||
constexpr Int64 MAX_INT64_WITH_EXACT_FLOAT64_REPR = 9007199254740992LL; // 2^53
|
||||
|
||||
template <>
|
||||
inline bool greaterOp<Float64, Int64>(Float64 f, Int64 i)
|
||||
{
|
||||
if (-MAX_INT64_WITH_EXACT_FLOAT64_REPR <= i && i <= MAX_INT64_WITH_EXACT_FLOAT64_REPR)
|
||||
return f > static_cast<Float64>(i);
|
||||
|
||||
return (f >= static_cast<Float64>(std::numeric_limits<Int64>::max())) // rhs is 2**63 (not 2^63 - 1)
|
||||
|| (f > static_cast<Float64>(std::numeric_limits<Int64>::min()) && static_cast<Int64>(f) > i);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool greaterOp<Int64, Float64>(Int64 i, Float64 f)
|
||||
{
|
||||
if (-MAX_INT64_WITH_EXACT_FLOAT64_REPR <= i && i <= MAX_INT64_WITH_EXACT_FLOAT64_REPR)
|
||||
return f < static_cast<Float64>(i);
|
||||
|
||||
return (f < static_cast<Float64>(std::numeric_limits<Int64>::min()))
|
||||
|| (f < static_cast<Float64>(std::numeric_limits<Int64>::max()) && i > static_cast<Int64>(f));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool greaterOp<Float64, UInt64>(Float64 f, UInt64 u)
|
||||
{
|
||||
if (u <= static_cast<UInt64>(MAX_INT64_WITH_EXACT_FLOAT64_REPR))
|
||||
return f > static_cast<Float64>(u);
|
||||
|
||||
return (f >= static_cast<Float64>(std::numeric_limits<UInt64>::max()))
|
||||
|| (f >= 0 && static_cast<UInt64>(f) > u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool greaterOp<UInt64, Float64>(UInt64 u, Float64 f)
|
||||
{
|
||||
if (u <= static_cast<UInt64>(MAX_INT64_WITH_EXACT_FLOAT64_REPR))
|
||||
return static_cast<Float64>(u) > f;
|
||||
|
||||
return (f < 0)
|
||||
|| (f < static_cast<Float64>(std::numeric_limits<UInt64>::max()) && u > static_cast<UInt64>(f));
|
||||
}
|
||||
|
||||
// Case 3b for float32
|
||||
template <> inline bool greaterOp<Float32, Int64>(Float32 f, Int64 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
template <> inline bool greaterOp<Float32, Int128>(Float32 f, Int128 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
template <> inline bool greaterOp<Float32, Int256>(Float32 f, Int256 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
template <> inline bool greaterOp<Float32, UInt64>(Float32 f, UInt64 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
template <> inline bool greaterOp<Float32, UInt128>(Float32 f, UInt128 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
template <> inline bool greaterOp<Float32, UInt256>(Float32 f, UInt256 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
|
||||
template <> inline bool greaterOp<Int64, Float32>(Int64 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
template <> inline bool greaterOp<Int128, Float32>(Int128 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
template <> inline bool greaterOp<Int256, Float32>(Int256 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
template <> inline bool greaterOp<UInt64, Float32>(UInt64 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
template <> inline bool greaterOp<UInt128, Float32>(UInt128 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
template <> inline bool greaterOp<UInt256, Float32>(UInt256 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_conversion<A, B> equalsOp(A a, B b)
|
||||
{
|
||||
return equalsOpTmpl(a, b);
|
||||
return DecomposedFloat<A>(a).equals(b);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_conversion<A, B> equalsOp(A a, B b)
|
||||
{
|
||||
using LargestType = std::conditional_t<(sizeof(A) >= sizeof(B)), A, B>;
|
||||
|
||||
return static_cast<LargestType>(a) == static_cast<LargestType>(b);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::Float64, DB::UInt64>(DB::Float64 f, DB::UInt64 u)
|
||||
{
|
||||
/// Maximum exactly representable integer.
|
||||
return u <= (1ULL << std::numeric_limits<DB::Float64>::digits)
|
||||
&& f == static_cast<DB::Float64>(u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::UInt64, DB::Float64>(DB::UInt64 u, DB::Float64 f)
|
||||
{
|
||||
return equalsOp(f, u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::Float64, DB::Int64>(DB::Float64 f, DB::Int64 u)
|
||||
{
|
||||
return u <= (1LL << std::numeric_limits<DB::Float64>::digits)
|
||||
&& u >= -(1LL << std::numeric_limits<DB::Float64>::digits)
|
||||
&& f == static_cast<DB::Float64>(u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::Int64, DB::Float64>(DB::Int64 u, DB::Float64 f)
|
||||
{
|
||||
return equalsOp(f, u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::Float32, DB::UInt64>(DB::Float32 f, DB::UInt64 u)
|
||||
{
|
||||
return u <= (1ULL << std::numeric_limits<DB::Float32>::digits)
|
||||
&& f == static_cast<DB::Float32>(u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::UInt64, DB::Float32>(DB::UInt64 u, DB::Float32 f)
|
||||
{
|
||||
return equalsOp(f, u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::Float32, DB::Int64>(DB::Float32 f, DB::Int64 u)
|
||||
{
|
||||
return u <= (1LL << std::numeric_limits<DB::Float32>::digits)
|
||||
&& u >= -(1LL << std::numeric_limits<DB::Float32>::digits)
|
||||
&& f == static_cast<DB::Float32>(u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::Int64, DB::Float32>(DB::Int64 u, DB::Float32 f)
|
||||
{
|
||||
return equalsOp(f, u);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<DB::UInt128, DB::Float64>(DB::UInt128 u, DB::Float64 f)
|
||||
{
|
||||
/// TODO: This is wrong.
|
||||
return u.items[0] == 0 && equalsOp(static_cast<UInt64>(u.items[1]), f);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<UInt128, Float32>(UInt128 u, Float32 f)
|
||||
{
|
||||
return equalsOp(u, static_cast<Float64>(f));
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<Float64, UInt128>(Float64 f, UInt128 u)
|
||||
{
|
||||
return equalsOp(u, f);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool equalsOp<Float32, UInt128>(Float32 f, UInt128 u)
|
||||
{
|
||||
return equalsOp(static_cast<Float64>(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<Float64>(i) > f;
|
||||
|
||||
return (f < static_cast<Float64>(min_int128))
|
||||
|| (f < static_cast<Float64>(max_int128) && i > static_cast<Int128>(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<Float64>(i);
|
||||
|
||||
return (f >= static_cast<Float64>(max_int128))
|
||||
|| (f > static_cast<Float64>(min_int128) && static_cast<Int128>(f) > i);
|
||||
}
|
||||
|
||||
inline bool greaterOp(Int128 i, Float32 f) { return greaterOp(i, static_cast<Float64>(f)); }
|
||||
inline bool greaterOp(Float32 f, Int128 i) { return greaterOp(static_cast<Float64>(f), i); }
|
||||
|
||||
inline bool NO_SANITIZE_UNDEFINED equalsOp(Int128 i, Float64 f) { return i == static_cast<Int128>(f) && static_cast<Float64>(i) == f; }
|
||||
inline bool NO_SANITIZE_UNDEFINED equalsOp(Int128 i, Float32 f) { return i == static_cast<Int128>(f) && static_cast<Float32>(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 <typename A, typename B>
|
||||
inline bool notEqualsOp(A a, B b)
|
||||
bool notEqualsOp(A a, B b)
|
||||
{
|
||||
return !equalsOp(a, b);
|
||||
}
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool lessOp(A a, B b)
|
||||
{
|
||||
return greaterOp(b, a);
|
||||
}
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_conversion<A, B> lessOrEqualsOp(A a, B b)
|
||||
{
|
||||
if (isNaN(a) || isNaN(b))
|
||||
return false;
|
||||
return !greaterOp(a, b);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_conversion<A, B> lessOrEqualsOp(A a, B b)
|
||||
{
|
||||
return a <= b;
|
||||
}
|
||||
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_not_safe_conversion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
{
|
||||
if (isNaN(a) || isNaN(b))
|
||||
return false;
|
||||
return !greaterOp(b, a);
|
||||
}
|
||||
|
||||
template <typename A, typename B>
|
||||
inline bool_if_safe_conversion<A, B> greaterOrEqualsOp(A a, B b)
|
||||
{
|
||||
return a >= b;
|
||||
}
|
||||
|
||||
/// Converts numeric to an equal numeric of other type.
|
||||
template <typename From, typename To>
|
||||
inline bool NO_SANITIZE_UNDEFINED convertNumeric(From value, To & result)
|
||||
|
@ -845,6 +845,8 @@ decltype(auto) castToNearestFieldType(T && x)
|
||||
using U = NearestFieldType<std::decay_t<T>>;
|
||||
if constexpr (std::is_same_v<std::decay_t<T>, U>)
|
||||
return std::forward<T>(x);
|
||||
else if constexpr (std::is_same_v<std::decay_t<T>, UUID>)
|
||||
return U(x.toUnderType());
|
||||
else
|
||||
return U(x);
|
||||
}
|
||||
|
@ -180,6 +180,8 @@ struct Decimal
|
||||
|
||||
template <typename T> inline bool operator< (const Decimal<T> & x, const Decimal<T> & y) { return x.value < y.value; }
|
||||
template <typename T> inline bool operator> (const Decimal<T> & x, const Decimal<T> & y) { return x.value > y.value; }
|
||||
template <typename T> inline bool operator<= (const Decimal<T> & x, const Decimal<T> & y) { return x.value <= y.value; }
|
||||
template <typename T> inline bool operator>= (const Decimal<T> & x, const Decimal<T> & y) { return x.value >= y.value; }
|
||||
template <typename T> inline bool operator== (const Decimal<T> & x, const Decimal<T> & y) { return x.value == y.value; }
|
||||
template <typename T> inline bool operator!= (const Decimal<T> & x, const Decimal<T> & y) { return x.value != y.value; }
|
||||
|
||||
|
@ -290,7 +290,7 @@ namespace
|
||||
if (value.type() == Poco::MongoDB::ElementTraits<String>::TypeId)
|
||||
{
|
||||
String string = static_cast<const Poco::MongoDB::ConcreteElement<String> &>(value).value();
|
||||
assert_cast<ColumnUInt128 &>(column).getData().push_back(parse<UUID>(string));
|
||||
assert_cast<ColumnUInt128 &>(column).getData().push_back(parse<UUID>(string).toUnderType());
|
||||
}
|
||||
else
|
||||
throw Exception{"Type mismatch, expected String (UUID), got type id = " + toString(value.type()) + " for column "
|
||||
|
@ -113,15 +113,15 @@ public:
|
||||
|
||||
T maxWholeValue() const { return getScaleMultiplier(precision - scale) - T(1); }
|
||||
|
||||
template<typename U>
|
||||
template <typename U>
|
||||
bool canStoreWhole(U x) const
|
||||
{
|
||||
static_assert(std::is_signed_v<typename T::NativeType>);
|
||||
static_assert(is_signed_v<typename T::NativeType>);
|
||||
T max = maxWholeValue();
|
||||
if constexpr (std::is_signed_v<U>)
|
||||
return -max <= x && x <= max;
|
||||
if constexpr (is_signed_v<U>)
|
||||
return -max.value <= x && x <= max.value;
|
||||
else
|
||||
return x <= static_cast<std::make_unsigned_t<typename T::NativeType>>(max.value);
|
||||
return x <= static_cast<make_unsigned_t<typename T::NativeType>>(max.value);
|
||||
}
|
||||
|
||||
/// @returns multiplier for U to become T with correct scale
|
||||
|
@ -235,9 +235,9 @@ convertToDecimalImpl(const typename FromDataType::FieldType & value, UInt32 scal
|
||||
if constexpr (is_big_int_v<FromFieldType>)
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal256>, ToDataType, ReturnType>(static_cast<Int256>(value), 0, scale, result));
|
||||
else if constexpr (std::is_same_v<FromFieldType, UInt64>)
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal128>, ToDataType, ReturnType>(value, 0, scale, result));
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal128>, ToDataType, ReturnType>(static_cast<Int128>(value), 0, scale, result));
|
||||
else
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal64>, ToDataType, ReturnType>(value, 0, scale, result));
|
||||
return ReturnType(convertDecimalsImpl<DataTypeDecimal<Decimal64>, ToDataType, ReturnType>(static_cast<Int64>(value), 0, scale, result));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,7 +18,7 @@ void SerializationUUID::deserializeText(IColumn & column, ReadBuffer & istr, con
|
||||
{
|
||||
UUID x;
|
||||
readText(x, istr);
|
||||
assert_cast<ColumnUInt128 &>(column).getData().push_back(x);
|
||||
assert_cast<ColumnUInt128 &>(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<ColumnUInt128 &>(column).getData().push_back(x); /// It's important to do this at the end - for exception safety.
|
||||
assert_cast<ColumnUInt128 &>(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<ColumnUInt128 &>(column).getData().push_back(x);
|
||||
assert_cast<ColumnUInt128 &>(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<ColumnUInt128 &>(column).getData().push_back(value);
|
||||
assert_cast<ColumnUInt128 &>(column).getData().push_back(value.toUnderType());
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -782,7 +782,7 @@ class FunctionBinaryArithmetic : public IFunction
|
||||
return function->execute(new_arguments, result_type, input_rows_count);
|
||||
}
|
||||
|
||||
template <class T, class ResultDataType, class CC, class C>
|
||||
template <typename T, typename ResultDataType, typename CC, typename C>
|
||||
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<ResultDataType> && IsDecimalNumber<T>)
|
||||
return DecimalUtils::convertTo<NativeResultType>(col_const->template getValue<T>(), col.getScale());
|
||||
else if constexpr (IsDecimalNumber<T>)
|
||||
return col_const->template getValue<T>().value;
|
||||
else
|
||||
return col_const->template getValue<T>();
|
||||
}
|
||||
|
||||
template <OpCase op_case, bool left_decimal, bool right_decimal, class OpImpl, class OpImplCheck,
|
||||
class L, class R, class VR, class SA, class SB>
|
||||
template <OpCase op_case, bool left_decimal, bool right_decimal, typename OpImpl, typename OpImplCheck,
|
||||
typename L, typename R, typename VR, typename SA, typename SB>
|
||||
void helperInvokeEither(const L& left, const R& right, VR& vec_res, SA scale_a, SB scale_b) const
|
||||
{
|
||||
if (check_decimal_overflow)
|
||||
|
@ -784,7 +784,7 @@ inline void parseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer & rb
|
||||
{
|
||||
UUID tmp;
|
||||
readUUIDText(tmp, rb);
|
||||
x = tmp;
|
||||
x = tmp.toUnderType();
|
||||
}
|
||||
|
||||
|
||||
@ -824,7 +824,7 @@ inline bool tryParseImpl<DataTypeUUID>(DataTypeUUID::FieldType & x, ReadBuffer &
|
||||
if (!tryReadUUIDText(tmp, rb))
|
||||
return false;
|
||||
|
||||
x = tmp;
|
||||
x = tmp.toUnderType();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -45,11 +45,7 @@ void writeSlice(const NumericArraySlice<T> & slice, NumericArraySink<U> & sink)
|
||||
|
||||
if constexpr (OverBigInt<T> || OverBigInt<U>)
|
||||
{
|
||||
if constexpr (std::is_same_v<U, UInt128>)
|
||||
{
|
||||
throw Exception("No conversion between UInt128 and " + demangle(typeid(T).name()), ErrorCodes::NOT_IMPLEMENTED);
|
||||
}
|
||||
else if constexpr (IsDecimalNumber<T>)
|
||||
if constexpr (IsDecimalNumber<T>)
|
||||
dst = static_cast<NativeU>(src.value);
|
||||
else
|
||||
dst = static_cast<NativeU>(src);
|
||||
|
@ -14,7 +14,7 @@ struct GenericArraySink;
|
||||
template <typename ArraySink>
|
||||
struct NullableArraySink;
|
||||
|
||||
using NumericArraySinks = typename TypeListMap<NumericArraySink, TypeListNumbersAndUInt128>::Type;
|
||||
using NumericArraySinks = typename TypeListMap<NumericArraySink, TypeListNumbers>::Type;
|
||||
using BasicArraySinks = typename AppendToTypeList<GenericArraySink, NumericArraySinks>::Type;
|
||||
using NullableArraySinks = typename TypeListMap<NullableArraySink, BasicArraySinks>::Type;
|
||||
using TypeListArraySinks = typename TypeListConcat<BasicArraySinks, NullableArraySinks>::Type;
|
||||
|
@ -17,7 +17,7 @@ struct NullableArraySource;
|
||||
template <typename Base>
|
||||
struct ConstSource;
|
||||
|
||||
using NumericArraySources = typename TypeListMap<NumericArraySource, TypeListNumbersAndUInt128>::Type;
|
||||
using NumericArraySources = typename TypeListMap<NumericArraySource, TypeListNumbers>::Type;
|
||||
using BasicArraySources = typename AppendToTypeList<GenericArraySource, NumericArraySources>::Type;
|
||||
|
||||
class ArraySourceVisitor : public ApplyTypeListForClass<Visitor, BasicArraySources>::Type
|
||||
|
@ -17,7 +17,7 @@ struct NullableValueSource;
|
||||
template <typename Base>
|
||||
struct ConstSource;
|
||||
|
||||
using NumericValueSources = typename TypeListMap<NumericValueSource, TypeListNumbersAndUInt128>::Type;
|
||||
using NumericValueSources = typename TypeListMap<NumericValueSource, TypeListNumbers>::Type;
|
||||
using BasicValueSources = typename AppendToTypeList<GenericValueSource, NumericValueSources>::Type;
|
||||
using NullableValueSources = typename TypeListMap<NullableValueSource, BasicValueSources>::Type;
|
||||
using BasicAndNullableValueSources = typename TypeListConcat<BasicValueSources, NullableValueSources>::Type;
|
||||
|
@ -55,7 +55,7 @@ struct ArraySinkCreator<>
|
||||
|
||||
std::unique_ptr<IArraySink> createArraySink(ColumnArray & col, size_t column_size)
|
||||
{
|
||||
using Creator = ApplyTypeListForClass<ArraySinkCreator, TypeListNumbersAndUInt128>::Type;
|
||||
using Creator = ApplyTypeListForClass<ArraySinkCreator, TypeListNumbers>::Type;
|
||||
return Creator::create(col.getData(), col.getOffsets(), column_size);
|
||||
}
|
||||
}
|
||||
|
@ -58,7 +58,7 @@ struct ArraySourceCreator<>
|
||||
|
||||
std::unique_ptr<IArraySource> createArraySource(const ColumnArray & col, bool is_const, size_t total_rows)
|
||||
{
|
||||
using Creator = typename ApplyTypeListForClass<ArraySourceCreator, TypeListNumbersAndUInt128>::Type;
|
||||
using Creator = typename ApplyTypeListForClass<ArraySourceCreator, TypeListNumbers>::Type;
|
||||
if (const auto * column_nullable = typeid_cast<const ColumnNullable *>(&col.getData()))
|
||||
{
|
||||
auto column = ColumnArray::create(column_nullable->getNestedColumnPtr(), col.getOffsetsPtr());
|
||||
|
@ -58,7 +58,7 @@ struct ValueSourceCreator<>
|
||||
|
||||
std::unique_ptr<IValueSource> createValueSource(const IColumn & col, bool is_const, size_t total_rows)
|
||||
{
|
||||
using Creator = typename ApplyTypeListForClass<ValueSourceCreator, TypeListNumbersAndUInt128>::Type;
|
||||
using Creator = typename ApplyTypeListForClass<ValueSourceCreator, TypeListNumbers>::Type;
|
||||
if (const auto * column_nullable = typeid_cast<const ColumnNullable *>(&col))
|
||||
{
|
||||
return Creator::create(column_nullable->getNestedColumn(), &column_nullable->getNullMapData(), is_const, total_rows);
|
||||
|
@ -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,11 +206,14 @@ 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)
|
||||
{
|
||||
if constexpr (IsDecimalNumber<AggregationType>)
|
||||
res[i] = s.value;
|
||||
else
|
||||
res[i] = s;
|
||||
continue;
|
||||
}
|
||||
@ -250,7 +253,7 @@ struct ArrayAggregateImpl
|
||||
{
|
||||
if constexpr (IsDecimalNumber<Element>)
|
||||
{
|
||||
s = s / count;
|
||||
s = s / AggregationType(count);
|
||||
res[i] = DecimalUtils::convertTo<Result>(s, data.getScale());
|
||||
}
|
||||
else
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -57,7 +57,7 @@ struct ArrayDifferenceImpl
|
||||
{
|
||||
if (pos == begin)
|
||||
{
|
||||
dst[pos] = 0;
|
||||
dst[pos] = {};
|
||||
prev = src[pos];
|
||||
}
|
||||
else
|
||||
|
@ -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<ColumnType, ColumnString>::value || std::is_same<ColumnType, ColumnFixedString>::value)
|
||||
value = &map[columns[arg_num]->getDataAt(i)];
|
||||
else
|
||||
|
@ -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;
|
||||
|
@ -27,18 +27,6 @@ roundDownToPowerOfTwo(T x)
|
||||
return x <= 0 ? 0 : (T(1) << (63 - __builtin_clzll(x)));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline std::enable_if_t<std::is_same_v<T, Int128>, 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 <typename T>
|
||||
inline std::enable_if_t<std::is_same_v<T, Float32>, T>
|
||||
roundDownToPowerOfTwo(T x)
|
||||
|
@ -1,8 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include <Core/Types.h>
|
||||
#include <Common/HashTable/Hash.h>
|
||||
#include <Common/LRUCache.h>
|
||||
#include <Common/SipHash.h>
|
||||
#include <Common/UInt128.h>
|
||||
#include <Common/ProfileEvents.h>
|
||||
#include <IO/MMappedFile.h>
|
||||
|
||||
@ -39,8 +40,7 @@ public:
|
||||
hash.update(offset);
|
||||
hash.update(length);
|
||||
|
||||
hash.get128(key.low, key.high);
|
||||
|
||||
hash.get128(key);
|
||||
return key;
|
||||
}
|
||||
|
||||
|
@ -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<T>)
|
||||
{
|
||||
/// Perform relativelly slow overflow check only when
|
||||
/// number of decimal digits so far is close to the max for given type.
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <common/find_symbols.h>
|
||||
#include <common/StringRef.h>
|
||||
#include <common/wide_integer_to_string.h>
|
||||
#include <common/DecomposedFloat.h>
|
||||
|
||||
#include <Core/DecimalFunctions.h>
|
||||
#include <Core/Types.h>
|
||||
@ -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 <typename T>
|
||||
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 <typename T>
|
||||
|
@ -10,6 +10,7 @@
|
||||
# include <Interpreters/Context.h>
|
||||
# include <Interpreters/ExpressionActions.h>
|
||||
# include <Common/LRUCache.h>
|
||||
# include <Common/HashTable/Hash.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
|
@ -384,7 +384,7 @@ template <typename Value, typename Mapped> struct KeyGetterForTypeImpl<HashJoin:
|
||||
};
|
||||
template <typename Value, typename Mapped> struct KeyGetterForTypeImpl<HashJoin::Type::keys256, Value, Mapped>
|
||||
{
|
||||
using Type = ColumnsHashing::HashMethodKeysFixed<Value, UInt256, Mapped, false, false, false>;
|
||||
using Type = ColumnsHashing::HashMethodKeysFixed<Value, UInt256, Mapped, false, false, false, use_offset>;
|
||||
};
|
||||
template <typename Value, typename Mapped> struct KeyGetterForTypeImpl<HashJoin::Type::hashed, Value, Mapped>
|
||||
{
|
||||
|
@ -80,7 +80,7 @@ static Field convertIntToDecimalType(const Field & from, const DataTypeDecimal<T
|
||||
if (!type.canStoreWhole(value))
|
||||
throw Exception("Number is too much to place in " + type.getName(), ErrorCodes::ARGUMENT_OUT_OF_BOUND);
|
||||
|
||||
T scaled_value = type.getScaleMultiplier() * value;
|
||||
T scaled_value = type.getScaleMultiplier() * static_cast<T>(value);
|
||||
return DecimalField<T>(scaled_value, type.getScale());
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
|
@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
#include <Processors/ISimpleTransform.h>
|
||||
#include <Common/HashTable/HashMap.h>
|
||||
#include <Common/UInt128.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <AggregateFunctions/AggregateFunctionFactory.h>
|
||||
#include <Common/Arena.h>
|
||||
#include <Common/FieldVisitorsAccurateComparison.h>
|
||||
#include <common/arithmeticOverflow.h>
|
||||
#include <DataTypes/DataTypesNumber.h>
|
||||
#include <DataTypes/getLeastSupertype.h>
|
||||
#include <Interpreters/ExpressionActions.h>
|
||||
@ -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",
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include <deque>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include <vector>
|
||||
#include <Storages/MergeTree/MergeTreeDataPartUUID.h>
|
||||
|
||||
|
||||
namespace DB
|
||||
{
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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());
|
||||
};
|
||||
|
||||
|
@ -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))
|
||||
|
@ -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());
|
||||
|
||||
|
@ -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<Int8>(authentication.getType()));
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user