chromium/third_party/mediapipe/src/mediapipe/framework/deps/registration.h

// 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_