#pragma once #include #include #include namespace DB { /** Stuff for comparing numbers. * Integer values are compared as usual. * Floating-point numbers are compared this way that NaNs always end up at the end * (if you don't do this, the sort would not work at all). */ template struct CompareHelper { static constexpr bool less(T a, U b, int /*nan_direction_hint*/) { return a < b; } static constexpr bool greater(T a, U b, int /*nan_direction_hint*/) { return a > b; } static constexpr bool equals(T a, U b, int /*nan_direction_hint*/) { return a == b; } /** Compares two numbers. Returns a number less than zero, equal to zero, or greater than zero if a < b, a == b, a > b, respectively. * If one of the values is NaN, then * - if nan_direction_hint == -1 - NaN are considered less than all numbers; * - if nan_direction_hint == 1 - NaN are considered to be larger than all numbers; * Essentially: nan_direction_hint == -1 says that the comparison is for sorting in descending order. */ static constexpr int compare(T a, U b, int /*nan_direction_hint*/) { return a > b ? 1 : (a < b ? -1 : 0); } }; template struct FloatCompareHelper { static constexpr bool less(T a, T b, int nan_direction_hint) { const bool isnan_a = std::isnan(a); const bool isnan_b = std::isnan(b); if (isnan_a && isnan_b) return false; if (isnan_a) return nan_direction_hint < 0; if (isnan_b) return nan_direction_hint > 0; return a < b; } static constexpr bool greater(T a, T b, int nan_direction_hint) { const bool isnan_a = std::isnan(a); const bool isnan_b = std::isnan(b); if (isnan_a && isnan_b) return false; if (isnan_a) return nan_direction_hint > 0; if (isnan_b) return nan_direction_hint < 0; return a > b; } static constexpr bool equals(T a, T b, int nan_direction_hint) { return compare(a, b, nan_direction_hint) == 0; } static constexpr int compare(T a, T b, int nan_direction_hint) { const bool isnan_a = std::isnan(a); const bool isnan_b = std::isnan(b); if (unlikely(isnan_a || isnan_b)) { if (isnan_a && isnan_b) return 0; return isnan_a ? nan_direction_hint : -nan_direction_hint; } return (T(0) < (a - b)) - ((a - b) < T(0)); } }; template struct CompareHelper : public FloatCompareHelper { }; template struct CompareHelper : public FloatCompareHelper { }; }