#pragma once #include #include namespace NYql::NPrivate::NRuntimeDispatch { template struct TTypeList {}; template struct TValueList {}; template decltype(auto) RuntimeDispatchOneElement(F&& func, TValueList, bool boolArg, TArgs&&... restArgs) { if (boolArg) { return RuntimeDispatchImpl( std::forward(func), TValueList(), std::forward(restArgs)...); } else { return RuntimeDispatchImpl( std::forward(func), TValueList(), std::forward(restArgs)...); } } template decltype(auto) RuntimeDispatchImpl(F&& func, TValueList, TArgs&&... args) { static_assert(sizeof...(TArgs) >= N, "RuntimeDispatch requires at least N arguments"); if constexpr (N == 0) { return func.template operator()(std::forward(args)...); } else { return RuntimeDispatchOneElement( std::forward(func), TValueList(), std::forward(args)...); } } template auto RuntimeDispatch(F&& func, TArgs&&... args) { return RuntimeDispatchImpl(std::forward(func), TValueList<>(), std::forward(args)...); } } // namespace NYql::NPrivate::NRuntimeDispatch #define YQL_PRIVATE_WRAP_LAMBDA_FOR_FUNCTION(call, returnType) \ [](auto&&... args) -> returnType { \ return call(std::forward(args)...); \ } #define YQL_PRIVATE_WRAP_LAMBDA_FOR_NEW(constructor, returnType) \ [](auto&&... args) -> returnType { \ return new constructor(std::forward(args)...); \ } // Dispatches at runtime to a template function based on N leading arguments. // Avoids the if/else branch hell. Example: // // Before: // if (a && b) { // return Foo(x); // } else if (a) { // return Foo(x); // } else if (b) { // return Foo(x); // } else { // return Foo(x); // } // // After: // return YQL_RUNTIME_DISPATCH(Foo, 2, a, b, x); #define YQL_RUNTIME_DISPATCH(funcName, N, ...) \ (NYql::NPrivate::NRuntimeDispatch::RuntimeDispatch<(N)>(YQL_PRIVATE_WRAP_LAMBDA_FOR_FUNCTION(funcName, decltype(auto)), __VA_ARGS__)) // Same as YQL_RUNTIME_DISPATCH, but for the new operator. // Example: // // Before: // if (a && b) { // return new Foo(x); // } else if (a) { // return new Foo(x); // } else if (b) { // return new Foo(x); // } else { // return new Foo(x); // } // // After: // return YQL_RUNTIME_DISPATCH_NEW(Base, Foo, 2, a, b, x); #define YQL_RUNTIME_DISPATCH_NEW(returnType, constructor, N, ...) \ (NYql::NPrivate::NRuntimeDispatch::RuntimeDispatch<(N)>(YQL_PRIVATE_WRAP_LAMBDA_FOR_NEW(constructor, returnType), __VA_ARGS__))