Skip to content
Snippets Groups Projects
Code owners
Assign users and groups as approvers for specific file changes. Learn more.
UseCasesLib.cpp 14.11 KiB
/***********************************************************************************\
* (c) Copyright 2013-2022 CERN for the benefit of the LHCb and ATLAS collaborations *
*                                                                                   *
* This software is distributed under the terms of the Apache version 2 licence,     *
* copied verbatim in the file "LICENSE".                                            *
*                                                                                   *
* In applying this licence, CERN does not waive the privileges and immunities       *
* granted to it by virtue of its status as an Intergovernmental Organization        *
* or submit itself to any jurisdiction.                                             *
\***********************************************************************************/
/**
 * Compile-time test for all known PluginService use-cases
 *
 * @author Marco Clemencic <marco.clemencic@cern.ch>
 */

#define GAUDI_PLUGIN_SERVICE_V2

#include <Gaudi/PluginService.h>

// standard use, 0 arguments
class Base {
public:
  typedef Gaudi::PluginService::Factory<Base*()> Factory;
  virtual ~Base() {}
};
class Component0 : public Base {};
DECLARE_COMPONENT( Component0 )

class Component1 : public Base {};

#define DECLARE_COMPONENT_WITH_PROPS( type )                                                                           \
  namespace {                                                                                                          \
    ::Gaudi::PluginService::DeclareFactory<type> _INTERNAL_FACTORY_REGISTER_CNAME{ { { "name", #type } } };            \
  }

DECLARE_COMPONENT_WITH_PROPS( Component1 )

// standard use, 2 arguments
class Base2 {
public:
  typedef Gaudi::PluginService::Factory<Base2*( const std::string&, int )> Factory;
  virtual ~Base2() {}
  virtual void abstractMethod() = 0;
};

class Component2 : public Base2 {
public:
  Component2( std::string _s, int _i ) : i( _i ), s( std::move( _s ) ) {}
  void abstractMethod() override {}

  int         i;
  std::string s;
};

DECLARE_COMPONENT( Component2 )

// deprecated
class ObsoleteComponent : public Base {};
DECLARE_COMPONENT( ObsoleteComponent )
DECLARE_COMPONENT_PROPERTY( ObsoleteComponent, "deprecated", "this component is obsolete" )

// namespaces
namespace Test {
  class ComponentA : public Base {};
  class ComponentB : public Base {};
  class ComponentC : public Base {};
  class ComponentD : public Base {};
} // namespace Test
DECLARE_COMPONENT( Test::ComponentA )

namespace {
  using Test::ComponentB;
  DECLARE_COMPONENT( ComponentB )
} // namespace

namespace Test {
  DECLARE_COMPONENT( ComponentC )
}

namespace {
  using TC = Test::ComponentD;
  DECLARE_COMPONENT( TC )
} // namespace

// using ids
DECLARE_COMPONENT_WITH_ID( Component2, "Id2" )
DECLARE_COMPONENT_WITH_ID( Test::ComponentB, "B" )

// explicit factory
DECLARE_FACTORY_WITH_ID( Test::ComponentA, "A", Base::Factory )

// custom factory example
// -- declaration --
struct MyInterface {
  virtual ~MyInterface() = default;

  virtual const std::string& name() const = 0;
};

struct BaseSetupHelper;

struct MyBase : MyInterface {
  using Factory = Gaudi::PluginService::Factory<MyInterface*( const std::string& )>;

  const std::string& name() const override { return m_name; }

private:
  friend BaseSetupHelper;
  std::string m_name;
};

// -- implementation --
struct MyComponent : MyBase {
  MyComponent() {}
};

struct BaseSetupHelper {
  static void setName( MyBase* base, const std::string& name ) { base->m_name = name; }
};

namespace {
  std::unique_ptr<MyInterface> creator( const std::string& name ) {
    auto p = std::make_unique<MyComponent>();
    BaseSetupHelper::setName( p.get(), name );
    return p;
  }
  Gaudi::PluginService::DeclareFactory<MyComponent> _{ creator };
} // namespace

// -- use --
void useComponent() {
  auto c = MyBase::Factory::create( "MyComponent", "TheName" );
  // ...
}

// factory from lambda
namespace SpecialId {
  struct MyComponent : Base {
    MyComponent( std::string n ) : name{ std::move( n ) } {}

    std::string name;
  };
  using namespace Gaudi::PluginService;
  DeclareFactory<MyComponent> __some_random_name( "special-id",
                                                  []() -> MyComponent::Factory::ReturnType {
                                                    return std::make_unique<MyComponent>( "special-id" );
                                                  },
                                                  { { "MyProperty", "special" } } );
} // namespace SpecialId

// customized factory wrapper
namespace CustomFactoryWrapper {
  class Base;

  // helper to initialize base class members
  void initBase( Base*, const std::string& );

  // helper to use the default constructor of T, followed by initialization with initBase
  template <typename T>
  std::enable_if_t<std::is_default_constructible_v<T>, std::unique_ptr<Base>>
  baseConstructorHelper( const std::string& name ) {
    auto p = std::make_unique<T>();
    initBase( p.get(), name );
    return p;
  }

  // helper to use the special constructor of T (backward compatibility)
  template <typename T>
  std::enable_if_t<!std::is_default_constructible_v<T>, std::unique_ptr<Base>>
  baseConstructorHelper( const std::string& name ) {
    return std::make_unique<T>( name );
  }
} // namespace CustomFactoryWrapper

namespace Gaudi {
  namespace PluginService {
    GAUDI_PLUGIN_SERVICE_V2_INLINE namespace v2 {
      namespace Details {
        // custom implementation of DefaultFactory to wrap the call to T constructor
        template <typename T>
        struct DefaultFactory<T, Factory<CustomFactoryWrapper::Base*( const std::string& )>> {
          inline typename Factory<CustomFactoryWrapper::Base*( const std::string& )>::ReturnType
          operator()( const std::string& name ) {
            return CustomFactoryWrapper::baseConstructorHelper<T>( name );
          }
        };
      } // namespace Details
    }
  } // namespace PluginService
} // namespace Gaudi

namespace CustomFactoryWrapper {
  class Base {
    friend void initBase( Base*, const std::string& );
    std::string m_name;

  public:
    using Factory = Gaudi::PluginService::Factory<Base*( const std::string& name )>;

    Base() {}
    Base( const std::string& name ) : m_name{ name } {}

    const std::string& name() const { return m_name; }
  };

  void initBase( Base* b, const std::string& name ) { b->m_name = name; }

  struct ComponentNew : Base {};
  struct ComponentOld : Base {
    ComponentOld( const std::string& name ) : Base{ name } {}
  };
  DECLARE_COMPONENT( ComponentNew )
  DECLARE_COMPONENT( ComponentOld )
} // namespace CustomFactoryWrapper

// ATLAS Custom factories
// see http://acode-browser1.usatlas.bnl.gov/lxr/source/athena/Control/AthenaKernel/AthenaKernel/TPCnvFactory.h
// see http://acode-browser1.usatlas.bnl.gov/lxr/source/athena/Control/AthenaServices/src/test/testConverters.cxx
namespace Athena {
  struct TPCnvVers {
    enum Value { Old = 0, Current = 1 };
  };

  struct TPCnvType {
    enum Value { Athena = 0, ARA = 1, Trigger = 2 };
  };
} // namespace Athena
struct ITPCnvBase {
  typedef Gaudi::PluginService::Factory<ITPCnvBase*()> Factory;
};

#define DO_ATHTPCNV_FACTORY_REGISTER_CNAME( name, serial ) _register_##_##serial

#define DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, cnv_type, signature,  \
                                               serial )                                                                \
  namespace {                                                                                                          \
    struct DO_ATHTPCNV_FACTORY_REGISTER_CNAME( type, serial ) {                                                        \
      DO_ATHTPCNV_FACTORY_REGISTER_CNAME( type, serial )() {                                                           \
        using ::Gaudi::PluginService::DeclareFactory;                                                                  \
        std::string prefix;                                                                                            \
        if ( cnv_type == Athena::TPCnvType::ARA )                                                                      \
          prefix = "_ARA";                                                                                             \
        else if ( cnv_type == Athena::TPCnvType::Trigger )                                                             \
          prefix = "_TRIG";                                                                                            \
        DeclareFactory<type> normal{};                                                                                 \
        if ( is_last_version == Athena::TPCnvVers::Current )                                                           \
          DeclareFactory<type> transient{ prefix + "_TRANS_" + #trans_type };                                          \
        DeclareFactory<type> persistent{ prefix + "_PERS_" + #pers_type };                                             \
      }                                                                                                                \
    } DO_ATHTPCNV_FACTORY_REGISTER_CNAME( s_##type, serial );                                                          \
  }

#define DO_ATHTPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, cnv_type, signature, serial )     \
  DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, ::Gaudi::PluginService::Details::demangle<type>(), trans_type,          \
                                         pers_type, is_last_version, cnv_type, signature, serial )

#define ATHTPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, signature )                          \
  DO_ATHTPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, Athena::TPCnvType::Athena, signature,   \
                                 __LINE__ )
#define ARATPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, signature )                          \
  DO_ATHTPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, Athena::TPCnvType::ARA, signature,      \
                                 __LINE__ )
#define TRIGTPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, signature )                         \
  DO_ATHTPCNV_PLUGINSVC_FACTORY( type, trans_type, pers_type, is_last_version, Athena::TPCnvType::Trigger, signature,  \
                                 __LINE__ )

#define ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, signature )              \
  DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, Athena::TPCnvType::Athena,  \
                                         signature, __LINE__ )
#define ARATPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, signature )              \
  DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, Athena::TPCnvType::ARA,     \
                                         signature, __LINE__ )
#define TRIGTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, signature )             \
  DO_ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( type, id, trans_type, pers_type, is_last_version, Athena::TPCnvType::Trigger, \
                                         signature, __LINE__ )

//********************************************************************
// Macros that users should use.
//

#define DECLARE_TPCNV_FACTORY( x, trans_type, pers_type, is_last_version )                                             \
  ATHTPCNV_PLUGINSVC_FACTORY( x, trans_type, pers_type, is_last_version, ITPCnvBase*() )

#define DECLARE_ARATPCNV_FACTORY( x, trans_type, pers_type, is_last_version )                                          \
  ARATPCNV_PLUGINSVC_FACTORY( x, trans_type, pers_type, is_last_version, ITPCnvBase*() )

#define DECLARE_TRIGTPCNV_FACTORY( x, trans_type, pers_type, is_last_version )                                         \
  TRIGTPCNV_PLUGINSVC_FACTORY( x, trans_type, pers_type, is_last_version, ITPCnvBase*() )

#define DECLARE_NAMED_TPCNV_FACTORY( x, n, trans_type, pers_type, is_last_version )                                    \
  ATHTPCNV_PLUGINSVC_FACTORY_WITH_ID( x, std::string( #n ), trans_type, pers_type, is_last_version, ITPCnvBase*() )

#define DECLARE_NAMED_ARATPCNV_FACTORY( x, n, trans_type, pers_type, is_last_version )                                 \
  ARATPCNV_PLUGINSVC_FACTORY_WITH_ID( x, std::string( #n ), trans_type, pers_type, is_last_version, ITPCnvBase*() )

#define DECLARE_NAMED_TRIGTPCNV_FACTORY( x, n, trans_type, pers_type, is_last_version )                                \
  TRIGTPCNV_PLUGINSVC_FACTORY_WITH_ID( x, std::string( #n ), trans_type, pers_type, is_last_version, ITPCnvBase*() )

namespace AthenaServicesTestConverters {
  class TestConverterBase : public ITPCnvBase {};

  class TestConverter_TA_PA1 : public TestConverterBase {};
  class TestConverter_TA_PA2 : public TestConverterBase {};

  class TestConverter_TB_PB1 : public TestConverterBase {};
  class TestConverter_TB_PB1_ARA : public TestConverterBase {};
  class TestConverter_TBTRIG_PB1 : public TestConverterBase {};

} // namespace AthenaServicesTestConverters

DECLARE_TPCNV_FACTORY( AthenaServicesTestConverters::TestConverter_TA_PA1, AthenaServicesTestConverters::TA,
                       AthenaServicesTestConverters::PA1, Athena::TPCnvVers::Old )
DECLARE_TPCNV_FACTORY( AthenaServicesTestConverters::TestConverter_TA_PA2, AthenaServicesTestConverters::TA,
                       AthenaServicesTestConverters::PA2, Athena::TPCnvVers::Current )

DECLARE_TPCNV_FACTORY( AthenaServicesTestConverters::TestConverter_TB_PB1, AthenaServicesTestConverters::TB,
                       AthenaServicesTestConverters::PB1, Athena::TPCnvVers::Current )
DECLARE_ARATPCNV_FACTORY( AthenaServicesTestConverters::TestConverter_TB_PB1_ARA, AthenaServicesTestConverters::TB,
                          AthenaServicesTestConverters::PB1, Athena::TPCnvVers::Current )
DECLARE_TRIGTPCNV_FACTORY( AthenaServicesTestConverters::TestConverter_TBTRIG_PB1, AthenaServicesTestConverters::TBTRIG,
                           AthenaServicesTestConverters::PB1, Athena::TPCnvVers::Current )