#pragma once #include "block_item.h" #include #include #include namespace NYql::NUdf { // ABI stable class IBlockItemComparator { public: using TPtr = TUniquePtr; virtual ~IBlockItemComparator() = default; virtual i64 Compare(TBlockItem lhs, TBlockItem rhs) const = 0; virtual bool Equals(TBlockItem lhs, TBlockItem rhs) const = 0; virtual bool Less(TBlockItem lhs, TBlockItem rhs) const = 0; inline bool Greater(TBlockItem lhs, TBlockItem rhs) const { return Less(rhs, lhs); } }; UDF_ASSERT_TYPE_SIZE(IBlockItemComparator, 8); template class TBlockItemComparatorBase : public IBlockItemComparator { public: const TDerived* Derived() const { return static_cast(this); } // returns <0 if lhs < rhs i64 Compare(TBlockItem lhs, TBlockItem rhs) const final { if constexpr (Nullable) { if (lhs) { if (rhs) { return Derived()->DoCompare(lhs, rhs); } else { return +1; } } else { if (rhs) { return -1; } else { return 0; } } } else { return Derived()->DoCompare(lhs, rhs); } } bool Equals(TBlockItem lhs, TBlockItem rhs) const final { if constexpr (Nullable) { if (lhs) { if (rhs) { return Derived()->DoEquals(lhs, rhs); } else { return false; } } else { if (rhs) { return false; } else { return true; } } } else { return Derived()->DoEquals(lhs, rhs); } } bool Less(TBlockItem lhs, TBlockItem rhs) const final { if constexpr (Nullable) { if (lhs) { if (rhs) { return Derived()->DoLess(lhs, rhs); } else { return false; } } else { if (rhs) { return true; } else { return false; } } } else { return Derived()->DoLess(lhs, rhs); } } }; template class TFixedSizeBlockItemComparator : public TBlockItemComparatorBase, Nullable> { public: i64 DoCompare(TBlockItem lhs, TBlockItem rhs) const { if constexpr (std::is_integral::value && sizeof(T) < sizeof(i64)) { return i64(lhs.As()) - i64(rhs.As()); } else { if constexpr (std::is_floating_point::value) { if (std::isunordered(lhs.As(), rhs.As())) { return i64(std::isnan(lhs.As())) - i64(std::isnan(rhs.As())); } } return (lhs.As() > rhs.As()) - (lhs.As() < rhs.As()); } } bool DoEquals(TBlockItem lhs, TBlockItem rhs) const { if constexpr (std::is_floating_point::value) { if (std::isunordered(lhs.As(), rhs.As())) { return std::isnan(lhs.As()) == std::isnan(rhs.As()); } } return lhs.As() == rhs.As(); } bool DoLess(TBlockItem lhs, TBlockItem rhs) const { if constexpr (std::is_floating_point::value) { if (std::isunordered(lhs.As(), rhs.As())) { return std::isnan(lhs.As()) < std::isnan(rhs.As()); } } return lhs.As() < rhs.As(); } }; template class TFixedSizeBlockItemComparator : public TBlockItemComparatorBase, Nullable> { public: i64 DoCompare(TBlockItem lhs, TBlockItem rhs) const { auto l = lhs.GetInt128(); auto r = rhs.GetInt128(); return (l > r) - (l < r); } bool DoEquals(TBlockItem lhs, TBlockItem rhs) const { auto l = lhs.GetInt128(); auto r = rhs.GetInt128(); return l == r; } bool DoLess(TBlockItem lhs, TBlockItem rhs) const { auto l = lhs.GetInt128(); auto r = rhs.GetInt128(); return l < r; } }; template class TStringBlockItemComparator : public TBlockItemComparatorBase, Nullable> { public: i64 DoCompare(TBlockItem lhs, TBlockItem rhs) const { return lhs.AsStringRef().Compare(rhs.AsStringRef()); } bool DoEquals(TBlockItem lhs, TBlockItem rhs) const { return lhs.AsStringRef() == rhs.AsStringRef(); } bool DoLess(TBlockItem lhs, TBlockItem rhs) const { return lhs.AsStringRef() < rhs.AsStringRef(); } }; template class TTzDateBlockItemComparator : public TBlockItemComparatorBase, Nullable> { using TLayout = typename TDataType::TLayout; public: bool DoCompare(TBlockItem lhs, TBlockItem rhs) const { const auto x = lhs.Get(); const auto y = rhs.Get(); if (x == y) { const auto tx = lhs.GetTimezoneId(); const auto ty = rhs.GetTimezoneId(); return (tx == ty) ? 0 : (tx < ty ? -1 : 1); } if (x < y) { return -1; } return 1; } bool DoEquals(TBlockItem lhs, TBlockItem rhs) const { return lhs.Get() == rhs.Get() && lhs.GetTimezoneId() == rhs.GetTimezoneId(); } bool DoLess(TBlockItem lhs, TBlockItem rhs) const { return std::forward_as_tuple(lhs.Get(), lhs.GetTimezoneId()) < std::forward_as_tuple(rhs.Get(), rhs.GetTimezoneId()); } }; template class TTupleBlockItemComparator : public TBlockItemComparatorBase, Nullable> { public: TTupleBlockItemComparator(TVector>&& children) : Children_(std::move(children)) {} public: i64 DoCompare(TBlockItem lhs, TBlockItem rhs) const { for (ui32 i = 0; i < Children_.size(); ++i) { auto res = Children_[i]->Compare(lhs.AsTuple()[i], rhs.AsTuple()[i]); if (res != 0) { return res; } } return 0; } bool DoEquals(TBlockItem lhs, TBlockItem rhs) const { for (ui32 i = 0; i < Children_.size(); ++i) { if (!Children_[i]->Equals(lhs.AsTuple()[i], rhs.AsTuple()[i])) { return false; } } return true; } bool DoLess(TBlockItem lhs, TBlockItem rhs) const { for (ui32 i = 0; i < Children_.size(); ++i) { auto res = Children_[i]->Compare(lhs.AsTuple()[i], rhs.AsTuple()[i]); if (res < 0) { return true; } if (res > 0) { return false; } } return false; } private: const TVector> Children_; }; class TExternalOptionalBlockItemComparator : public TBlockItemComparatorBase { public: TExternalOptionalBlockItemComparator(std::unique_ptr inner) : Inner_(std::move(inner)) {} i64 DoCompare(TBlockItem lhs, TBlockItem rhs) const { return Inner_->Compare(lhs.GetOptionalValue(), rhs.GetOptionalValue()); } bool DoEquals(TBlockItem lhs, TBlockItem rhs) const { return Inner_->Equals(lhs.GetOptionalValue(), rhs.GetOptionalValue()); } bool DoLess(TBlockItem lhs, TBlockItem rhs) const { return Inner_->Less(lhs.GetOptionalValue(), rhs.GetOptionalValue()); } private: std::unique_ptr Inner_; }; }