Code View

plugin / plugin-2.2.0.0 / src / plugin / PluginRegister.hh
// SPDX-License-Identifier: MIT
#pragma once

#include <plugin/PluginCatalog.hh>

#include <any>
#include <string>

namespace plugin
{
  /**
   * @brief Registers a plugin (default-constructible only) into a PluginCatalog
   * upon construction and unregisters it upon destruction.
   */
  template< class T, class Base >
  class PLUGIN_EXPORT PluginRegisterer
  {
    public:
      PluginRegisterer( typename PluginCatalog< Base >::key_type const& name, bool copy = false )
        : key( name )
      {
        Base::catalog( ).insert( key, Creator< Base >( CreateDefault, copy ) );
      }

      PluginRegisterer( PluginRegisterer&& ) = delete;

      ~PluginRegisterer( )
      {
        Base::catalog( ).erase( key );
      }

      PluginRegisterer& operator=( PluginRegisterer&& ) = delete;

      static Base* CreateDefault( ) { return new T( ); }

    protected:
      PluginRegisterer( ) = default;

      PluginRegisterer( PluginRegisterer const& r )
        : key( r.key )
      {
      }

      PluginRegisterer& operator=( PluginRegisterer const& r )
      {
        if( this != &r )
          key = r.key;
        return *this;
      }

    protected:
      typename PluginCatalog< Base >::key_type key;
  };

  /**
   * @brief Registers a plugin with both default and config-based construction.
   *
   * The Config type is the concrete struct that the plugin's constructor accepts.
   * At creation time, std::any_cast is used to extract the Config — a type
   * mismatch throws std::bad_any_cast at runtime.
   *
   * @tparam T      Concrete plugin class
   * @tparam Base   Base class of the plugin hierarchy
   * @tparam Config Configuration struct accepted by T's constructor
   */
  template< class T, class Base, class Config >
  class PLUGIN_EXPORT PluginRegistererWithConfig
  {
    public:
      PluginRegistererWithConfig( typename PluginCatalog< Base >::key_type const& name,
                                  bool copy = false )
        : key( name )
      {
        Base::catalog( ).insert(
          key,
          Creator< Base >( CreateDefault, CreateFromConfig, copy ) );
      }

      PluginRegistererWithConfig( PluginRegistererWithConfig&& ) = delete;

      ~PluginRegistererWithConfig( )
      {
        Base::catalog( ).erase( key );
      }

      PluginRegistererWithConfig& operator=( PluginRegistererWithConfig&& ) = delete;

      static Base* CreateDefault( ) { return new T( ); }

      static Base* CreateFromConfig( std::any const& cfg )
      {
        return new T( std::any_cast< Config const& >( cfg ) );
      }

    protected:
      PluginRegistererWithConfig( ) = default;

      PluginRegistererWithConfig( PluginRegistererWithConfig const& r )
        : key( r.key )
      {
      }

      PluginRegistererWithConfig& operator=( PluginRegistererWithConfig const& r )
      {
        if( this != &r )
          key = r.key;
        return *this;
      }

    protected:
      typename PluginCatalog< Base >::key_type key;
  };
}  // namespace plugin

// -----------------------------------------------------------------------
// Macros
// -----------------------------------------------------------------------

#define PLUGIN_CONCAT_IMPL( a, b ) a##b
#define PLUGIN_CONCAT( a, b )      PLUGIN_CONCAT_IMPL( a, b )

/// Register with default constructor only (backward compatible)
#define REGISTERBYNAME( NAME, CLASS, BASE )                            \
  namespace                                                            \
  {                                                                    \
    static const volatile plugin::PluginRegisterer< CLASS, BASE >      \
      PLUGIN_CONCAT( REGISTERER_##NAME##_, __LINE__ )( #NAME, false ); \
  }

#define REGISTER( CLASS, BASE ) REGISTERBYNAME( CLASS, CLASS, BASE )

/// Register with both default and config-based construction
#define REGISTERBYNAME_WITH_CONFIG( NAME, CLASS, BASE, CONFIG )                     \
  namespace                                                                         \
  {                                                                                 \
    static const volatile plugin::PluginRegistererWithConfig< CLASS, BASE, CONFIG > \
      PLUGIN_CONCAT( REGISTERER_##NAME##_, __LINE__ )( #NAME, false );              \
  }

#define REGISTER_WITH_CONFIG( CLASS, BASE, CONFIG ) \
  REGISTERBYNAME_WITH_CONFIG( CLASS, CLASS, BASE, CONFIG )

/// Alias registrations
#define REGISTERAS( NAME, CLASS, BASE )                               \
  namespace                                                           \
  {                                                                   \
    static const volatile plugin::PluginRegisterer< CLASS, BASE >     \
      PLUGIN_CONCAT( REGISTERER_##NAME##_, __LINE__ )( #NAME, true ); \
  }

#define REGISTERBYNICK( CNAME, CLASS, BASE )                         \
  namespace                                                          \
  {                                                                  \
    static const volatile plugin::PluginRegisterer< CLASS, BASE >    \
      PLUGIN_CONCAT( REGISTERERNICK_, __LINE__ )( ( CNAME ), true ); \
  }