#pragma once #include #include #include namespace DB { template struct TypePair { using LeftType = T; using RightType = U; }; template static bool callOnBasicType(TypeIndex number, F && f) { if constexpr (_int) { switch (number) { case TypeIndex::UInt8: return f(TypePair()); case TypeIndex::UInt16: return f(TypePair()); case TypeIndex::UInt32: return f(TypePair()); case TypeIndex::UInt64: return f(TypePair()); case TypeIndex::UInt128: return f(TypePair()); case TypeIndex::UInt256: return f(TypePair()); case TypeIndex::Int8: return f(TypePair()); case TypeIndex::Int16: return f(TypePair()); case TypeIndex::Int32: return f(TypePair()); case TypeIndex::Int64: return f(TypePair()); case TypeIndex::Int128: return f(TypePair()); case TypeIndex::Int256: return f(TypePair()); case TypeIndex::Enum8: return f(TypePair()); case TypeIndex::Enum16: return f(TypePair()); default: break; } } if constexpr (_decimal) { switch (number) { case TypeIndex::Decimal32: return f(TypePair()); case TypeIndex::Decimal64: return f(TypePair()); case TypeIndex::Decimal128: return f(TypePair()); case TypeIndex::Decimal256: return f(TypePair()); default: break; } } if constexpr (_float) { switch (number) { case TypeIndex::Float32: return f(TypePair()); case TypeIndex::Float64: return f(TypePair()); default: break; } } if constexpr (_datetime) { switch (number) { case TypeIndex::Date: return f(TypePair()); case TypeIndex::Date32: return f(TypePair()); case TypeIndex::DateTime: return f(TypePair()); case TypeIndex::DateTime64: return f(TypePair()); default: break; } } return false; } /// Unroll template using TypeIndex template static inline bool callOnBasicTypes(TypeIndex type_num1, TypeIndex type_num2, F && f) { if constexpr (_int) { switch (type_num1) { case TypeIndex::UInt8: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::UInt16: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::UInt32: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::UInt64: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::UInt128: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::UInt256: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Int8: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Int16: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Int32: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Int64: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Int128: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Int256: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Enum8: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Enum16: return callOnBasicType(type_num2, std::forward(f)); default: break; } } if constexpr (_decimal) { switch (type_num1) { case TypeIndex::Decimal32: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Decimal64: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Decimal128: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Decimal256: return callOnBasicType(type_num2, std::forward(f)); default: break; } } if constexpr (_float) { switch (type_num1) { case TypeIndex::Float32: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Float64: return callOnBasicType(type_num2, std::forward(f)); default: break; } } if constexpr (_datetime) { switch (type_num1) { case TypeIndex::Date: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::Date32: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::DateTime: return callOnBasicType(type_num2, std::forward(f)); case TypeIndex::DateTime64: return callOnBasicType(type_num2, std::forward(f)); default: break; } } return false; } class DataTypeDate; class DataTypeDate32; class DataTypeString; class DataTypeFixedString; class DataTypeUUID; class DataTypeIPv4; class DataTypeIPv6; class DataTypeDateTime; class DataTypeDateTime64; template class DataTypeEnum; template class DataTypeNumber; template class DataTypeDecimal; template static bool callOnIndexAndDataType(TypeIndex number, F && f, ExtraArgs && ... args) { switch (number) { case TypeIndex::UInt8: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::UInt16: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::UInt32: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::UInt64: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::UInt128: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::UInt256: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int8: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int16: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int32: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int64: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int128: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Int256: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Float32: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Float64: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Decimal32: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Decimal64: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Decimal128: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Decimal256: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Date: return f(TypePair(), std::forward(args)...); case TypeIndex::Date32: return f(TypePair(), std::forward(args)...); case TypeIndex::DateTime: return f(TypePair(), std::forward(args)...); case TypeIndex::DateTime64: return f(TypePair(), std::forward(args)...); case TypeIndex::String: return f(TypePair(), std::forward(args)...); case TypeIndex::FixedString: return f(TypePair(), std::forward(args)...); case TypeIndex::Enum8: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::Enum16: return f(TypePair, T>(), std::forward(args)...); case TypeIndex::UUID: return f(TypePair(), std::forward(args)...); case TypeIndex::IPv4: return f(TypePair(), std::forward(args)...); case TypeIndex::IPv6: return f(TypePair(), std::forward(args)...); case TypeIndex::Interval: return f(TypePair(), std::forward(args)...); default: break; } return false; } template static bool callOnTwoTypeIndexes(TypeIndex left_type, TypeIndex right_type, F && func) { return callOnIndexAndDataType(left_type, [&](const auto & left_types) -> bool { using LeftTypes = std::decay_t; using LeftType = typename LeftTypes::LeftType; return callOnIndexAndDataType(right_type, [&](const auto & right_types) -> bool { using RightTypes = std::decay_t; using RightType = typename RightTypes::LeftType; return std::forward(func)(TypePair()); }); }); } }