#pragma once #include "Algorithms.h" #include "ArraySourceVisitor.h" #include "ArraySinkVisitor.h" #include "ValueSourceVisitor.h" namespace DB { namespace ErrorCodes { extern const int LOGICAL_ERROR; } namespace GatherUtils { /// Base classes which selects template function implementation with concrete ArraySource or ArraySink /// Derived classes should implement selectImpl for ArraySourceSelector and ArraySinkSelector, /// selectSourceSink for ArraySinkSourceSelector and selectSourcePair for ArraySourcePairSelector template void callSelectMemberFunctionWithTupleArgument(Tuple & tuple, Args && ... args) { if constexpr (index == std::tuple_size::value) Base::selectImpl(args ...); else callSelectMemberFunctionWithTupleArgument(tuple, args ..., std::get(tuple)); } template void callSelectSource(bool is_const, bool is_nullable, Tuple & tuple, Args && ... args) { if constexpr (index == std::tuple_size::value) Base::selectSource(is_const, is_nullable, args ...); else callSelectSource(is_const, is_nullable, tuple, args ..., std::get(tuple)); } template struct ArraySourceSelectorVisitor final : public ArraySourceVisitorImpl> { explicit ArraySourceSelectorVisitor(IArraySource & source, Args && ... args) : packed_args(args ...), array_source(source) {} using Tuple = std::tuple; template void visitImpl(Source & source) { callSelectSource(array_source.isConst(), array_source.isNullable(), packed_args, source); } Tuple packed_args; IArraySource & array_source; }; template struct ArraySourceSelector { template static void select(IArraySource & source, Args && ... args) { ArraySourceSelectorVisitor visitor(source, args ...); source.accept(visitor); } }; template struct ArraySinkSelectorVisitor final : public ArraySinkVisitorImpl> { explicit ArraySinkSelectorVisitor(Args && ... args) : packed_args(args ...) {} using Tuple = std::tuple; template void visitImpl(Sink & sink) { callSelectMemberFunctionWithTupleArgument(packed_args, sink); } Tuple packed_args; }; template struct ArraySinkSelector { template static void select(IArraySink & sink, Args && ... args) { ArraySinkSelectorVisitor visitor(args ...); sink.accept(visitor); } }; template struct ArraySourcePairSelector { template static void select(IArraySource & first, IArraySource & second, Args && ... args) { ArraySourceSelector::select(first, second, args ...); } template static void selectSource(bool is_const, bool is_nullable, FirstSource && first, IArraySource & second, Args && ... args) { ArraySourceSelector::select(second, is_const, is_nullable, first, args ...); } template static void selectSource(bool is_second_const, bool is_second_nullable, SecondSource && second, bool is_first_const, bool is_first_nullable, FirstSource && first, Args && ... args) { Base::selectSourcePair(is_first_const, is_first_nullable, first, is_second_const, is_second_nullable, second, args ...); } }; template struct ArrayAndValueSourceSelectorBySink : public ArraySinkSelector> { template static void selectImpl(Sink && sink, IArraySource & array_source, IValueSource & value_source, Args && ... args) { using SinkType = typename std::decay_t; using ArraySource = typename SinkType::CompatibleArraySource; using ValueSource = typename SinkType::CompatibleValueSource; auto check_type = [] (auto source_ptr) { if (source_ptr == nullptr) throw Exception(ErrorCodes::LOGICAL_ERROR, "{} expected {} or {} or {} or {} but got {}", demangle(typeid(Base).name()), demangle(typeid(typename SinkType::CompatibleArraySource).name()), demangle(typeid(ConstSource).name()), demangle(typeid(typename SinkType::CompatibleValueSource).name()), demangle(typeid(ConstSource).name()), demangle(typeid(*source_ptr).name())); }; auto check_type_and_call_concat = [& sink, & check_type, & args ...] (auto array_source_ptr, auto value_source_ptr) { check_type(array_source_ptr); check_type(value_source_ptr); Base::selectArrayAndValueSourceBySink(*array_source_ptr, *value_source_ptr, sink, args ...); }; if (array_source.isConst() && value_source.isConst()) check_type_and_call_concat(typeid_cast *>(&array_source), typeid_cast *>(&value_source)); else if (array_source.isConst()) check_type_and_call_concat(typeid_cast *>(&array_source), typeid_cast(&value_source)); else if (value_source.isConst()) check_type_and_call_concat(typeid_cast(&array_source), typeid_cast *>(&value_source)); else check_type_and_call_concat(typeid_cast(&array_source), typeid_cast(&value_source)); } }; } }