/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * 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 namespace apache::thrift::compiler::detail { /** * A simple reimplementation of thrift's PluggableFunction without using * dependencies banned from the compiler. * * Tag argument must have a static member function `defaultImpl` that is called * when the function is not set. * * Not thread-safe. * * Ex: * struct MyTag { static void defaultImpl(int) {} }; * pluggable_functions().set(+[](int){}); * pluggable_functions().call(42); */ class pluggable_function_set { template using signature = decltype(Tag::defaultImpl); public: template void set(signature* fn) { std::type_index id = typeid(Tag); assert(!funcs.count(id)); funcs[id] = reinterpret_cast(fn); } template std::invoke_result_t, Args...> call(Args&&... args) { return get()(std::forward(args)...); } private: using erased_fn = void (*)(void); std::unordered_map funcs; template signature* get() { std::type_index id = typeid(Tag); if (auto fn = funcs.find(id); fn != funcs.end()) { return reinterpret_cast*>(fn->second); } return Tag::defaultImpl; } }; pluggable_function_set& pluggable_functions(); } // namespace apache::thrift::compiler::detail