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
class IUnitTestService1 : virtual public IAsgService
{
// Declare the interface that this class provides
ASG_SERVICE_INTERFACE( CP::IUnitTestService1 )
/// declare the interface that this class provides
public:
DeclareInterfaceID( asg::IUnitTestService1, 1, 0 );
/// \brief get the integer property
public:
......
......@@ -33,8 +33,6 @@ namespace asg
public:
StatusCode initialize () override;
ASG_SERVICE_CLASS1 (UnitTestService1, IUnitTestService1)
public:
virtual std::string getPropertyString () const override;
......
......@@ -26,7 +26,7 @@ namespace asg
UnitTestService1 (const std::string& name, ISvcLocator* pSvcLocator)
: AsgService (name, pSvcLocator)
{
// declareInterface<IUnitTestService1>();
declareServiceInterface<IUnitTestService1>();
declareProperty ("propertyInt", m_propertyInt, "the integer property");
declareProperty ("propertyString", m_propertyString, "the string property");
......
......@@ -17,6 +17,8 @@
#include "AthenaBaseComps/AthService.h"
#endif
#include <vector>
#include <utility>
class ISvcLocator;
......@@ -53,8 +55,31 @@ namespace asg
/// Print the state of the service
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
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
#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 @@
#include <string>
// Local include(s):
#include "AsgServices/AsgServiceMacros.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
{
/// Base class for the dual-use service interface classes
......
......@@ -51,4 +51,23 @@ namespace asg
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
......@@ -110,18 +110,23 @@ def createPublicTool( typeName, toolName ):
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
This function is meant to be used in the analysis algorithm sequence
configurations for setting up services on the analysis algorithms.
Services that could then be configured with a syntax shared between
Athena and EventLoop.
This function is meant to be used to set up services in a dual-use
manner, particularly for the common CP algorithms. This allows to
use the same syntax in EventLoop and Athena, hiding the
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:
typeName -- The C++ type name of the service
serviceName -- The name with which the service handle was configured on
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:
......@@ -148,7 +153,11 @@ def createService( typeName, serviceName ):
except ImportError:
# If that didn't work, then apparently we're in an EventLoop
# 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 ):
......
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