// Copyright 2019 The MediaPipe Authors. // // 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. #ifndef MEDIAPIPE_DEPS_REGISTRATION_H_ #define MEDIAPIPE_DEPS_REGISTRATION_H_ #include <algorithm> #include <functional> #include <string> #include <tuple> #include <type_traits> #include <unordered_map> #include <unordered_set> #include <utility> #include "absl/base/macros.h" #include "absl/base/thread_annotations.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/log/absl_check.h" #include "absl/log/absl_log.h" #include "absl/meta/type_traits.h" #include "absl/strings/str_join.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" #include "absl/synchronization/mutex.h" #include "mediapipe/framework/deps/registration_token.h" #include "mediapipe/framework/port/canonical_errors.h" #include "mediapipe/framework/port/statusor.h" namespace mediapipe { // Usage: // // === Defining a registry ================================================ // // class Widget {}; // // using WidgetRegistry = // GlobalFactoryRegistry<unique_ptr<Widget>, // return // unique_ptr<Gadget>, const Thing*> // args // // === Registering an implementation ======================================= // // class MyWidget : public Widget { // static unique_ptr<Widget> Create(unique_ptr<Gadget> arg, // const Thing* thing) { // return MakeUnique<Widget>(std::move(arg), thing); // } // ... // }; // // REGISTER_FACTORY_FUNCTION_QUALIFIED( // WidgetRegistry, widget_registration, // ::my_ns::MyWidget, MyWidget::Create); // // === Using std::function ================================================= // // class Client {}; // // using ClientRegistry = // GlobalFactoryRegistry<absl::StatusOr<unique_ptr<Client>>; // // class MyClient : public Client { // public: // MyClient(unique_ptr<Backend> backend) // : backend_(std::move(backend)) {} // private: // const std::unique_ptr<Backend> backend_; // }; // // // Any std::function that returns a Client is valid to pass here. Below, // // we use a lambda. // REGISTER_FACTORY_FUNCTION_QUALIFIED( // ClientRegistry, client_registration, // ::my_ns::MyClient, // []() { // auto backend = absl::make_unique<Backend>("/path/to/backend"); // const absl::Status status = backend->Init(); // if (!status.ok()) { // return status; // } // std::unique_ptr<Client> client // = absl::make_unique<MyClient>(std::move(backend)); // return client; // }); // // === Using the registry to create instances ============================== // // // Registry will return absl::StatusOr<Object> // absl::StatusOr<unique_ptr<Widget>> s_or_widget = // WidgetRegistry::CreateByName( // "my_ns.MyWidget", std::move(gadget), thing); // // Registry will return NOT_FOUND if the name is unknown. // if (!s_or_widget.ok()) ... // handle error // DoStuffWithWidget(std::move(s_or_widget).value()); // // // It's also possible to find an instance by name within a source namespace. // auto s_or_widget = WidgetRegistry::CreateByNameInNamespace( // "my_ns.sub_namespace", "MyWidget"); // // // It's also possible to just check if a name is registered without creating // // an instance. // bool registered = WidgetRegistry::IsRegistered("my_ns::MyWidget"); // // // It's also possible to iterate through all registered function names. // // This might be useful if clients outside of your codebase are registering // // plugins. // for (const auto& name : WidgetRegistry::GetRegisteredNames()) { // absl::StatusOr<unique_ptr<Widget>> s_or_widget = // WidgetRegistry::CreateByName(name, std::move(gadget), thing); // ... // } // // === Injecting instances for testing ===================================== // // Unregister unregisterer(WidgetRegistry::Register( // "MockWidget", // [](unique_ptr<Gadget> arg, const Thing* thing) { // ... // })); namespace registration_internal { inline constexpr char kCxxSep[] = …; inline constexpr char kNameSep[] = …; template <typename T> struct WrapStatusOr { … }; // Specialization to avoid double-wrapping types that are already StatusOrs. WrapStatusOr<absl::StatusOr<T>>; // Defining a member of this type causes P to be ODR-used, which forces its // instantiation if it's a static member of a template. // Previously we depended on the pointer's value to determine whether the size // of a character array is 0 or 1, forcing it to be instantiated so the // compiler can determine the object's layout. But using it as a template // argument is more compact. template <auto* P> struct ForceStaticInstantiation { … }; } // namespace registration_internal class NamespaceAllowlist { … }; template <typename R, typename... Args> class FunctionRegistry { … }; template <typename R, typename... Args> class GlobalFactoryRegistry { … }; // Two levels of macros are required to convert __LINE__ into a string // containing the line number. #define REGISTRY_STATIC_VAR_INNER(var_name, line) … #define REGISTRY_STATIC_VAR(var_name, line) … // Disables all static registration in MediaPipe accomplished using: // - REGISTER_FACTORY_FUNCTION_QUALIFIED // - MEDIAPIPE_REGISTER_FACTORY_FUNCTION // - MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE // // Which includes: // - calculators // - input stream handlers // - output stream handlers // - generators // - anything else registered using above macros #if !defined(MEDIAPIPE_DISABLE_STATIC_REGISTRATION) #define MEDIAPIPE_DISABLE_STATIC_REGISTRATION … #endif // !defined(MEDIAPIPE_DISABLE_STATIC_REGISTRATION) // Enables "Dry Run" for MediaPipe static registration: MediaPipe logs the // registration code, instead of actual registration. // // The intended use: if you plan to disable static registration using // MEDIAPIPE_DISABLE_STATIC_REGISTRATION, you may find it useful to build your // MediaPipe dependency first with only: // MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN // and load it to see what manual registration will be required when you build // with: // MEDIAPIPE_DISABLE_STATIC_REGISTRATION #if !defined(MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN) #define MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN … #endif // !defined(MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN) #if MEDIAPIPE_DISABLE_STATIC_REGISTRATION && \ MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN static_assert(false, "Cannot do static registration Dry Run as static registration is " "disabled."); #endif // MEDIAPIPE_DISABLE_STATIC_REGISTRATION && // MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN #if MEDIAPIPE_DISABLE_STATIC_REGISTRATION // When static registration is disabled, make sure corresponding macros don't do // any registration. #define MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED … #define MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE … #elif MEDIAPIPE_ENABLE_STATIC_REGISTRATION_DRY_RUN // When static registration is enabled and running in Dry-Run mode, make sure // corresponding macros print registration details instead of doing actual // registration. #define INTERNAL_MEDIAPIPE_REGISTER_FACTORY_STRINGIFY_HELPER … #define INTERNAL_MEDIAPIPE_REGISTER_FACTORY_STRINGIFY … #define MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED … #define MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE … #else // When static registration is enabled and NOT running in Dry-Run mode, make // sure corresponding macros do proper static registration. #define MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED(RegistryType, var_name, \ name, ...) … // Defines a utility registrator class which can be used to automatically // register factory functions. // // Example: // === Defining a registry ================================================ // // class Component {}; // // using ComponentRegistry = GlobalFactoryRegistry<std::unique_ptr<Component>>; // // === Defining a registrator ============================================= // // MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE(ComponentRegistrator, // ComponentRegistry, T::kName, // absl::make_unique<T>); // // === Defining and registering a new component. ========================== // // class MyComponent : public Component, // private ComponentRegistrator<MyComponent> { // public: // static constexpr char kName[] = "MyComponent"; // ... // }; // // NOTE: // - MyComponent is automatically registered in ComponentRegistry by // "MyComponent" name. // - Every component is require to provide its name (T::kName here.) #define MEDIAPIPE_STATIC_REGISTRATOR_TEMPLATE(RegistratorName, RegistryType, \ name, ...) … #endif // MEDIAPIPE_DISABLE_STATIC_REGISTRATION #define MEDIAPIPE_REGISTER_FACTORY_FUNCTION(RegistryType, name, ...) … // TODO: migrate usages to use // MEDIAPIPE_REGISTER_FACTORY_FUNCTION_QUALIFIED. #define REGISTER_FACTORY_FUNCTION_QUALIFIED(RegistryType, var_name, name, ...) … } // namespace mediapipe #endif // MEDIAPIPE_DEPS_REGISTRATION_H_