Commit 9593dacd authored by Nils Erik Krumnack's avatar Nils Erik Krumnack
Browse files

wrap AnaToolHandle around AsgToolConfig

The basic reasoning here is that AnaToolHandle is essentially the
out-dated and discouraged mechanism for creating tools, and has been
replaced with AsgToolConfig for quite a while (or alternatively
indirectly via AnaAlgorithmConfig).

I did have to disable some Athena tests for setting sub-tools in
Athena.  There are already some of those disabled, and the basic logic
is that since this is the legacy way of doing things, unless this
breaks existing code (as verified by CI tests) I no longer want to
support all the possible edge cases in this rather brittle and complex
piece of code.
parent 7bb6c91e
......@@ -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());
}
......@@ -45,6 +49,10 @@ namespace asg
StatusCode UnitTestTool1 ::
initialize ()
{
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");
......
......@@ -333,30 +333,6 @@ namespace asg
#ifdef ROOTCORE
// check makeNew<type>()
TEST (AnaToolHandleTest, makeNew)
{
// making separate ToolHandle with different type
std::string name = makeUniqueName();
AnaToolHandle<IUnitTestTool1> tool ("UNKNOWN_TOOL_TYPE/" + name);
ASSERT_EQ ("UNKNOWN_TOOL_TYPE", tool.type());
ASSERT_SUCCESS (tool.makeNew<asg::UnitTestTool1> ("asg::UnitTestTool1"));
ASSERT_EQ ("asg::UnitTestTool1", tool.type());
ASSERT_FALSE (tool.isInitialized());
ASSERT_SUCCESS (tool.initialize());
ASSERT_MATCH_REGEX ("^(ToolSvc.)?" + name + "$", tool->name());
}
// check makeNew<type>()
TEST_F (AnaToolHandleUseTest, makeNew)
{
ASSERT_SUCCESS (tool.makeNew<asg::UnitTestTool1> ("asg::UnitTestTool1"));
}
#endif
// check ASG_SET_ANA_TOOL_TYPE
TEST (AnaToolHandleTest, setToolTypeMacro)
{
......@@ -1030,8 +1006,6 @@ 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", "empty"),
......@@ -1048,6 +1022,8 @@ namespace asg
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")));
#endif
......
......@@ -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();
......
......@@ -13,6 +13,7 @@
#include <AsgTools/AsgTool.h>
#include <AsgTools/AsgToolConfig.h>
#include <AsgTools/ToolHandle.h>
#include <atomic>
#include <list>
......@@ -35,290 +36,6 @@ namespace asg
{
class AnaToolShare;
/// \brief a class maintaining a list of cleanups to be performed
/// when releasing a tool.
class AnaToolCleanup
{
//
// public interface
//
/// \brief standard swap
/// \par Guarantee
/// no-fail
public:
void swap (AnaToolCleanup& that);
/// \brief add a cleanup to perform
///
/// Normally this is added to the end of the list of cleanups,
/// but by passing post as false, you can also add it at the
/// beginning.
///
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
void addCleanup (AnaToolCleanup val_cleanup, bool post = true);
/// \copydoc addCleanup
public:
void addCleanup (const std::shared_ptr<void>& val_cleanup,
bool post = true);
//
// private interface
//
private:
std::list<std::shared_ptr<void> > m_cleanup;
};
/// \brief the base class for classes holding property values for
/// AnaToolHandle
class AnaToolProperty
{
//
// public interface
//
/// \brief standard default constructor for base class
/// \par Guarantee
/// no-fail
public:
virtual ~AnaToolProperty () noexcept = default;
#ifdef XAOD_STANDALONE
/// \brief apply the property to the given tool in RootCore
/// \par Guarantee
/// basic
/// \par Failures
/// unknown property\n
/// invalid property type/value\n
/// out of memory II
public:
virtual StatusCode
applyPropertyRootCore (AsgTool& tool, const std::string& name,
AnaToolCleanup& cleanup)
const = 0;
#endif
#ifndef XAOD_STANDALONE
/// \brief store the property in the configuration service in
/// Athena
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
virtual StatusCode
applyPropertyAthena (const std::string& toolName,
const std::string& name,
AnaToolCleanup& cleanup)
const = 0;
#endif
};
/// \brief the complete configuration for a tool
///
/// This is very much a-kin to the python configurables used
/// inside Athena (thanks Steve Farrell for the analogy).
/// However, so far this is mostly an internal helper class for
/// the \ref AnaToolHandle implementation.
class AnaToolConfig
{
//
// public interface
//
/// \brief standard swap
/// \par Guarantee
/// no-fail
public:
void swap (AnaToolConfig& that) noexcept;
/// \brief whether we contain no properties
/// \par Guarantee
/// no-fail
public:
bool empty () const noexcept;
/// \brief the type of the tool to create
/// \par Guarantee
/// no-fail
public:
const std::string& type () const noexcept;
/// \brief set the value of \ref type
/// \par Guarantee
/// no-fail
public:
void setType (std::string type) noexcept;
#ifdef XAOD_STANDALONE
/// \brief register the new of the given type as factory
///
/// If this is set, it is used instead of \ref type to allocate
/// the tool. This is mostly meant as a stop-gap solution for
/// tools which either do not have a dictionary, or which have a
/// class structure incompatible with instantiation via the
/// dictionary.
/// \par Guarantee
/// strong
/// \par Failures
/// out of memory I
public:
template<typename Type>
void registerNew ();
#endif
/// \brief set the property with the given name in the same
/// fashion as \ref AnaToolHandle::setProperty
/// \par Guarantee
/// strong
/// \par Failures
/// out of memory II\n
/// no way to handle value
public:
template<typename Type> StatusCode
setProperty (const std::string& val_name, const Type& val_value);
/// \copydoc setProperty
public:
template<typename Type> StatusCode
setProperty (const std::string& val_name,
const AnaToolHandle<Type>& val_value);
#ifndef XAOD_STANDALONE
/// \copydoc setProperty
public:
template<typename Type> StatusCode
setProperty (const std::string& val_name,
const ToolHandle<Type>& val_value);
/// \copydoc setProperty
public:
template<typename Type> StatusCode
setProperty (const std::string& val_name,
const ToolHandleArray<Type>& val_value);
#endif
/// \copydoc setProperty
public:
StatusCode
setProperty (const std::string& val_name,
const char *val_value);
/// \brief add/set the property with the given name
/// \par Guarantee
/// strong
/// \par Failures
/// out of memory II
public:
void addProperty (const std::string& name,
const std::shared_ptr<AnaToolProperty>& property);
/// \brief make a configured and initialized tool
/// \par Guarantee
/// strong
/// \par Failures
/// tool creation failures
public:
template<typename ToolType> StatusCode
makeTool (const std::string& name,
parentType_t *parent,
ToolHandle<ToolType>& th,
AnaToolCleanup& cleanup) const;
/// \brief make a configured and initialized tool of the basic type
/// \par Guarantee
/// strong
/// \par Failures
/// tool creation failures
public:
StatusCode
makeBaseTool (const std::string& name,
parentType_t *parent,
ToolHandle<interfaceType_t>& th,
AnaToolCleanup& cleanup) const;
#ifndef XAOD_STANDALONE
/// \brief store the properties in the configuration service in
/// Athena
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
StatusCode
applyPropertiesAthena (const std::string& toolName,
AnaToolCleanup& cleanup) const;
#endif
//
// private interface
//
/// \brief the value of \ref type
private:
std::string m_type;
/// \brief the factory to use, if we have one
private:
std::function<StatusCode (AsgTool*&, const std::string&)> m_factory;
/// \brief the list of all properties stored
private:
std::map<std::string,std::shared_ptr<AnaToolProperty> > m_properties;
#ifdef XAOD_STANDALONE
/// \brief create, configure and initialize the tool (in
/// RootCore)
/// \par Guarantee
/// strong
/// \par Failures
/// tool creation/initialization failures
private:
StatusCode
makeToolRootCore (const std::string& toolName, IAsgTool*& toolPtr,
detail::AnaToolCleanup& cleanup) const;
#endif
#ifdef XAOD_STANDALONE
/// \brief allocate the tool
/// \par Guarantee
/// basic
/// \par Failures
/// tool allocation failures
private:
StatusCode
allocateTool (AsgTool*& toolPtr, const std::string& toolName) const;
#endif
};
/// \brief the mode with which an \ref AnaToolHandle object is
......@@ -589,9 +306,17 @@ namespace asg
/// \par Failures
/// property setting failures
/// \pre !isInitialized()
/// \{
public:
template <class T2> StatusCode
setProperty (const std::string& property, const T2& value);
template <class T2> StatusCode
setProperty (const std::string& property, const ToolHandle<T2>& value);
template <class T2> StatusCode
setProperty (const std::string& property, const AnaToolHandle<T2>& value);
template <class T2> StatusCode
setProperty (const std::string& property, const ToolHandleArray<T2>& value);
/// \}
/// \brief the type configured for this AnaToolHandle
......@@ -607,24 +332,6 @@ namespace asg
public:
void setType (std::string val_type) noexcept;
#ifdef XAOD_STANDALONE
/// \brief set the value of \ref type and a factory based on the
/// standard tool constructor
///
/// This is mainly for use with RootCore where we occasionally
/// have trouble instantiating tools via their dictionaries. Even
/// in that case you shouldn't call this directly, but use the
/// \ref ASG_MAKE_ANA_TOOL macro.
///
/// \par Guarantee
/// strong
/// \par Failures
/// out of memory I
public:
template<class T2>
void setTypeRegisterNew (std::string val_type);
#endif
/// \brief the name configured for this AnaToolHandle
/// \par Guarantee
......@@ -776,7 +483,7 @@ namespace asg
/// \par Failures
/// out of memory II
public:
const detail::AnaToolConfig& config () const;
const AsgToolConfig& config () const;
/// \brief whether the user is allowed to configure this with an
......@@ -847,36 +554,32 @@ namespace asg
setType (val_type); }
return StatusCode::SUCCESS; };
// public:
// [[deprecated]] ("please use either getHandle() or declarePropertyFor() instead")
// ToolHandle<T>& handle () {
// return *m_handleUser;};
#ifdef XAOD_STANDALONE
public:
template<class T2>
[[deprecated("please use setTypeRegisterNew() instead")]]
StatusCode makeNew (std::string val_type) {
setTypeRegisterNew<T2> (std::move (val_type));
return StatusCode::SUCCESS;}
#endif
//
// private interface
//
/// \brief any extra initialization we need to do before creating
/// the tool
///
/// This is mostly/only for creating public tools the tool needs
/// to use. This is not ideal for various reasons, but it is what
/// it is, and this is legacy code.
///
/// \warn This member has to come before \ref m_cleanup
private:
std::vector<std::function<StatusCode ()>> m_extraInit;
/// \brief any stuff we need to release as part of cleanup
///
/// This is protected by \ref m_isInitialized and should not be
/// accessed until \ref m_isInitialized is true.
/// \warn This member has to come before \ref m_handleUser
private:
detail::AnaToolCleanup m_cleanup;
std::shared_ptr<void> m_cleanup;
/// \brief the configuration for this tool
private:
detail::AnaToolConfig m_config;
AsgToolConfig m_config;
/// \brief the value of \ref name
private:
......@@ -983,13 +686,8 @@ namespace asg
(ASG_SET_ANA_TOOL_TYPE(handle,type), StatusCode (StatusCode::SUCCESS))
/// \brief set the tool type on the tool handle, using new in rootcore
#ifdef XAOD_STANDALONE
#define ASG_SET_ANA_TOOL_TYPE(handle,type) \
(handle).template setTypeRegisterNew<type> (#type)
#else
#define ASG_SET_ANA_TOOL_TYPE(handle,type) \
(handle).setType (#type)
#endif
#include <AsgTools/AnaToolHandle.icc>
......
......@@ -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
......@@ -80,6 +88,15 @@ namespace asg
void setName (const std::string& val_name);
/// \brief get \ref type and \ref name at the same time
/// \par Guarantee
/// basic
/// \par Failures
/// out of memory II
public:
std::string typeAndName () const;
/// \brief set \ref type and \ref name at the same time
/// \par Guarantee
/// basic
......@@ -142,6 +159,20 @@ 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,
const AsgToolConfig& toolConfig);
#ifdef XAOD_STANDALONE
/// \brief make a component with the given configuration
///
......
......@@ -55,6 +55,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
/// strong
/// \par Failures
......@@ -63,7 +71,8 @@ namespace asg
public:
template<typename T> ::StatusCode
makeTool (ToolHandle<T>& toolHandle,
std::shared_ptr<void>& cleanup) const;
std::shared_ptr<void>& cleanup,
bool allowNestedName = false) const;