Commit 80c10ddd authored by Nils Erik Krumnack's avatar Nils Erik Krumnack
Browse files

Merge branch 'cherry_17Jun21' into '21.2'

sweep updates to central AnalysisBase packages from master to 21.2

See merge request !44538
parents c013bfd8 24d2290b
......@@ -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:
......
......@@ -10,6 +10,7 @@
#define ASG_TOOLS__I_UNIT_TEST_TOOL2_H
#include <AsgTools/IAsgTool.h>
#include <AsgTools/ToolHandleArray.h>
namespace asg
{
......@@ -41,6 +42,11 @@ namespace asg
public:
virtual bool
wasUserConfigured (const std::string& handleName) const = 0;
/// \brief get the tool handle array
public:
virtual const ToolHandleArray<IUnitTestTool1>&
getArray () const = 0;
};
}
......
......@@ -33,8 +33,6 @@ namespace asg
public:
StatusCode initialize () override;
ASG_SERVICE_CLASS1 (UnitTestService1, IUnitTestService1)
public:
virtual std::string getPropertyString () const override;
......
......@@ -48,6 +48,10 @@ namespace asg
virtual bool
wasUserConfigured (const std::string& handleName) const override;
public:
virtual const ToolHandleArray<IUnitTestTool1>&
getArray () const override;
public:
ToolHandle<IUnitTestTool1> m_regPublicHandle;
......@@ -60,6 +64,9 @@ namespace asg
public:
AnaToolHandle<IUnitTestTool1> m_anaPrivateHandle;
public:
ToolHandleArray<IUnitTestTool1> m_regPrivateArray {this};
private:
bool m_wasUserConfiguredPublic = false;
......
......@@ -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");
......
......@@ -30,6 +30,8 @@ namespace asg
declareProperty ("initializeFail", m_initializeFail, "whether initialize should fail");
++ instance_counts (name());
ANA_MSG_INFO ("create UnitTestTool1 " << this);
}
......@@ -37,6 +39,8 @@ namespace asg
UnitTestTool1 ::
~UnitTestTool1 ()
{
ANA_MSG_INFO ("destroy UnitTestTool1 " << this);
-- instance_counts (name());
}
......@@ -46,6 +50,11 @@ namespace asg
initialize ()
{
m_origMsgLevel = msg().level();
ANA_MSG_INFO ("initialize UnitTestTool1 " << this);
ANA_MSG_INFO (" propertyString: " << m_propertyString);
ANA_MSG_INFO (" propertyInt: " << m_propertyInt);
if (m_initializeFail)
{
ATH_MSG_ERROR ("tool configured to fail initialize");
......
......@@ -29,6 +29,7 @@ namespace asg
m_anaPrivateHandle ("asg::UnitTestTool1/anaPrivateHandle", this)
{
declareProperty ("allowEmpty", m_allowEmpty);
declareProperty ("regPrivateArray", m_regPrivateArray, "array of private tools");
declareProperty ("regPublicHandle", m_regPublicHandle);
declareProperty ("regPrivateHandle", m_regPrivateHandle);
......@@ -52,6 +53,9 @@ namespace asg
ANA_CHECK (m_anaPrivateHandle.setProperty ("propertyInt", 222));
ANA_CHECK (m_anaPrivateHandle.initialize ());
for (auto& handle : m_regPrivateArray)
ANA_CHECK (handle.retrieve());
return StatusCode::SUCCESS;
}
......@@ -110,4 +114,12 @@ namespace asg
return m_wasUserConfiguredPrivate;
throw std::runtime_error ("unknown handle: " + handleName);
}
const ToolHandleArray<IUnitTestTool1>& UnitTestTool2 ::
getArray () const
{
return m_regPrivateArray;
}
}
......@@ -1067,14 +1067,14 @@ namespace asg
std::make_tuple ("anaPublicHandle", "public", "ATH"),
std::make_tuple ("regPublicHandle", "public", "TH"),
std::make_tuple ("anaPublicHandle", "public", "TH"),
std::make_tuple ("regPublicHandle", "public", "NOINIT"),
std::make_tuple ("anaPublicHandle", "public", "NOINIT"),
std::make_tuple ("regPublicHandle", "public", "empty"),
std::make_tuple ("anaPublicHandle", "public", "empty"),
std::make_tuple ("regPrivateHandle", "private", "ATH"),
std::make_tuple ("anaPrivateHandle", "private", "ATH"),
std::make_tuple ("regPrivateHandle", "private", "TH"),
std::make_tuple ("anaPrivateHandle", "private", "TH"),
std::make_tuple ("regPublicHandle", "public", "NOINIT"),
std::make_tuple ("anaPublicHandle", "public", "NOINIT"),
std::make_tuple ("regPrivateHandle", "private", "NOINIT"),
std::make_tuple ("anaPrivateHandle", "private", "NOINIT"),
std::make_tuple ("regPrivateHandle", "private", "empty"),
......
......@@ -141,6 +141,34 @@ namespace asg
TEST (AsgToolConfigTest, basic_subtoolConfigureIndirect)
{
const std::string name = makeUniqueName();
AsgToolConfig config ("asg::UnitTestTool2/" + name);
{
AsgToolConfig subconfig ("asg::UnitTestTool1A");
subconfig.setPropertyFromString ("propertyInt", "17");
ASSERT_SUCCESS (config.addPrivateTool ("regPrivateHandle", subconfig));
}
{
AsgToolConfig subconfig ("asg::UnitTestTool1A");
subconfig.setPropertyFromString ("propertyInt", "42");
ASSERT_SUCCESS (config.addPrivateTool ("anaPrivateHandle", subconfig));
}
std::shared_ptr<void> cleanup;
ToolHandle<IUnitTestTool2> tool;
ASSERT_SUCCESS (config.makeTool (tool, cleanup));
EXPECT_EQ ("ToolSvc." + name, tool->name());
EXPECT_SUCCESS (tool->retrieveToolHandle("regPrivateHandle"));
EXPECT_TRUE (tool->getToolHandle ("regPrivateHandle")->isInitialized());
EXPECT_EQ (17, tool->getToolHandle ("regPrivateHandle")->getPropertyInt());
EXPECT_TRUE (tool->wasUserConfigured("anaPrivateHandle"));
EXPECT_TRUE (tool->getToolHandle ("anaPrivateHandle")->isInitialized());
EXPECT_EQ (42, tool->getToolHandle ("anaPrivateHandle")->getPropertyInt());
}
TEST (AsgToolConfigTest, privateTool)
{
const std::string name1 = makeUniqueName();
......@@ -173,6 +201,47 @@ namespace asg
ASSERT_SUCCESS (config2.makePrivateTool (tool2));
EXPECT_EQ ("ToolSvc." + name1 + ".myPrivateTool", tool2->name());
}
TEST (AsgToolConfigTest, emptyArray)
{
const std::string name = makeUniqueName();
AsgToolConfig mainConfig ("asg::UnitTestTool2/" + name);
std::shared_ptr<void> cleanup;
ToolHandle<IUnitTestTool2> tool;
ASSERT_SUCCESS (mainConfig.makeTool (tool, cleanup));
EXPECT_EQ ("ToolSvc." + name, tool->name());
ASSERT_EQ (0u, tool->getArray().size());
}
TEST (AsgToolConfigTest, fillArray)
{
const std::string name = makeUniqueName();
AsgToolConfig mainConfig ("asg::UnitTestTool2/" + name);
{
auto subtool = mainConfig.createPrivateToolInArray ("regPrivateArray", "asg::UnitTestTool1");
ANA_MSG_INFO ("subtool = " << subtool);
ASSERT_SUCCESS (mainConfig.setProperty (subtool + ".propertyInt", 19));
}
{
AsgToolConfig subconfig ("asg::UnitTestTool1");
ANA_CHECK_THROW (subconfig.setProperty ("propertyInt", 22));
auto subtool = mainConfig.addPrivateToolInArray ("regPrivateArray", subconfig);
ANA_MSG_INFO ("subtool = " << subtool);
}
std::shared_ptr<void> cleanup;
ToolHandle<IUnitTestTool2> tool;
ASSERT_SUCCESS (mainConfig.makeTool (tool, cleanup));
EXPECT_EQ ("ToolSvc." + name, tool->name());
ASSERT_EQ (2u, tool->getArray().size());
EXPECT_EQ (19, tool->getArray()[0]->getPropertyInt());
EXPECT_EQ (22, tool->getArray()[1]->getPropertyInt());
}
}
ATLAS_GOOGLE_TEST_MAIN
......@@ -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
......@@ -45,6 +45,15 @@ namespace asg
explicit AsgServiceConfig (const std::string& val_typeAndName);
/// \brief initializing constructor
/// \par Guarantee
/// strong
/// \par Failures
/// out of memory II
public:
explicit AsgServiceConfig (const AsgComponentConfig& val_config);
/// \brief Virtual destructor, to make PyROOT happy
///
/// Without it ROOT 6.22+ does not allow Python classes to inherit from this
......
/*
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
......
......@@ -39,7 +39,7 @@ ServiceHandle<T> ::
ServiceHandle (T2 *parent, const std::string& propertyName,
const std::string& serviceName,
const std::string& propertyTitle)
: ServiceHandle (serviceName, parent)
: ServiceHandle (serviceName, parent->name())
{
parent->declareProperty (propertyName, *this, propertyTitle);
}
......
......@@ -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
......@@ -25,4 +25,11 @@ namespace asg
AsgServiceConfig (const std::string& val_typeAndName)
: AsgComponentConfig (val_typeAndName)
{}
AsgServiceConfig ::
AsgServiceConfig (const AsgComponentConfig& val_config)
: AsgComponentConfig (val_config)
{}
}
/*
Copyright (C) 2002-2020 CERN for the benefit of the ATLAS collaboration
Copyright (C) 2002-2021 CERN for the benefit of the ATLAS collaboration
*/
/// \author Nils Krumnack
......@@ -7,7 +7,7 @@
#ifndef ASGTOOLS_ASGCOMPONENT_H
#define ASGTOOLS_ASGCOMPONENT_H
#ifndef XAOD_STANDALONE
#if !defined(XAOD_STANDALONE) && !defined(__CPPCHECK__)
#error "This header should only be used in XAOD_STANDALONE"
#else
......
......@@ -19,6 +19,7 @@ class StatusCode;
namespace asg
{
class AsgComponent;
class AsgToolConfig;
}
namespace asg
......@@ -50,6 +51,13 @@ namespace asg
explicit AsgComponentConfig (const std::string& val_typeAndName);
/// \brief whether all properties are unset
/// \par Guarantee
/// no-fail
public:
bool empty () const noexcept;
/// \brief the type of the component
/// \par Guarantee
/// no-fail
......@@ -151,6 +159,48 @@ namespace asg
const std::string& toolType);
/// \brief add a private tool from the given configuration
///
/// This will ignore the name set in `toolConfig` and use whatever
/// `name` is given instead.
///
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
StatusCode addPrivateTool (const std::string& name,
AsgToolConfig toolConfig);
/// \brief the array version of \ref createPrivateTool
///
/// This returns the actual name of the tool to allow setting
/// properties on it.
///
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
std::string createPrivateToolInArray (const std::string& name,
const std::string& toolType);
/// \brief the array version of \ref addPrivateTool
///
/// This will ignore the name set in `toolConfig` and use whatever
/// `name` is given instead.
///
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
std::string addPrivateToolInArray (const std::string& name,
AsgToolConfig toolConfig);
#ifdef XAOD_STANDALONE
/// \brief make a component with the given configuration
///
......@@ -215,20 +265,22 @@ namespace asg
// private interface
//
/// \brief the value of \ref type
private:
/// \brief the value of \ref type
std::string m_type;
/// \brief the value of \ref name
private:
std::string m_name;
/// \brief the map of private tools to create
private:
std::map<std::string,std::string> m_privateTools;
/// \brief the map of (private) tools to create
std::map<std::string,std::tuple<AsgToolConfig,std::string>> m_privateTools;
/// \brief the map of (private) tool handle arrays to manage, and
/// the tools they contain
std::map<std::string,std::vector<std::string>> m_toolArrays;
/// \brief the map of property values
private:
std::map<std::string,std::string> m_propertyValues;
......@@ -237,11 +289,29 @@ namespace asg
/// strong
/// \par Failures
/// type or name doesn't have proper format
private:
StatusCode checkTypeName (bool nestedNames) const;
/// \brief access the configuration for the given subtool
/// \par Guarantee
/// strong
/// \par Failures
/// unknown subtool
/// \{
struct AccessSubtoolData final
{
AsgToolConfig *config {nullptr};
std::string prefix;
std::string name;
};
AccessSubtoolData accessSubtool (const std::string& name,
std::size_t split);
/// \}
};
}
#include "AsgComponentConfig.icc"
#include <AsgTools/AsgToolConfig.h>
#endif
......@@ -42,6 +42,15 @@ namespace asg
explicit AsgToolConfig (const std::string& val_typeAndName);
/// \brief initializing constructor
/// \par Guarantee
/// strong
/// \par Failures
/// out of memory II
public:
explicit AsgToolConfig (const AsgComponentConfig& val_config);
/// \brief make a tool with the given configuration
///
/// Note that the exact creational patterns are not determined yet
......@@ -55,6 +64,14 @@ namespace asg
/// updated to at the very least work on a ToolHandle, but so far
/// this code isn't even dual-use.
///
/// The argument `allowNestedName` should probably be omitted in
/// most cases. I mostly added it to allow AnaToolHandle to
/// create new tools via an AsgToolConfig (06 Jan 21), for which a
/// number of existing users rely on making nested names. Usually
/// when you want a nested name you ought to set the parent on the
/// `ToolHandle` and then use a non-nested name for the name of
/// the config.
///
/// \par Guarantee
/// basic
/// \par Failures
......@@ -63,7 +80,8 @@ namespace asg
public:
template<typename T> ::StatusCode