| /** |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| **/ |
| |
| #ifndef QUICKSTEP_TYPES_OPERATIONS_COMPARISONS_COMPARISON_UTIL_HPP_ |
| #define QUICKSTEP_TYPES_OPERATIONS_COMPARISONS_COMPARISON_UTIL_HPP_ |
| |
| #include <algorithm> |
| #include <cstddef> |
| #include <cstdint> |
| #include <limits> |
| #include <memory> |
| #include <type_traits> |
| |
| #include "catalog/CatalogTypedefs.hpp" |
| #include "types/DatetimeLit.hpp" |
| #include "types/IntervalLit.hpp" |
| #include "types/Type.hpp" |
| #include "types/TypeID.hpp" |
| #include "types/TypedValue.hpp" |
| #include "types/containers/Tuple.hpp" |
| #include "types/operations/comparisons/AsciiStringComparators.hpp" |
| #include "types/operations/comparisons/AsciiStringComparators-inl.hpp" |
| #include "types/operations/comparisons/Comparison.hpp" |
| #include "types/operations/comparisons/ComparisonFactory.hpp" |
| #include "types/operations/comparisons/ComparisonID.hpp" |
| #include "types/operations/comparisons/LiteralComparators.hpp" |
| #include "types/operations/comparisons/LiteralComparators-inl.hpp" |
| #include "utility/Macros.hpp" |
| |
| #include "glog/logging.h" |
| |
| namespace quickstep { |
| namespace comparison_util_detail { |
| |
| // This wraps an instance of the abstract base UncheckedComparator class and |
| // forwards calls from the inline -Inl methods to virtual methods of the base |
| // class. It is necessary for comparing types that are unknown to the macros |
| // and functions in this file (NOTE: it is vastly preferable to modify this |
| // file to be aware of a new type rather than relying on this slower fallback). |
| class GenericComparatorWrapper : public UncheckedComparator { |
| public: |
| explicit GenericComparatorWrapper(const UncheckedComparator &internal_comparator) |
| : internal_comparator_(internal_comparator) { |
| } |
| |
| ~GenericComparatorWrapper() { |
| } |
| |
| inline bool compareTypedValues(const TypedValue &left, const TypedValue &right) const { |
| return internal_comparator_.compareTypedValues(left, right); |
| } |
| |
| inline bool compareTypedValuesInl(const TypedValue &left, const TypedValue &right) const { |
| return internal_comparator_.compareTypedValues(left, right); |
| } |
| |
| inline bool compareDataPtrs(const void *left, const void *right) const { |
| return internal_comparator_.compareDataPtrs(left, right); |
| } |
| |
| inline bool compareDataPtrsInl(const void *left, const void *right) const { |
| return internal_comparator_.compareDataPtrs(left, right); |
| } |
| |
| inline bool compareTypedValueWithDataPtr(const TypedValue &left, |
| const void *right) const { |
| return internal_comparator_.compareTypedValueWithDataPtr(left, right); |
| } |
| |
| inline bool compareTypedValueWithDataPtrInl(const TypedValue &left, |
| const void *right) const { |
| return internal_comparator_.compareTypedValueWithDataPtr(left, right); |
| } |
| |
| inline bool compareDataPtrWithTypedValue(const void *left, |
| const TypedValue &right) const { |
| return internal_comparator_.compareDataPtrWithTypedValue(left, right); |
| } |
| |
| inline bool compareDataPtrWithTypedValueInl(const void *left, |
| const TypedValue &right) const { |
| return internal_comparator_.compareDataPtrWithTypedValue(left, right); |
| } |
| |
| private: |
| const UncheckedComparator &internal_comparator_; |
| }; |
| |
| } // namespace comparison_util_detail |
| |
| // TODO(chasseur): Maintaining the various Invoke* functions for new types and |
| // combinations of types is a bit of a pain. This is an instance of the |
| // double-dispatch problem that we are trying to resolve statically at compile |
| // time so that we can use fast inlined methods of comparators in generic |
| // algorithms. Try to think of a more clever and easily maintainable way of |
| // achieving the same ends. |
| |
| /** \addtogroup Types |
| * @{ |
| */ |
| |
| /** |
| * @brief Invoke a generic functor (or lambda) on a less-than comparator for |
| * a given Type (ignoring nullability). |
| * |
| * @param type The Type to compare. |
| * @param functor A generic functor or lambda that has a templated call |
| * operator taking a single argument. The call operator will be invoked |
| * with a less-than UncheckedComparator for type as its argument. The |
| * provided UncheckedComparator will be of a concrete type and its |
| * inline methods will be usable. |
| * @return The return value of functor's call operator applied to the less-than |
| * comparator. |
| **/ |
| template <typename FunctorT> |
| auto InvokeOnLessComparatorForTypeIgnoreNullability(const Type &type, |
| const FunctorT &functor) { |
| switch (type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<int, false, int, false> comp; |
| return functor(comp); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| std::int64_t, false> comp; |
| return functor(comp); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<float, false, |
| float, false> comp; |
| return functor(comp); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<double, false, |
| double, false> comp; |
| return functor(comp); |
| } |
| case kChar: { |
| const std::size_t string_length |
| = static_cast<const AsciiStringSuperType&>(type).getStringLength(); |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, false> |
| comp(string_length, string_length); |
| return functor(comp); |
| } |
| case kVarChar: { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, false> |
| comp(0, 0); |
| return functor(comp); |
| } |
| case kDate: { |
| LessLiteralUncheckedComparator<DateLit, false, |
| DateLit, false> comp; |
| return functor(comp); |
| } |
| case kDatetime: { |
| LessLiteralUncheckedComparator<DatetimeLit, false, |
| DatetimeLit, false> comp; |
| return functor(comp); |
| } |
| case kDatetimeInterval: { |
| LessLiteralUncheckedComparator<DatetimeIntervalLit, false, |
| DatetimeIntervalLit, false> |
| comp; |
| return functor(comp); |
| } |
| case kYearMonthInterval: { |
| LessLiteralUncheckedComparator<YearMonthIntervalLit, false, |
| YearMonthIntervalLit, false> |
| comp; |
| return functor(comp); |
| } |
| default: { |
| LOG(WARNING) |
| << "Developer warning: using generic fallback for unrecognized Type: " |
| << type.getName(); |
| std::unique_ptr<UncheckedComparator> generic_less_comparator( |
| ComparisonFactory::GetComparison(ComparisonID::kLess).makeUncheckedComparatorForTypes( |
| type, type)); |
| comparison_util_detail::GenericComparatorWrapper comp(*generic_less_comparator); |
| return functor(comp); |
| } |
| } |
| } |
| |
| namespace comparison_util_detail { |
| |
| // Fallback generic (slow) helper for |
| // InvokeOnLessComparatorForDifferentTypesIgnoreNullability() when that |
| // function doesn't know how to make a comparator for 'left_type' and |
| // 'right_type'. |
| template <typename FunctorT> |
| auto InvokeOnLessComparatorForDifferentTypesFallback( |
| const Type &left_type, |
| const Type &right_type, |
| const FunctorT &functor) { |
| LOG(WARNING) |
| << "Developer warning: using generic fallback for unrecognized pair of " |
| << "Types: " << left_type.getName() << ", " << right_type.getName(); |
| std::unique_ptr<UncheckedComparator> generic_less_comparator( |
| ComparisonFactory::GetComparison(ComparisonID::kLess).makeUncheckedComparatorForTypes( |
| left_type, right_type)); |
| GenericComparatorWrapper comp(*generic_less_comparator); |
| return functor(comp); |
| } |
| |
| } // namespace comparison_util_detail |
| |
| /** |
| * @brief Invoke a generic functor (or lambda) on a less-than comparator for |
| * a given pair of Types, which may be different (ignoring nullability). |
| * |
| * @param left_type The Type on the left side of the less-than comparison. |
| * @param right_type The Type on the right side of the less-than comparison. |
| * @param functor A generic functor or lambda that has a templated call |
| * operator taking a single argument. The call operator will be invoked |
| * with a less-than UncheckedComparator for left_type and right_type as |
| * its argument. The provided UncheckedComparator will be of a concrete |
| * type and its inline methods will be usable. |
| * @return The return value of functor's call operator applied to the less-than |
| * comparator. |
| **/ |
| template <typename FunctorT> |
| auto InvokeOnLessComparatorForDifferentTypesIgnoreNullability( |
| const Type &left_type, |
| const Type &right_type, |
| const FunctorT &functor) { |
| switch (left_type.getTypeID()) { |
| case kInt: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<int, false, int, false> comp; |
| return functor(comp); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<int, false, std::int64_t, false> comp; |
| return functor(comp); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<int, false, float, false> comp; |
| return functor(comp); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<int, false, double, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kLong: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<std::int64_t, false, int, false> comp; |
| return functor(comp); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| std::int64_t, false> comp; |
| return functor(comp); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| float, false> comp; |
| return functor(comp); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| double, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kFloat: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<float, false, int, false> comp; |
| return functor(comp); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<float, false, std::int64_t, false> comp; |
| return functor(comp); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<float, false, float, false> comp; |
| return functor(comp); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<float, false, double, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDouble: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<double, false, int, false> comp; |
| return functor(comp); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<double, false, std::int64_t, false> comp; |
| return functor(comp); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<double, false, float, false> comp; |
| return functor(comp); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<double, false, double, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kChar: { |
| const std::size_t left_string_length |
| = static_cast<const AsciiStringSuperType&>(left_type).getStringLength(); |
| switch (right_type.getTypeID()) { |
| case kChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, true> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, true, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } |
| } |
| case kVarChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, true, true> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, true, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kVarChar: { |
| const std::size_t left_string_length |
| = static_cast<const AsciiStringSuperType&>(left_type).getStringLength(); |
| switch (right_type.getTypeID()) { |
| case kChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, false, true> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, true, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } |
| } |
| case kVarChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, true> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, true, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } else { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| return functor(comp); |
| } |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDate: { |
| switch (right_type.getTypeID()) { |
| case kDate: { |
| LessLiteralUncheckedComparator<DateLit, false, |
| DateLit, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDatetime: { |
| switch (right_type.getTypeID()) { |
| case kDatetime: { |
| LessLiteralUncheckedComparator<DatetimeLit, false, |
| DatetimeLit, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDatetimeInterval: { |
| switch (right_type.getTypeID()) { |
| case kDatetimeInterval: { |
| LessLiteralUncheckedComparator<DatetimeIntervalLit, false, |
| DatetimeIntervalLit, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kYearMonthInterval: { |
| switch (right_type.getTypeID()) { |
| case kYearMonthInterval: { |
| LessLiteralUncheckedComparator<YearMonthIntervalLit, false, |
| YearMonthIntervalLit, false> comp; |
| return functor(comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| default: |
| return comparison_util_detail::InvokeOnLessComparatorForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| |
| namespace comparison_util_detail { |
| |
| // Fallback generic (slow) helper for |
| // InvokeOnBothLessComparatorForDifferentTypesIgnoreNullability() when that |
| // function doesn't know how to make comparators for 'left_type' and |
| // 'right_type'. |
| template <typename FunctorT> |
| auto InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| const Type &left_type, |
| const Type &right_type, |
| const FunctorT &functor) { |
| LOG(WARNING) |
| << "Developer warning: using generic fallback for unrecognized pair of " |
| << "Types: " << left_type.getName() << ", " << right_type.getName(); |
| |
| std::unique_ptr<UncheckedComparator> generic_less_comparator( |
| ComparisonFactory::GetComparison(ComparisonID::kLess).makeUncheckedComparatorForTypes( |
| left_type, right_type)); |
| GenericComparatorWrapper comp(*generic_less_comparator); |
| |
| std::unique_ptr<UncheckedComparator> generic_less_comparator_reversed( |
| ComparisonFactory::GetComparison(ComparisonID::kLess).makeUncheckedComparatorForTypes( |
| right_type, left_type)); |
| GenericComparatorWrapper comp_reversed(*generic_less_comparator_reversed); |
| |
| return functor(comp, comp_reversed); |
| } |
| |
| } // namespace comparison_util_detail |
| |
| /** |
| * @brief Invoke a generic functor (or lambda) on both directions of the |
| * less-than comparator for a given pair of Types, which may be |
| * different (ignoring nullability). |
| * |
| * @param left_type The Type on the left side of the less-than comparison. |
| * @param right_type The Type on the right side of the less-than comparison. |
| * @param functor A generic functor or lambda that has a templated call |
| * operator taking two arguments. The call operator will be invoked |
| * with a less-than UncheckedComparator for left_type < right_type as |
| * its first argument, and a comparator for right_type < left_type as |
| * its seconds argument. The provided UncheckedComparators will be of |
| * concrete types and their inline methods will be usable. |
| * @return The return value of functor's call operator applied to the less-than |
| * comparator. |
| **/ |
| template <typename FunctorT> |
| auto InvokeOnBothLessComparatorsForDifferentTypesIgnoreNullability( |
| const Type &left_type, |
| const Type &right_type, |
| const FunctorT &functor) { |
| switch (left_type.getTypeID()) { |
| case kInt: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<int, false, int, false> comp; |
| return functor(comp, comp); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<int, false, std::int64_t, false> comp; |
| LessLiteralUncheckedComparator<std::int64_t, false, int, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<int, false, float, false> comp; |
| LessLiteralUncheckedComparator<float, false, int, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<int, false, double, false> comp; |
| LessLiteralUncheckedComparator<double, false, int, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kLong: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<std::int64_t, false, int, false> comp; |
| LessLiteralUncheckedComparator<int, false, std::int64_t, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| std::int64_t, false> comp; |
| return functor(comp, comp); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| float, false> comp; |
| LessLiteralUncheckedComparator<float, false, |
| std::int64_t, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<std::int64_t, false, |
| double, false> comp; |
| LessLiteralUncheckedComparator<double, false, |
| std::int64_t, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kFloat: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<float, false, int, false> comp; |
| LessLiteralUncheckedComparator<int, false, float, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<float, false, std::int64_t, false> comp; |
| LessLiteralUncheckedComparator<std::int64_t, false, float, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<float, false, float, false> comp; |
| return functor(comp, comp); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<float, false, double, false> comp; |
| LessLiteralUncheckedComparator<double, false, float, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDouble: { |
| switch (right_type.getTypeID()) { |
| case kInt: { |
| LessLiteralUncheckedComparator<double, false, int, false> comp; |
| LessLiteralUncheckedComparator<int, false, double, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kLong: { |
| LessLiteralUncheckedComparator<double, false, std::int64_t, false> comp; |
| LessLiteralUncheckedComparator<std::int64_t, false, double, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kFloat: { |
| LessLiteralUncheckedComparator<double, false, float, false> comp; |
| LessLiteralUncheckedComparator<float, false, double, false> comp_reversed; |
| return functor(comp, comp_reversed); |
| } |
| case kDouble: { |
| LessLiteralUncheckedComparator<double, false, double, false> comp; |
| return functor(comp, comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kChar: { |
| const std::size_t left_string_length |
| = static_cast<const AsciiStringSuperType&>(left_type).getStringLength(); |
| switch (right_type.getTypeID()) { |
| case kChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, true> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, false, true, |
| false, false, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, true, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, true> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, false, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } |
| } |
| case kVarChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, true, true> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, true, true, |
| false, false, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, false, true, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, false, true> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else { |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, false, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kVarChar: { |
| const std::size_t left_string_length |
| = static_cast<const AsciiStringSuperType&>(left_type).getStringLength(); |
| switch (right_type.getTypeID()) { |
| case kChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, false, true> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, false, true, |
| false, true, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, true, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, true, true> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, false, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, false, false, |
| false, true, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } |
| } |
| case kVarChar: { |
| const std::size_t right_string_length |
| = static_cast<const AsciiStringSuperType&>(right_type).getStringLength(); |
| if (left_string_length < right_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, true> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, true, true, |
| false, true, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else if (right_string_length < left_string_length) { |
| LessAsciiStringUncheckedComparator<false, true, true, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, true> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } else { |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, false> |
| comp(left_string_length, right_string_length); |
| LessAsciiStringUncheckedComparator<false, true, false, |
| false, true, false> |
| comp_reversed(right_string_length, left_string_length); |
| return functor(comp, comp_reversed); |
| } |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDate: { |
| switch (right_type.getTypeID()) { |
| case kDate: { |
| LessLiteralUncheckedComparator<DateLit, false, |
| DateLit, false> comp; |
| return functor(comp, comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDatetime: { |
| switch (right_type.getTypeID()) { |
| case kDatetime: { |
| LessLiteralUncheckedComparator<DatetimeLit, false, |
| DatetimeLit, false> comp; |
| return functor(comp, comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kDatetimeInterval: { |
| switch (right_type.getTypeID()) { |
| case kDatetimeInterval: { |
| LessLiteralUncheckedComparator<DatetimeIntervalLit, false, |
| DatetimeIntervalLit, false> comp; |
| return functor(comp, comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| case kYearMonthInterval: { |
| switch (right_type.getTypeID()) { |
| case kYearMonthInterval: { |
| LessLiteralUncheckedComparator<YearMonthIntervalLit, false, |
| YearMonthIntervalLit, false> comp; |
| return functor(comp, comp); |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| default: |
| return comparison_util_detail::InvokeOnBothLessComparatorsForDifferentTypesFallback( |
| left_type, right_type, functor); |
| } |
| } |
| |
| /** |
| * @brief A functor object which wraps std::lower_bound. |
| **/ |
| template <class IteratorT, class T, class Compare> |
| struct LowerBoundFunctor { |
| static constexpr bool literal_on_left = false; |
| |
| /** |
| * @brief Calls std::lower_bound to do a binary search for a value in the |
| * specified range of iterators. |
| * |
| * @param first The beginning of the range to search (range must be sorted). |
| * @param last One past the end of the range to search. |
| * @param val The value to find the lower-bound position for. |
| * @param comp A comparison functor which compares val with the values at |
| * iterators in the range from first to last. |
| * @return The position in the range from first to last which is the lower |
| * bound for val. |
| **/ |
| inline IteratorT operator()(IteratorT first, |
| IteratorT last, |
| const T &val, |
| const Compare &comp) { |
| return std::lower_bound(first, last, val, comp); |
| } |
| }; |
| |
| /** |
| * @brief A functor object which wraps std::upper_bound. |
| **/ |
| template <class IteratorT, class T, class Compare> |
| struct UpperBoundFunctor { |
| static constexpr bool literal_on_left = true; |
| |
| /** |
| * @brief Calls std::upper_bound to do a binary search for a value in the |
| * specified range of iterators. |
| * |
| * @param first The beginning of the range to search (range must be sorted). |
| * @param last One past the end of the range to search. |
| * @param val The value to find the upper-bound position for. |
| * @param comp A comparison functor which compares val with the values at |
| * iterators in the range from first to last. |
| * @return The position in the range from first to last which is the upper |
| * bound for val. |
| **/ |
| inline IteratorT operator()(IteratorT first, |
| IteratorT last, |
| const T &val, |
| const Compare &comp) { |
| return std::upper_bound(first, last, val, comp); |
| } |
| }; |
| |
| /** |
| * @brief Find a boundary according to BoundFunctorT for untyped (i.e. void*) |
| * values of a specified type. |
| * |
| * @param type The Type of values to compare. |
| * @param begin_it The beginning of the range of values to search. |
| * @param end_it One past the end of the range of values to search. |
| * @param value The literal value to find a bound for. |
| * @return The position in the range from begin_it to end_it which is the bound |
| * for value according to BoundFunctorT. |
| **/ |
| template <typename IteratorT, |
| template <class BoundIteratorT, class T, class Compare> class BoundFunctorT> |
| inline IteratorT GetBoundForUntypedValue(const Type &type, |
| IteratorT begin_it, |
| IteratorT end_it, |
| const void *value) { |
| return InvokeOnLessComparatorForTypeIgnoreNullability( |
| type, |
| [&](const auto &comp) -> IteratorT { // NOLINT(build/c++11) |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type> |
| stl_comp(comp); |
| return BoundFunctorT<IteratorT, |
| const void*, |
| decltype(stl_comp)>()(begin_it, end_it, value, stl_comp); |
| }); |
| } |
| |
| /** |
| * @brief Similar to GetBoundForUntypedValue, but allows finding bounds for a |
| * value which is of a different type than the values in the range |
| * being searched. |
| * |
| * @param type The Type of values in the range from begin_it to end_it. |
| * @param begin_it The beginning of the range of values to search. |
| * @param end_it One past the end of the range of values to search. |
| * @param value The literal value to find a bound for, which need not be an |
| * instance of type so long as it is comparable with type. |
| * @param value_type The Type that value belongs to. |
| * @return The position in the range from begin_it to end_it which is the bound |
| * for value according to BoundFunctorT. |
| **/ |
| template <typename IteratorT, |
| template <class BoundIteratorT, class T, class Compare> class BoundFunctorT> |
| IteratorT GetBoundForDifferentTypedValue( |
| const Type &type, |
| IteratorT begin_it, |
| IteratorT end_it, |
| const TypedValue &value, |
| const Type &value_type) { |
| constexpr bool literal_on_left |
| = BoundFunctorT<IteratorT, |
| const void*, |
| STLUncheckedComparatorWrapper<UncheckedComparator>>::literal_on_left; |
| if (literal_on_left) { |
| return InvokeOnLessComparatorForDifferentTypesIgnoreNullability( |
| value_type, type, |
| [&](const auto &comp) -> IteratorT { // NOLINT(build/c++11) |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type> |
| stl_comp(comp); |
| return BoundFunctorT<IteratorT, |
| const void*, |
| decltype(stl_comp)>()(begin_it, end_it, value.getDataPtr(), stl_comp); |
| }); |
| } else { |
| return InvokeOnLessComparatorForDifferentTypesIgnoreNullability( |
| type, |
| value_type, |
| [&](const auto &comp) -> IteratorT { // NOLINT(build/c++11) |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type> |
| stl_comp(comp); |
| return BoundFunctorT<IteratorT, |
| const void*, |
| decltype(stl_comp)>()(begin_it, end_it, value.getDataPtr(), stl_comp); |
| }); |
| } |
| } |
| |
| /** |
| * @brief Determine if two untyped values are equal. |
| * |
| * @param type The Type which the untyped values should be interpreted as. |
| * @param left The first value to check for equality. |
| * @param right The second value to check for equality. |
| * @return Whether left is equal to right (treating both values as instances of |
| * type). |
| **/ |
| inline bool CheckUntypedValuesEqual(const Type &type, const void *left, const void *right) { |
| switch (type.getTypeID()) { |
| case kInt: |
| return STLLiteralEqual<int>()(left, right); |
| case kLong: |
| return STLLiteralEqual<std::int64_t>()(left, right); |
| case kFloat: |
| return STLLiteralEqual<float>()(left, right); |
| case kDouble: |
| return STLLiteralEqual<double>()(left, right); |
| case kChar: |
| return STLCharEqual(static_cast<const AsciiStringSuperType&>(type).getStringLength())(left, right); |
| case kVarChar: |
| return STLVarCharEqual()(left, right); |
| case kDate: |
| return STLLiteralEqual<DateLit>()(left, right); |
| case kDatetime: |
| return STLLiteralEqual<DatetimeLit>()(left, right); |
| case kDatetimeInterval: |
| return STLLiteralEqual<DatetimeIntervalLit>()(left, right); |
| case kYearMonthInterval: |
| return STLLiteralEqual<YearMonthIntervalLit>()(left, right); |
| default: { |
| DEV_WARNING("Unrecognized type encountered in CheckUntypedValuesEqual() " |
| "from types/operations/comparisons/ComparisonUtil.hpp. This file should be updated " |
| "to be aware of the new type."); |
| std::unique_ptr<UncheckedComparator> generic_comp( |
| ComparisonFactory::GetComparison(ComparisonID::kEqual) |
| .makeUncheckedComparatorForTypes(type, type)); |
| return generic_comp->compareDataPtrs(left, right); |
| } |
| } |
| } |
| |
| /** |
| * @brief Sort a range of values into ascending order. |
| * |
| * @param type The Type which values in the range from begin_it to end_it |
| * should be treated as. |
| * @param begin_it The beginning of the range of values to sort. |
| * @param end_it One past the end of the range of values to sort. |
| **/ |
| template <typename IteratorT> |
| void SortValues(const Type &type, |
| IteratorT begin_it, |
| IteratorT end_it) { |
| InvokeOnLessComparatorForTypeIgnoreNullability( |
| type, |
| [&](const auto &comp) { // NOLINT(build/c++11) |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type> |
| stl_comp(comp); |
| std::sort(begin_it, end_it, stl_comp); |
| }); |
| } |
| |
| /** |
| * @brief An adapter which wraps a ComparatorT comparison functor for objects |
| * of type ValueT, which supports a method getDataPtr() to return an |
| * untyped pointer to an underlying value. |
| **/ |
| template <typename ValueT, typename ComparatorT> |
| class ComparatorAdapter { |
| public: |
| /** |
| * @brief Constructor. |
| * |
| * @param comparator The comparison functor to adapt. |
| **/ |
| explicit ComparatorAdapter(const ComparatorT &comparator = ComparatorT()) |
| : comparator_(comparator) { |
| } |
| |
| /** |
| * @brief Apply the comparator provided to the constructor to the underlying |
| * values represented by left and right. |
| * |
| * @param left The left value to compare. |
| * @param right The right value to compare. |
| * @return The result of applying the adapted comparator to left and right. |
| **/ |
| inline bool operator()(const ValueT &left, const ValueT &right) { |
| return comparator_(left.getDataPtr(), right.getDataPtr()); |
| } |
| |
| private: |
| ComparatorT comparator_; |
| }; |
| |
| /** |
| * @brief Sort a range of wrapped values (which provide a getDataPtr() method |
| * to access underlying data) into ascending order. |
| * |
| * @note This always sorts the range from begin_it to end_it into ascending |
| * order, but the underlying sequence can be sorted in descending order |
| * by using reverse iterators. |
| * |
| * @param type The Type which values should be interpreted as. |
| * @param begin_it The beginning of the range of wrapped values to sort. |
| * @param end_it One past the end of the range of wrapped values to sort. |
| **/ |
| template <typename ValueT, typename IteratorT> |
| void SortWrappedValues(const Type &type, |
| IteratorT begin_it, |
| IteratorT end_it) { |
| InvokeOnLessComparatorForTypeIgnoreNullability( |
| type, |
| [&](const auto &comp) { // NOLINT(build/c++11) |
| std::sort( |
| begin_it, |
| end_it, |
| ComparatorAdapter< |
| ValueT, |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type>>( |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type>( |
| comp))); |
| }); |
| } |
| |
| /** |
| * @brief Sort a range of wrapped values (which provide a getDataPtr() method |
| * to access underlying data). |
| * |
| * @note This always sorts the range from begin_it to end_it into ascending |
| * order, but the underlying sequence can be sorted in descending order |
| * by using reverse iterators. |
| * |
| * @param type The Type which values should be interpreted as. |
| * @param begin_it The beginning of the range of wrapped values to sort. |
| * @param end_it One past the end of the range of wrapped values to sort. |
| **/ |
| template <typename ValueT, typename IteratorT> |
| void StableSortWrappedValues(const Type &type, |
| IteratorT begin_it, |
| IteratorT end_it) { |
| InvokeOnLessComparatorForTypeIgnoreNullability( |
| type, |
| [&](const auto &comp) { // NOLINT(build/c++11) |
| std::stable_sort( |
| begin_it, |
| end_it, |
| ComparatorAdapter< |
| ValueT, |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type>>( |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type>( |
| comp))); |
| }); |
| } |
| |
| /** |
| * @brief Find a boundary according to BoundFunctorT for wrapped values (which |
| * provide a getDataPtr() method to access underlying data, and a |
| * a single-argument constructor which takes a const void* pointing to a |
| * literal value). |
| * |
| * @param type The Type of values to compare. |
| * @param begin_it The beginning of the range of values to search. |
| * @param end_it One past the end of the range of values to search. |
| * @param value The literal value to find a bound for. |
| * @return The position in the range from begin_it to end_it which is the bound |
| * for value according to BoundFunctorT. |
| **/ |
| template <typename ValueT, |
| typename IteratorT, |
| template <class BoundIteratorT, class T, class Compare> class BoundFunctorT> |
| inline IteratorT GetBoundForWrappedValues(const Type &type, |
| IteratorT begin_it, |
| IteratorT end_it, |
| const void *value) { |
| return InvokeOnLessComparatorForTypeIgnoreNullability( |
| type, |
| [&](const auto &comp) -> IteratorT { // NOLINT(build/c++11) |
| STLUncheckedComparatorWrapper<typename std::remove_reference<decltype(comp)>::type> |
| stl_comp(comp); |
| ComparatorAdapter<ValueT, decltype(stl_comp)> stl_comp_adapter(stl_comp); |
| return BoundFunctorT<IteratorT, |
| ValueT, |
| decltype(stl_comp_adapter)>()(begin_it, |
| end_it, |
| ValueT(value), |
| stl_comp_adapter); |
| }); |
| } |
| |
| /** |
| * @brief An adapter which compares tuples according to the value of a |
| * particular attribute. |
| **/ |
| template <typename AttributeComparatorT> |
| class STLTupleComparator { |
| public: |
| /** |
| * @brief Constructor. |
| * |
| * @param attr_id The ID of the attribute which Tuples should be compared by. |
| * @param attr_comp A comparison functor which can compare values of the |
| * attribute specified by attr_id. |
| **/ |
| STLTupleComparator(const attribute_id attr_id, |
| const AttributeComparatorT &attr_comp) |
| : attr_id_(attr_id), |
| attr_comp_(attr_comp) { |
| } |
| |
| inline bool operator() (const Tuple &left, const Tuple &right) const { |
| return attr_comp_(left.getAttributeValue(attr_id_), |
| right.getAttributeValue(attr_id_)); |
| } |
| |
| inline bool operator() (const Tuple *left, const Tuple *right) const { |
| return attr_comp_(left->getAttributeValue(attr_id_), |
| right->getAttributeValue(attr_id_)); |
| } |
| |
| private: |
| const attribute_id attr_id_; |
| AttributeComparatorT attr_comp_; |
| }; |
| |
| /** |
| * @brief Sort a range of Tuples into ascending order by comparing values of a |
| * particular attribute. |
| * |
| * @param sort_attr_id The ID of the attribute to order tuples by. |
| * @param sort_attr_type The Type of the attribute indicated by sort_attr_id. |
| * @param begin_it The beginning of the range of tuples to sort. |
| * @param end_it One past the end of the range of tuples to sort. |
| **/ |
| template <typename IteratorT> |
| void SortTuples(const attribute_id sort_attr_id, |
| const Type &sort_attr_type, |
| IteratorT begin_it, |
| IteratorT end_it) { |
| DCHECK(!sort_attr_type.isNullable()); |
| InvokeOnLessComparatorForTypeIgnoreNullability( |
| sort_attr_type, |
| [&](const auto &comp) { // NOLINT(build/c++11) |
| std::sort( |
| begin_it, |
| end_it, |
| STLTupleComparator< |
| STLUncheckedComparatorWrapper< |
| typename std::remove_reference<decltype(comp)>::type>>( |
| sort_attr_id, |
| STLUncheckedComparatorWrapper< |
| typename std::remove_reference<decltype(comp)>::type>(comp))); |
| }); |
| } |
| |
| /** |
| * @brief Get a special value for a Type that compares after all other values |
| * for the type. |
| * @warning In general, it is still possible for user-supplied data to compare |
| * as equal to a value generated by this method. |
| * |
| * @param type The Type to generate a "last" value for. |
| * @return A value that comes after all other values for type. |
| **/ |
| inline TypedValue GetLastValueForType(const Type &type) { |
| static const char kLastString[] = "\x7F"; // ASCII "DEL" control code. |
| |
| switch (type.getTypeID()) { |
| case kInt: |
| return TypedValue(std::numeric_limits<int>::max()); |
| case kLong: |
| return TypedValue(std::numeric_limits<std::int64_t>::max()); |
| case kFloat: |
| return TypedValue(std::numeric_limits<float>::max()); |
| case kDouble: |
| return TypedValue(std::numeric_limits<double>::max()); |
| case kChar: |
| return TypedValue(kChar, kLastString, 2); |
| case kVarChar: |
| return TypedValue(kVarChar, kLastString, 2); |
| case kDate: { |
| return TypedValue(DateLit::Create(99999, 12, 31)); |
| } |
| case kDatetime: { |
| DatetimeLit lit; |
| lit.ticks = std::numeric_limits<std::int64_t>::max(); |
| return TypedValue(lit); |
| } |
| case kDatetimeInterval: { |
| DatetimeIntervalLit lit; |
| lit.interval_ticks = std::numeric_limits<std::int64_t>::max(); |
| return TypedValue(lit); |
| } |
| case kYearMonthInterval: { |
| YearMonthIntervalLit lit; |
| lit.months = std::numeric_limits<std::int64_t>::max(); |
| return TypedValue(lit); |
| } |
| default: |
| FATAL_ERROR("Unknown Type encountered in GetLastValueForType() in " |
| "types/operations/comparisons/ComparisonUtil.hpp"); |
| } |
| } |
| |
| /** @} */ |
| |
| } // namespace quickstep |
| |
| #endif // QUICKSTEP_TYPES_OPERATIONS_COMPARISONS_COMPARISON_UTIL_HPP_ |