Commit b6a90dd4 authored by Nils Krumnack's avatar Nils Krumnack
Browse files

rework AsgService interface declarations and configuration

As part of implementing my first dual-use service I decided that the
existing macros are not quite as elegant as I hoped, and also don't
match gaudi mechanisms as closely as I would have liked.

I also updated the dual-use service configuration, so that it works
nicely in a dual-use setting.
parent 492e1f73
...@@ -17,8 +17,9 @@ namespace asg ...@@ -17,8 +17,9 @@ namespace asg
class IUnitTestService1 : virtual public IAsgService class IUnitTestService1 : virtual public IAsgService
{ {
// Declare the interface that this class provides /// declare the interface that this class provides
ASG_SERVICE_INTERFACE( CP::IUnitTestService1 ) public:
DeclareInterfaceID( asg::IUnitTestService1, 1, 0 );
/// \brief get the integer property /// \brief get the integer property
public: public:
......
...@@ -33,8 +33,6 @@ namespace asg ...@@ -33,8 +33,6 @@ namespace asg
public: public:
StatusCode initialize () override; StatusCode initialize () override;
ASG_SERVICE_CLASS1 (UnitTestService1, IUnitTestService1)
public: public:
virtual std::string getPropertyString () const override; virtual std::string getPropertyString () const override;
......
...@@ -26,7 +26,7 @@ namespace asg ...@@ -26,7 +26,7 @@ namespace asg
UnitTestService1 (const std::string& name, ISvcLocator* pSvcLocator) UnitTestService1 (const std::string& name, ISvcLocator* pSvcLocator)
: AsgService (name, pSvcLocator) : AsgService (name, pSvcLocator)
{ {
// declareInterface<IUnitTestService1>(); declareServiceInterface<IUnitTestService1>();
declareProperty ("propertyInt", m_propertyInt, "the integer property"); declareProperty ("propertyInt", m_propertyInt, "the integer property");
declareProperty ("propertyString", m_propertyString, "the string property"); declareProperty ("propertyString", m_propertyString, "the string property");
......
...@@ -17,6 +17,8 @@ ...@@ -17,6 +17,8 @@
#include "AthenaBaseComps/AthService.h" #include "AthenaBaseComps/AthService.h"
#endif #endif
#include <vector>
#include <utility>
class ISvcLocator; class ISvcLocator;
...@@ -53,8 +55,31 @@ namespace asg ...@@ -53,8 +55,31 @@ namespace asg
/// Print the state of the service /// Print the state of the service
virtual void print() const; virtual void print() const;
/// add the given interface to the list of interfaces
template<typename T> void declareServiceInterface ();
#ifndef XAOD_STANDALONE
/// query interface for gaudi
virtual StatusCode queryInterface (const InterfaceID& riid, void **ppvi);
/// list of interfaces we have
private:
std::vector<std::pair<const InterfaceID& (*)(),void *(*)(AsgService*)>> m_interfaces;
#endif
}; // class AsgService }; // class AsgService
template<typename T>
void AsgService :: declareServiceInterface ()
{
#ifndef XAOD_STANDALONE
m_interfaces.emplace_back (T::interfaceID, [] (AsgService *self) -> void* {return dynamic_cast<T*>(self);});
#endif
}
} // namespace asg } // namespace asg
#endif // ASGSERVICES_ASGSERVICE_H #endif // ASGSERVICES_ASGSERVICE_H
/*
Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
*/
/// @author Nils Krumnack
/// @author David Adams <dladams@bnl.gov> (for original implementation for tools)
#ifndef AsgServiceMacros_H
#define AsgServiceMacros_H
/// \file CPP macros that turn ASG services into Athena services.
#ifndef XAOD_STANDALONE
// This is used in the body of the service interface class definition, e.g.
// class IMyServiceInterface:
// virtual public IAsgService {
// ASG_SERVICE_INTERFACE(MyServiceInterface)
// .
// .
// .
// };
#define ASG_SERVICE_INTERFACE(CLASSNAME) \
public: \
static const InterfaceID& interfaceID() { \
static const InterfaceID myid(#CLASSNAME, 1, 0 ); \
return myid; \
}
// This is used in the body of the service implementation definition, e.g.
// class MyServiceInterface:
// virtual public IMyServiceInterface, public AsgService {
// ASG_SERVICE_INTERFACE(MyServiceInterface,IMyServiceInterface)
// .
// .
// .
// };
#define ASG_SERVICE_CLASS1(CLASSNAME,INT1) \
public: \
StatusCode queryInterface( const InterfaceID& riid, void** ppvi ) override { \
if ( ppvi == nullptr ) { return StatusCode::FAILURE ; } \
if ( INT1::interfaceID() == riid ) { \
*ppvi = static_cast<INT1*>(this); \
addRef(); \
return StatusCode::SUCCESS;} \
return AthService::queryInterface( riid, ppvi );}
#else
#define ASG_SERVICE_INTERFACE(CLASSNAME)
#define ASG_SERVICE_CLASS1(CLASSNAME,INT1)
#endif
#endif
...@@ -12,9 +12,18 @@ ...@@ -12,9 +12,18 @@
#include <string> #include <string>
// Local include(s): // Local include(s):
#include "AsgServices/AsgServiceMacros.h"
#include "AsgMessaging/INamedInterface.h" #include "AsgMessaging/INamedInterface.h"
#ifdef XAOD_STANDALONE
/// \brief standalone version of the Gaudi interface declaration
///
/// This can't be a no-op, because the Gaudi version needs to be
/// followed by a semicolon, so we need a statement that requires to
/// be followed by a semi-colon.
#define DeclareInterfaceID(iface, major, minor) \
static constexpr nullptr_t interfaceID = nullptr
#endif
namespace asg namespace asg
{ {
/// Base class for the dual-use service interface classes /// Base class for the dual-use service interface classes
......
...@@ -51,4 +51,23 @@ namespace asg ...@@ -51,4 +51,23 @@ namespace asg
return; return;
} }
#ifndef XAOD_STANDALONE
StatusCode AsgService ::
queryInterface (const InterfaceID& riid, void **ppvi)
{
for (const auto& interface : m_interfaces)
{
if (riid == interface.first())
{
*ppvi = interface.second (this);
addRef();
return StatusCode::SUCCESS;
}
}
return AsgServiceBase::queryInterface (riid, ppvi);
}
#endif
} // namespace asg } // namespace asg
...@@ -110,18 +110,23 @@ def createPublicTool( typeName, toolName ): ...@@ -110,18 +110,23 @@ def createPublicTool( typeName, toolName ):
return createComponent( typeName, toolName, 'AsgTool' ) return createComponent( typeName, toolName, 'AsgTool' )
def createService( typeName, serviceName ): def createService( typeName, serviceName, sequence=None ):
"""Helper function for setting up a service for a dual-use algorithm """Helper function for setting up a service for a dual-use algorithm
This function is meant to be used in the analysis algorithm sequence This function is meant to be used to set up services in a dual-use
configurations for setting up services on the analysis algorithms. manner, particularly for the common CP algorithms. This allows to
Services that could then be configured with a syntax shared between use the same syntax in EventLoop and Athena, hiding the
Athena and EventLoop. differences internally. Since in EventLoop the service gets added
to a sequence (but in Athena does not), that sequence needs to be
passed into this function.
Keyword arguments: Keyword arguments:
typeName -- The C++ type name of the service typeName -- The C++ type name of the service
serviceName -- The name with which the service handle was configured on serviceName -- The name with which the service handle was configured on
the algorithm. Also the instance name of the service. the algorithm. Also the instance name of the service.
sequence -- an optional argument of an algorithm sequence to add it to
in EventLoop (ignored in Athena)
""" """
try: try:
...@@ -148,7 +153,11 @@ def createService( typeName, serviceName ): ...@@ -148,7 +153,11 @@ def createService( typeName, serviceName ):
except ImportError: except ImportError:
# If that didn't work, then apparently we're in an EventLoop # If that didn't work, then apparently we're in an EventLoop
# environment, so let's use the EventLoop specific formalism. # environment, so let's use the EventLoop specific formalism.
return createComponent( typeName, serviceName, 'AsgService' ) service = createComponent( typeName, serviceName, 'AsgService' )
if sequence is not None :
sequence += service
pass
return service
def addPrivateTool( alg, toolName, typeName ): def addPrivateTool( alg, toolName, typeName ):
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment