#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 struct ArraySourceSelectorVisitor : public ArraySourceVisitorImpl> { explicit ArraySourceSelectorVisitor(Args && ... args) : packed_args(args ...) {} using Tuple = std::tuple; template void visitImpl(Source & source) { callSelectMemberFunctionWithTupleArgument(packed_args, source); } Tuple packed_args; }; template struct ArraySourceSelector { template static void select(IArraySource & source, Args && ... args) { ArraySourceSelectorVisitor visitor(args ...); source.accept(visitor); } }; template struct ArraySinkSelectorVisitor : 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 ValueSourceSelectorVisitor : public ValueSourceVisitorImpl> { explicit ValueSourceSelectorVisitor(Args && ... args) : packed_args(args ...) {} using Tuple = std::tuple; template void visitImpl(Source & source) { callSelectMemberFunctionWithTupleArgument(packed_args, source); } Tuple packed_args; }; template struct ValueSourceSelector { template static void select(IValueSource & source, Args && ... args) { ValueSourceSelectorVisitor visitor(args ...); source.accept(visitor); } }; template struct ArraySinkSourceSelector { template static void select(IArraySource & source, IArraySink & sink, Args && ... args) { ArraySinkSelector::select(sink, source, args ...); } template static void selectImpl(Sink && sink, IArraySource & source, Args && ... args) { ArraySourceSelector::select(source, sink, args ...); } template static void selectImpl(Source && source, Sink && sink, Args && ... args) { Base::selectSourceSink(source, sink, args ...); } }; template struct ArraySourcePairSelector { template static void select(IArraySource & first, IArraySource & second, Args && ... args) { ArraySourceSelector::select(first, second, args ...); } template static void selectImpl(FirstSource && first, IArraySource & second, Args && ... args) { ArraySourceSelector::select(second, first, args ...); } template static void selectImpl(SecondSource && second, FirstSource && first, Args && ... args) { Base::selectSourcePair(first, second, args ...); } }; template struct ArrayAndValueSourceSelectorBySink : public ArraySinkSelector> { template static void selectImpl(Sink && sink, IArraySource & array_source, IValueSource & value_source, Args && ... args) { using SynkType = typename std::decay::type; using ArraySource = typename SynkType::CompatibleArraySource; using ValueSource = typename SynkType::CompatibleValueSource; auto checkType = [] (auto source_ptr) { if (source_ptr == nullptr) throw Exception(demangle(typeid(Base).name()) + " expected " + demangle(typeid(typename SynkType::CompatibleArraySource).name()) + " or " + demangle(typeid(ConstSource).name()) + " or " + demangle(typeid(typename SynkType::CompatibleValueSource).name()) + + " or " + demangle(typeid(ConstSource).name()) + " but got " + demangle(typeid(*source_ptr).name()), ErrorCodes::LOGICAL_ERROR); }; auto checkTypeAndCallConcat = [& sink, & checkType, & args ...] (auto array_source_ptr, auto value_source_ptr) { checkType(array_source_ptr); checkType(value_source_ptr); Base::selectArrayAndValueSourceBySink(*array_source_ptr, *value_source_ptr, sink, args ...); }; if (array_source.isConst() && value_source.isConst()) checkTypeAndCallConcat(typeid_cast *>(&array_source), typeid_cast *>(&value_source)); else if (array_source.isConst()) checkTypeAndCallConcat(typeid_cast *>(&array_source), typeid_cast(&value_source)); else if (value_source.isConst()) checkTypeAndCallConcat(typeid_cast(&array_source), typeid_cast *>(&value_source)); else checkTypeAndCallConcat(typeid_cast(&array_source), typeid_cast(&value_source)); } }; } }