// Copyright 2023 PingCAP, Inc. // // Licensed 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. #pragma once #include #include #include #include #include namespace DB::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)); } }; } // namespace DB::GatherUtils