From 98086d895dc13efcf0509bd2c00b5e264b407e2c Mon Sep 17 00:00:00 2001 From: Gerhard Raven <gerhard.raven@nikhef.nl> Date: Fri, 6 Jan 2023 11:38:25 +0100 Subject: [PATCH] Consolidate Linker code - add functionality to LHCb::LinksByKey (link, typed constructor), make it impossible to change sourceID, targetID, ordering _after_ construction (as that would leave any already present data in a bad shape) - drop the no longer relevant OutputLinks class - drop the unused AllLinks header - drop the no longer releavent LinkedFromKey class - move LinkerEntry and LinkerRange into LinkerTable as they are implementation details of iterating over the table - add warning counter which keeps track of how often Object2MCLinker invokes an algorithm to build a linker table - unify 'range' function names, make the inverse range in Object2MCLinker lazy - reduce code in LinkerTool using the new functionality in LinksByKey - reduce code in LinkerWithKey using the new functionality in LinksByKey - remove confusing (and buggy?) Object2MCLinker::linkerTable method --- .../include/Associators/Associators.h | 1 - .../include/Associators/Detail/Mixin.h | 11 +- .../include/Associators/InputLinks.h | 11 +- .../include/Associators/OutputLinks.h | 66 ------ .../include/Kernel/Particle2MCLinker.h | 87 +++++--- .../include/Kernel/Particle2MCLinker.icpp | 42 +--- .../include/CaloFutureUtils/CaloFuture2MC.h | 8 - Event/LinkerEvent/include/Event/LinksByKey.h | 86 +++++--- Event/LinkerEvent/include/Linker/AllLinks.h | 128 ------------ Event/LinkerEvent/include/Linker/LinkedFrom.h | 14 +- .../include/Linker/LinkedFromKey.h | 27 --- .../LinkerEvent/include/Linker/LinkerEntry.h | 54 ----- .../LinkerEvent/include/Linker/LinkerRange.h | 81 -------- .../LinkerEvent/include/Linker/LinkerTable.h | 193 +++++++++++------- Event/LinkerEvent/include/Linker/LinkerTool.h | 97 ++------- .../include/Linker/LinkerWithKey.h | 89 +++----- Event/LinkerEvent/src/LinksByKey.cpp | 6 +- 17 files changed, 317 insertions(+), 684 deletions(-) delete mode 100644 Associators/AssociatorsBase/include/Associators/OutputLinks.h delete mode 100644 Event/LinkerEvent/include/Linker/AllLinks.h delete mode 100644 Event/LinkerEvent/include/Linker/LinkedFromKey.h delete mode 100644 Event/LinkerEvent/include/Linker/LinkerEntry.h delete mode 100644 Event/LinkerEvent/include/Linker/LinkerRange.h diff --git a/Associators/AssociatorsBase/include/Associators/Associators.h b/Associators/AssociatorsBase/include/Associators/Associators.h index c70ddfdbf6e..ab20c3f1e31 100644 --- a/Associators/AssociatorsBase/include/Associators/Associators.h +++ b/Associators/AssociatorsBase/include/Associators/Associators.h @@ -10,4 +10,3 @@ \*****************************************************************************/ #include "InputLinks.h" #include "Location.h" -#include "OutputLinks.h" diff --git a/Associators/AssociatorsBase/include/Associators/Detail/Mixin.h b/Associators/AssociatorsBase/include/Associators/Detail/Mixin.h index 2bc7fa4b9ae..ccc2eb3289f 100644 --- a/Associators/AssociatorsBase/include/Associators/Detail/Mixin.h +++ b/Associators/AssociatorsBase/include/Associators/Detail/Mixin.h @@ -15,7 +15,6 @@ #include <GaudiKernel/LinkManager.h> #include <Associators/InputLinks.h> -#include <Associators/OutputLinks.h> namespace { struct DefaultType {}; @@ -52,8 +51,9 @@ namespace Detail { // ContainedObject and the specified type, respectively. template <typename Src, typename Target = DefaultType, typename std::enable_if_t<std::is_same<DefaultType, Target>::value>* = nullptr> - OutputLinks<Source, Src> outputLinks() const { - return OutputLinks<Source, Src>{}; + auto outputLinks() const { + return LHCb::LinksByKey{std::in_place_type<Source>, std::in_place_type<Src>, + LHCb::LinksByKey::Order::decreasingWeight}; } // Bit of a trick here with enable if: if Target is specified, so @@ -62,8 +62,9 @@ namespace Detail { // types. template <typename Src, typename Target = DefaultType, typename std::enable_if_t<!std::is_same<DefaultType, Target>::value>* = nullptr> - OutputLinks<Src, Target> outputLinks() const { - return OutputLinks<Src, Target>{}; + auto outputLinks() const { + return LHCb::LinksByKey{std::in_place_type<Src>, std::in_place_type<Target>, + LHCb::LinksByKey::Order::decreasingWeight}; } }; diff --git a/Associators/AssociatorsBase/include/Associators/InputLinks.h b/Associators/AssociatorsBase/include/Associators/InputLinks.h index 68a127d6c17..1b1de8353fe 100644 --- a/Associators/AssociatorsBase/include/Associators/InputLinks.h +++ b/Associators/AssociatorsBase/include/Associators/InputLinks.h @@ -11,17 +11,13 @@ #ifndef ASSOCIATORS_INPUTLINKS_H #define ASSOCIATORS_INPUTLINKS_H -#include <iostream> -#include <type_traits> - #include <Event/LinksByKey.h> #include <GaudiKernel/GaudiException.h> #include <GaudiKernel/IRegistry.h> #include <GaudiKernel/LinkManager.h> #include <Relations/RelationWeighted2D.h> - -// template <class Source, class Targed, class Enabled = void> -// class InputLinks {}; +#include <iostream> +#include <type_traits> namespace { @@ -99,8 +95,7 @@ public: }; typename LHCb::RelationWeighted2D<unsigned int, Target, double>::Range from( unsigned int key ) const { - auto range = m_keyRelations.relations( key ); - return range; + return m_keyRelations.relations( key ); } typename LHCb::RelationWeighted2D<Source, Target, double>::Range from( const Source* source ) const { diff --git a/Associators/AssociatorsBase/include/Associators/OutputLinks.h b/Associators/AssociatorsBase/include/Associators/OutputLinks.h deleted file mode 100644 index a8f12e4c183..00000000000 --- a/Associators/AssociatorsBase/include/Associators/OutputLinks.h +++ /dev/null @@ -1,66 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* 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. * -\*****************************************************************************/ -#ifndef ASSOCIATORS_OUTPUTLINKS_H -#define ASSOCIATORS_OUTPUTLINKS_H - -#include <Event/LinksByKey.h> - -#include <GaudiKernel/LinkManager.h> - -template <typename Source, typename Target> -class OutputLinks final { -public: - OutputLinks() { - m_links.setTargetClassID( Target::classID() ); - m_links.setSourceClassID( Source::classID() ); - } - - operator LHCb::LinksByKey() { - // This is horrible, but needed because the copy constructor of - // DataObject creates a new (and empty) LinkManager. The - // existing move constructor moves the linkmanager, which would - // work, expect the using auto conversion twice would result in - // undefined behaviour. So, create a copy, insert all the links - // it's and then return it. - LHCb::LinksByKey r{m_links}; - for ( long linkID = 0; linkID != m_links.linkMgr()->size(); ++linkID ) { - auto link = m_links.linkMgr()->link( linkID ); - r.linkMgr()->addLink( link->path(), link->object() ); - } - return r; - } - - const LHCb::LinksByKey& links() const { return m_links; } - LHCb::LinksByKey& links() { return m_links; } - - void reset() { m_links.reset(); } - - void link( const Source* source, const Target* dest, double weight = 1. ) { - if ( !source || !dest ) return; - - m_links.addReference( source->index(), m_links.linkID( source->parent() ), dest->index(), - m_links.linkID( dest->parent() ), weight ); - } - - void link( int key, const Target* dest, double weight = 1. ) { - if ( !dest ) return; - - m_links.addReference( key, -1, dest->index(), m_links.linkID( dest->parent() ), weight ); - } - - void setIncreasingWeight() { m_links.setIncreasing(); } - void setDecreasingWeight() { m_links.setDecreasing(); } - -private: - LHCb::LinksByKey m_links; -}; - -#endif diff --git a/Associators/MCAssociators/include/Kernel/Particle2MCLinker.h b/Associators/MCAssociators/include/Kernel/Particle2MCLinker.h index 160dbda6a1c..066aac5ae74 100644 --- a/Associators/MCAssociators/include/Kernel/Particle2MCLinker.h +++ b/Associators/MCAssociators/include/Kernel/Particle2MCLinker.h @@ -25,7 +25,6 @@ #include "GaudiKernel/IAlgManager.h" #include "GaudiKernel/IRegistry.h" #include "GaudiKernel/KeyedObject.h" -#include "GaudiKernel/compose.h" /** * Class providing association functionality to MCParticles @@ -35,7 +34,7 @@ * @author Philippe Charpentier * @date 2004-04-29 */ -template <typename SOURCE = LHCb::Particle, typename PARENT = GaudiAlgorithm> +template <typename SOURCE, typename PARENT = GaudiAlgorithm> class Object2MCLinker { // Typedef for RangeFrom return type using ToRange = @@ -51,10 +50,9 @@ public: : m_parent( myMother ) , m_extension( extension ) , m_linkerAlgType( algType ) - , m_containerList( std::move( containerList ) ) - , m_linkerTable( myMother->evtSvc(), nullptr, "" ) {} + , m_containerList( std::move( containerList ) ) {} - Object2MCLinker( const PARENT* myMother ) : m_parent( myMother ), m_linkerTable( myMother->evtSvc(), nullptr, "" ) {} + Object2MCLinker( const PARENT* myMother ) : m_parent( myMother ) {} Object2MCLinker( const PARENT* myMother, const int method, std::vector<std::string> containerList ) : Object2MCLinker( myMother, Particle2MCMethod::algType[method], Particle2MCMethod::extension[method], @@ -92,14 +90,11 @@ public: return std::distance( r.begin(), r.end() ); } - bool notFound(); bool checkAssociation( const SOURCE* obj, const LHCb::MCParticle* mcPart ); using Linker = LinkerWithKey<LHCb::MCParticle, SOURCE>; - Linker* linkerTable( const std::string& name ); private: - Linker* linkerTable( const std::string& name, LinkedTo<LHCb::MCParticle> test ); const std::string& name() const { return m_parent->name(); } const std::string& context() const { return m_parent->context(); } @@ -140,9 +135,10 @@ private: mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_setInputErr{m_parent, "Unable to set Property InputData", 10}; mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_setRITErr{m_parent, "Unable to set Property RootInTES", 10}; mutable Gaudi::Accumulators::MsgCounter<MSG::WARNING> m_ipropWarn{m_parent, "Unable to get IProperty pointer", 10}; + mutable Gaudi::Accumulators::MsgCounter<MSG::WARNING> m_executing_linker_builder_algo{ + m_parent, "Explicitly Executing Linker Building algorithm", 0}; LHCb::LinksByKey const* m_links = nullptr; - Linker m_linkerTable; // Private methods protected: @@ -151,17 +147,16 @@ protected: void createLinks( const std::string& contName ); private: - StatusCode locateAlgorithm( const std::string& algType, const std::string& algName, IAlgorithm*& alg, - const std::vector<std::string>& inputData ); - std::string getGaudiRootInTES(); - StatusCode setAlgInputData( IAlgorithm*& alg, const std::vector<std::string>& inputData ); + StatusCode locateAlgorithm( const std::string& algType, const std::string& algName, IAlgorithm*& alg, + const std::vector<std::string>& inputData ); + StatusCode setAlgInputData( IAlgorithm*& alg, const std::vector<std::string>& inputData ); - inline std::string containerName( const ContainedObject* obj ) const { + std::string containerName( const ContainedObject* obj ) const { return ( obj->parent() && obj->parent()->registry() ) ? obj->parent()->registry()->identifier() : std::string{}; } }; -template <typename OBJ2MCP = LHCb::Particle, typename PARENT = GaudiAlgorithm> +template <typename OBJ2MCP, typename PARENT = GaudiAlgorithm> class Object2FromMC : public Object2MCLinker<OBJ2MCP, PARENT> { std::vector<LHCb::LinksByKey const*> m_linkerList; @@ -173,9 +168,7 @@ public: if ( !this->hasValidParent() || this->m_linkerAlgType.empty() ) return; m_linkerList.reserve( this->m_containerList.size() ); for ( const auto& cont : this->m_containerList ) { - const std::string containerName = cont + this->m_extension; - const std::string name = - "Link/" + ( "/Event/" == containerName.substr( 0, 7 ) ? containerName.substr( 7 ) : containerName ); + const std::string name = LHCb::LinksByKey::linkerName( cont + this->m_extension ); this->debug() << "trying to retrieve " << name << endmsg; SmartDataPtr<LHCb::LinksByKey> links( this->evtSvc(), name ); if ( !links ) { @@ -192,15 +185,59 @@ public: const OBJ2MCP* part = dynamic_cast<const OBJ2MCP*>( obj ); if ( part ) return !range( part ).empty(); const LHCb::MCParticle* mcPart = dynamic_cast<const LHCb::MCParticle*>( obj ); - return mcPart && !rangeP( mcPart ).empty(); + return mcPart && !range( mcPart ).empty(); } - auto rangeP( const LHCb::MCParticle* mcPart ) { - std::vector<std::pair<OBJ2MCP const*, double>> r; - for ( const auto& links : this->m_linkerList ) { - for ( const auto& [part, w] : LinkedFrom<OBJ2MCP>{links}.weightedRange( mcPart ) ) r.emplace_back( &part, w ); - } - return r; + using Object2MCLinker<OBJ2MCP, PARENT>::range; + auto range( const LHCb::MCParticle* mcPart ) const { + class InverseRange { + LHCb::span<LHCb::LinksByKey const* const> m_linkerList; + const LHCb::MCParticle* m_part = nullptr; + class Sentinel {}; + class Iterator { + using InnerRange = + decltype( LinkedFrom<OBJ2MCP>{nullptr}.weightedRange( static_cast<LHCb::MCParticle*>( nullptr ) ) ); + using InnerIter = decltype( std::declval<InnerRange>().begin() ); + LHCb::span<LHCb::LinksByKey const* const> m_linkerList; + InnerRange m_range = LinkedFrom<OBJ2MCP>{nullptr}.weightedRange( static_cast<LHCb::MCParticle*>( nullptr ) ); + InnerIter m_current = + LinkedFrom<OBJ2MCP>{nullptr}.weightedRange( static_cast<LHCb::MCParticle*>( nullptr ) ).begin(); + const LHCb::MCParticle* m_part = nullptr; + + public: + Iterator( LHCb::span<LHCb::LinksByKey const* const> linkers, const LHCb::MCParticle* p ) + : m_linkerList{linkers}, m_part{p} { + for ( ; m_range.empty() && !m_linkerList.empty(); m_linkerList = m_linkerList.subspan<1>() ) { + m_range = LinkedFrom<OBJ2MCP>{m_linkerList.front()}.weightedRange( m_part ); + } + m_current = m_range.begin(); + } + Iterator& operator++() { + if ( m_current != m_range.end() ) { + ++m_current; + } else if ( !m_linkerList.empty() ) { + *this = Iterator{m_linkerList.subspan<1>(), m_part}; + } + return *this; + } + decltype( auto ) operator*() const { return *m_current; } + bool operator!=( Sentinel ) const { return !m_linkerList.empty(); } + }; + + public: + InverseRange( LHCb::span<LHCb::LinksByKey const* const> links, const LHCb::MCParticle* p ) + : m_linkerList{links}, m_part{p} {} + Iterator begin() const { return {m_linkerList, m_part}; } + Sentinel end() const { return {}; } + bool empty() const { return !( begin() != end() ); } + decltype( auto ) front() const { return *begin(); } + auto const* try_front() const { + auto i = begin(); + return i != end() ? &std::get<0>( *i ) : nullptr; + } + }; + + return InverseRange{this->m_linkerList, mcPart}; } }; diff --git a/Associators/MCAssociators/include/Kernel/Particle2MCLinker.icpp b/Associators/MCAssociators/include/Kernel/Particle2MCLinker.icpp index ae2896a10c6..9692bb4a84c 100644 --- a/Associators/MCAssociators/include/Kernel/Particle2MCLinker.icpp +++ b/Associators/MCAssociators/include/Kernel/Particle2MCLinker.icpp @@ -110,10 +110,7 @@ StatusCode Object2MCLinker<SOURCE, PARENT>::locateAlgorithm( const std::string& } return sc; } -template <typename SOURCE, typename PARENT> -std::string Object2MCLinker<SOURCE, PARENT>::getGaudiRootInTES() { - return m_parent ? m_parent->rootInTES() : std::string{}; -} + template <typename SOURCE, typename PARENT> StatusCode Object2MCLinker<SOURCE, PARENT>::setAlgInputData( IAlgorithm*& alg, const std::vector<std::string>& inputData ) { @@ -121,7 +118,6 @@ StatusCode Object2MCLinker<SOURCE, PARENT>::setAlgInputData( IAlgorithm*& if ( inputData.empty() ) return StatusCode::SUCCESS; IProperty* prop = dynamic_cast<IProperty*>( alg ); - if ( !prop ) { ++m_ipropWarn; return StatusCode::SUCCESS; @@ -143,7 +139,7 @@ StatusCode Object2MCLinker<SOURCE, PARENT>::setAlgInputData( IAlgorithm*& std::string sep = "\""; for ( const auto& inpStr : inputData ) { propString += sep; - if ( std::string::npos == inpStr.find( "/Particles" ) && std::string::npos == inpStr.find( "/ProtoP" ) ) + if ( inpStr.npos == inpStr.find( "/Particles" ) && inpStr.npos == inpStr.find( "/ProtoP" ) ) propString += "/Particles"; propString += inpStr; sep = "\",\""; @@ -155,7 +151,7 @@ StatusCode Object2MCLinker<SOURCE, PARENT>::setAlgInputData( IAlgorithm*& return sc; } debug() << "Property InputData set to " << propString << " in algo " << alg->name() << endmsg; - const std::string rit( getGaudiRootInTES() ); + const std::string rit( m_parent ? m_parent->rootInTES() : std::string{} ); if ( !rit.empty() ) { std::string check; // check current RootInTES, if it exists sc = prop->getProperty( "RootInTES", check ); @@ -176,12 +172,6 @@ StatusCode Object2MCLinker<SOURCE, PARENT>::setAlgInputData( IAlgorithm*& return sc; } -template <typename SOURCE, typename PARENT> -bool Object2MCLinker<SOURCE, PARENT>::notFound() { - return std::all_of( m_containerList.begin(), m_containerList.end(), - [&]( const std::string& s ) { return notFound( s ); } ); -} - template <typename SOURCE, typename PARENT> void Object2MCLinker<SOURCE, PARENT>::createLinks( const std::string& contName ) { // First find the contname is in the list @@ -210,6 +200,8 @@ void Object2MCLinker<SOURCE, PARENT>::createLinks( const std::string& contName ) } // Call the algorithm to get the table done debug() << "==> Executing Linker builder algorithm " << m_linkerAlg->name() << endmsg; + // FIXME: this is a _major_ _design_ mistake: only the scheduler should execute algorithms... + ++m_executing_linker_builder_algo; StatusCode sc = m_linkerAlg->sysExecute( Gaudi::Hive::currentContext() ); if ( sc.isFailure() ) { error() << "Failed executing Linker builder algorithm " << m_linkerAlg->name() << endmsg; @@ -226,7 +218,7 @@ typename Object2MCLinker<SOURCE, PARENT>::ToRange Object2MCLinker<SOURCE, PARENT m_links = nullptr; return LinkedTo<LHCb::MCParticle>{nullptr}.weightedRange( static_cast<SOURCE*>( nullptr ) ); } - std::string contName = containerName( dynamic_cast<const ContainedObject*>( part ) ); + std::string contName = containerName( part ); if ( contName.compare( 0, 7, "/Event/" ) == 0 ) { contName = contName.substr( 7 ); } if ( contName.empty() ) { m_links = nullptr; @@ -241,28 +233,6 @@ typename Object2MCLinker<SOURCE, PARENT>::ToRange Object2MCLinker<SOURCE, PARENT return LinkedTo<LHCb::MCParticle>{m_links}.weightedRange( part ); } -// Helper methods to create a LinkerWithKey table if needed -template <typename SOURCE, typename PARENT> -typename Object2MCLinker<SOURCE, PARENT>::Linker* -Object2MCLinker<SOURCE, PARENT>::linkerTable( const std::string& name ) { - if ( !hasValidParent() ) return nullptr; - auto links = SmartDataPtr<LHCb::LinksByKey>{evtSvc(), LHCb::LinksByKey::linkerName( name )}; - return linkerTable( name, LinkedTo<LHCb::MCParticle>{links} ); -} - -template <typename SOURCE, typename PARENT> -typename Object2MCLinker<SOURCE, PARENT>::Linker* -Object2MCLinker<SOURCE, PARENT>::linkerTable( const std::string& name, LinkedTo<LHCb::MCParticle> test ) { - if ( !hasValidParent() ) return nullptr; - - if ( !test ) { - m_linkerTable = typename Object2MCLinker<SOURCE, PARENT>::Linker( evtSvc(), 0, name ); - return &m_linkerTable; - } else { - debug() << "Linker table " << name << " found" << endmsg; - } - return nullptr; -} template <typename SOURCE, typename PARENT> bool Object2MCLinker<SOURCE, PARENT>::checkAssociation( const SOURCE* obj, const LHCb::MCParticle* mcPart ) { auto r = range( obj ); diff --git a/CaloFuture/CaloFutureUtils/include/CaloFutureUtils/CaloFuture2MC.h b/CaloFuture/CaloFutureUtils/include/CaloFutureUtils/CaloFuture2MC.h index 12cdfffbd13..1068f57f969 100644 --- a/CaloFuture/CaloFutureUtils/include/CaloFutureUtils/CaloFuture2MC.h +++ b/CaloFuture/CaloFutureUtils/include/CaloFutureUtils/CaloFuture2MC.h @@ -22,10 +22,6 @@ namespace LHCb { template <class FROM, class TO, class WEIGHT> class IRelationWeighted; -template <class FROM, class TO> -class LinkerWithKey; -template <class FROM> -class LinkedTo; namespace LHCb { template <class FROM, class TO, class WEIGHT> class RelationWeighted1D; @@ -53,8 +49,4 @@ namespace LHCb::CaloFuture2MC { using IHypoTable = IRelationWeighted<LHCb::Detector::Calo::CellID, LHCb::MCParticle, float>; using HypoTable = RelationWeighted1D<LHCb::Detector::Calo::CellID, LHCb::MCParticle, float>; - using DigitLink = LinkerWithKey<LHCb::MCParticle, LHCb::CaloDigit>; - - using HypoLink = LinkerWithKey<LHCb::MCParticle, LHCb::CaloHypo>; - } // namespace LHCb::CaloFuture2MC diff --git a/Event/LinkerEvent/include/Event/LinksByKey.h b/Event/LinkerEvent/include/Event/LinksByKey.h index 44f36a82251..2a6bece82ff 100644 --- a/Event/LinkerEvent/include/Event/LinksByKey.h +++ b/Event/LinkerEvent/include/Event/LinksByKey.h @@ -16,10 +16,12 @@ #include "Kernel/STLExtensions.h" #include "GaudiKernel/DataObject.h" +#include "GaudiKernel/GaudiException.h" #include "GaudiKernel/IDataProviderSvc.h" +#include "GaudiKernel/IRegistry.h" #include "GaudiKernel/KeyedObject.h" -#include "GaudiKernel/SerializeSTL.h" +#include <fmt/format.h> #include <ostream> #include <utility> #include <vector> @@ -45,12 +47,33 @@ namespace LHCb { class LinksByKey final : public DataObject { public: + enum struct Order { increasingWeight, decreasingWeight }; + static std::string linkerName( const std::string& containerName ) { return "Link/" + ( "/Event/" == containerName.substr( 0, 7 ) ? containerName.substr( 7 ) : containerName ); } + static std::string inverseLinkerName( std::string const& containerName ) { + return linkerName( containerName ) + "Inv"; + } + + /// Default constructor, reserve space (needed for ROOT I/O streaming unfortunately) + /* [[deprecated]] */ LinksByKey() { + m_keyIndex.reserve( 1000 ); + m_linkReference.reserve( 1000 ); + } + + template <typename SOURCE, typename TARGET, typename = std::enable_if_t<!std::is_void_v<SOURCE>>> + LinksByKey( std::in_place_type_t<SOURCE>, std::in_place_type_t<TARGET>, Order order = Order::decreasingWeight ) + : m_increasing{order == Order::increasingWeight} + , m_sourceClassID{SOURCE::classID()} + , m_targetClassID{TARGET::classID()} { + m_keyIndex.reserve( 1000 ); + m_linkReference.reserve( 1000 ); + } - /// Default constructor, reserve space - LinksByKey() { + template <typename TARGET> + LinksByKey( std::in_place_type_t<void>, std::in_place_type_t<TARGET>, Order order = Order::decreasingWeight ) + : m_increasing{order == Order::increasingWeight}, m_targetClassID{TARGET::classID()} { m_keyIndex.reserve( 1000 ); m_linkReference.reserve( 1000 ); } @@ -62,17 +85,8 @@ namespace LHCb { /// Fill the ASCII output stream std::ostream& fillStream( std::ostream& s ) const override; - /// Define the increasing order for the references - LinksByKey& setIncreasing() { - m_increasing = true; - return *this; - } - - /// Define the decreasing order for the references - LinksByKey& setDecreasing() { - m_increasing = false; - return *this; - } + /// Return the order of the references + Order order() const { return m_increasing ? Order::increasingWeight : Order::decreasingWeight; } /// Get the pointers to the linked containers void resolveLinks( IDataProviderSvc* eventSvc ); @@ -80,6 +94,21 @@ namespace LHCb { /// Add a reference to the specified key void addReference( int srcKey, int srcLinkID, int destKey, int destLinkID, double weight = 1. ); + template <typename SOURCE, typename TARGET> + void link( const SOURCE* source, const TARGET* dest, double weight = 1. ) { + requireTargetID( TARGET::classID() ); + requireSourceID( SOURCE::classID() ); + if ( !source || !dest ) return; + addReference( source->index(), linkID( source->parent() ), dest->index(), linkID( dest->parent() ), weight ); + } + + template <typename TARGET> + void link( int key, const TARGET* dest, double weight = 1. ) { + requireTargetID( TARGET::classID() ); + if ( !dest ) return; + addReference( key, -1, dest->index(), linkID( dest->parent() ), weight ); + } + /// Retrieve the first LinkReference for this key bool firstReference( int key, const DataObject* container, LHCb::LinkReference& reference ) const; @@ -96,7 +125,7 @@ namespace LHCb { int nextSource( LHCb::LinkReference& reference, std::vector<std::pair<int, int>>::const_iterator& iter ) const; /// Returns the LinkManager linkID for this data object (Container) - int linkID( const DataObject* obj ) const; + int linkID( const DataObject* obj ); /// Reset the content of the objects void reset() { @@ -113,19 +142,25 @@ namespace LHCb { /// Retrieve const Class ID of the source of the Link unsigned int sourceClassID() const { return m_sourceClassID; } - /// Update Class ID of the source of the Link - LinksByKey& setSourceClassID( unsigned int value ) { - m_sourceClassID = value; - return *this; + void requireSourceID( const CLID& sourceID ) const { + if ( sourceClassID() != sourceID ) { + throw GaudiException( + fmt::format( "Incompatible SOURCE type for location {} : requested classID is : {} expected {}", location(), + sourceID, sourceClassID() ), + "LinksByKey", StatusCode::FAILURE ); + } } /// Retrieve const Class ID of the target of the Link unsigned int targetClassID() const { return m_targetClassID; } - /// Update Class ID of the target of the Link - LinksByKey& setTargetClassID( unsigned int value ) { - m_targetClassID = value; - return *this; + void requireTargetID( const CLID& targetID ) const { + if ( targetClassID() != targetID ) { + throw GaudiException( + fmt::format( "Incompatible TARGET type for location {} : Request classID is {} expected {}", location(), + targetID, targetClassID() ), + "LinksByKey", StatusCode::FAILURE ); + } } friend std::ostream& operator<<( std::ostream& str, const LinksByKey& obj ) { return obj.fillStream( str ); } @@ -158,11 +193,10 @@ namespace LHCb { if ( int key; findIndex( srcIndex, key ) ) { internalApply( srcIndex, m_keyIndex[key].second, func ); } } - protected: + private: /// Returns the index of the key in m_keyIndex. True if key exist, else inserting position bool findIndex( int key, int& index ) const; - private: /** * Internal helper function applying the given function to all links of the * chain given by refIndex @@ -170,6 +204,8 @@ namespace LHCb { template <typename Function> void internalApply( unsigned int srcIndex, int refIndex, Function&& func ) const; + std::string location() const { return registry() ? registry()->identifier() : "UnRegistered"; } + private: bool m_increasing = false; ///< Type of ordering std::vector<std::pair<int, int>> m_keyIndex; ///< List of linked objects diff --git a/Event/LinkerEvent/include/Linker/AllLinks.h b/Event/LinkerEvent/include/Linker/AllLinks.h deleted file mode 100644 index e47964f6ab2..00000000000 --- a/Event/LinkerEvent/include/Linker/AllLinks.h +++ /dev/null @@ -1,128 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* 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. * -\*****************************************************************************/ -#ifndef LINKER_ALLLINKS_H -#define LINKER_ALLLINKS_H 1 - -// STL -#include <sstream> - -// Include files -#include "Event/LinksByKey.h" -#include "GaudiKernel/ContainedObject.h" -#include "GaudiKernel/GaudiException.h" -#include "GaudiKernel/IDataProviderSvc.h" -#include "GaudiKernel/LinkManager.h" -#include "GaudiKernel/ObjectContainerBase.h" -#include "GaudiKernel/SmartDataPtr.h" -#include "GaudiKernel/SmartIF.h" - -/** @class AllLinks AllLinks.h Linker/AllLinks.h - * Templated interface to the LinksByKey, direct version - * - * @author Olivier Callot - * @date 2004-01-06 - */ - -template <class TARGET, class SOURCE = ContainedObject> -class AllLinks final { -public: - /// Standard constructor - AllLinks( IDataProviderSvc* eventSvc, IMessageSvc* msgSvc, std::string containerName ) { - m_eventSvc = eventSvc; - std::string name = "Link/" + containerName; - if ( containerName.compare( 0, 7, "/Event/" ) == 0 ) { name = "Link/" + containerName.substr( 7 ); } - SmartDataPtr<LHCb::LinksByKey> links( eventSvc, name ); - if ( !links ) { - if ( msgSvc ) { - MsgStream msg( msgSvc, "AllLinks::" + containerName ); - msg << MSG::ERROR << "*** Link container " << name << " not found." << endmsg; - } - } else { - //== Check proper template, only if specified. - if ( links->sourceClassID() != SOURCE::classID() && CLID_ContainedObject != SOURCE::classID() ) { - std::ostringstream message; - message << "Incompatible SOURCE type for location " << containerName << " : Template classID is " - << SOURCE::classID() << " expected " << links->sourceClassID(); - throw GaudiException( message.str(), "AllLinks", StatusCode::FAILURE ); - } - if ( links->targetClassID() != TARGET::classID() ) { - std::ostringstream message; - message << "Incompatible TARGET type for location " << containerName << " : Template classID is " - << TARGET::classID() << " expected " << links->targetClassID(); - throw GaudiException( message.str(), "AllLinks", StatusCode::FAILURE ); - } - } - m_links = links; - m_curReference.setNextIndex( -1 ); - m_curReference.setWeight( 0. ); - }; - - bool notFound() const { return !m_links; } - - TARGET* first() { - if ( !m_links ) return nullptr; - m_iter = m_links->keyIndex().begin(); - if ( m_links->keyIndex().end() == m_iter ) return nullptr; - m_curReference.setNextIndex( ( *m_iter ).second ); - return next(); - } - - TARGET* next() { - if ( !m_links ) return nullptr; - int nn = m_curReference.nextIndex(); - while ( 0 > nn ) { - if ( m_links->keyIndex().end() == m_iter ) return nullptr; - m_iter++; - if ( m_links->keyIndex().end() == m_iter ) return nullptr; - nn = ( *m_iter ).second; - } - m_curReference = m_links->linkReference()[nn]; - return currentTarget(); - } - - double weight() { return m_curReference.weight(); } - int key() { return ( *m_iter ).first; } - SOURCE* source() { return currentSource( ( *m_iter ).first ); } - -private: - TARGET* currentTarget() { - if ( !m_links ) return nullptr; - int myLinkID = m_curReference.linkID(); - LinkManager::Link* link = m_links->linkMgr()->link( myLinkID ); - if ( 0 == link->object() ) { - SmartDataPtr<DataObject> tmp( m_eventSvc.get(), link->path() ); - link->setObject( tmp ); - if ( !tmp ) return nullptr; - } - auto* parent = dynamic_cast<ObjectContainerBase*>( link->object() ); - return parent ? static_cast<TARGET*>( parent->containedObject( m_curReference.objectKey() ) ) : nullptr; - } - - SOURCE* currentSource( int key ) { - if ( !m_links ) return nullptr; - int myLinkID = m_curReference.srcLinkID(); - if ( 0 > myLinkID ) return nullptr; - LinkManager::Link* link = m_links->linkMgr()->link( myLinkID ); - if ( !link->object() ) { - SmartDataPtr<DataObject> tmp( m_eventSvc.get(), link->path() ); - link->setObject( tmp ); - if ( !tmp ) return nullptr; - } - auto* parent = dynamic_cast<ObjectContainerBase*>( link->object() ); - return parent ? static_cast<SOURCE*>( parent->containedObject( key ) ) : nullptr; - } - - SmartIF<IDataProviderSvc> m_eventSvc; - LHCb::LinksByKey* m_links; - LHCb::LinkReference m_curReference; - std::vector<std::pair<int, int>>::const_iterator m_iter; -}; -#endif // LINKER_ALLLINKS_H diff --git a/Event/LinkerEvent/include/Linker/LinkedFrom.h b/Event/LinkerEvent/include/Linker/LinkedFrom.h index bcbbbcd778e..c14b9f7995b 100644 --- a/Event/LinkerEvent/include/Linker/LinkedFrom.h +++ b/Event/LinkerEvent/include/Linker/LinkedFrom.h @@ -42,7 +42,7 @@ class LinkedFrom final { std::vector<std::pair<int, int>>::const_iterator m_srcIterator; long m_wantedKey = -1; - SOURCE const* currentSource( int index ) { + SOURCE const* source( int index ) { assert( m_links ); LinkManager::Link const* link = m_links->linkMgr()->link( m_curReference.srcLinkID() ); if ( !link->object() ) { @@ -53,7 +53,7 @@ class LinkedFrom final { return container ? static_cast<SOURCE const*>( container->containedObject( index ) ) : nullptr; } Iterator( LHCb::LinksByKey const* links, ContainedObject const* target ) - : m_links{links}, m_wantedKey{target->index()} { + : m_links{links}, m_wantedKey{target ? target->index() : -1} { if ( !m_links ) return; //== check that the target's container is known. const DataObject* container = target->parent(); @@ -68,7 +68,7 @@ class LinkedFrom final { m_curReference.setLinkID( short( link->ID() ) ); m_curReference.setObjectKey( m_wantedKey ); int index = m_links->firstSource( m_curReference, m_srcIterator ); - m_current = ( m_wantedKey == m_curReference.objectKey() ? currentSource( index ) : nullptr ); + m_current = ( m_wantedKey == m_curReference.objectKey() ? source( index ) : nullptr ); } public: @@ -82,7 +82,7 @@ class LinkedFrom final { Iterator& operator++() { if ( m_current ) { int index = m_links->nextSource( m_curReference, m_srcIterator ); - m_current = ( m_wantedKey == m_curReference.objectKey() ? currentSource( index ) : nullptr ); + m_current = ( m_wantedKey == m_curReference.objectKey() ? source( index ) : nullptr ); } return *this; } @@ -147,8 +147,9 @@ private: } if ( m_links->sourceClassID() != SOURCE::classID() && CLID_ContainedObject != SOURCE::classID() ) { throw GaudiException( - fmt::format( "Incompatible SOURCE type for location {} : Template classID is {} expected {}", - m_links->registry()->identifier(), SOURCE::classID(), m_links->sourceClassID() ), + fmt::format( "Incompatible SOURCE type for location {} @ {} : Template classID is {} expected {}", + m_links->registry()->identifier(), (const void*)m_links, SOURCE::classID(), + m_links->sourceClassID() ), "LinkedFrom", StatusCode::FAILURE ); } } @@ -164,4 +165,5 @@ private: LHCb::LinksByKey const* m_links; }; + #endif // LINKER_LINKEDFROM_H diff --git a/Event/LinkerEvent/include/Linker/LinkedFromKey.h b/Event/LinkerEvent/include/Linker/LinkedFromKey.h deleted file mode 100644 index d643cd42e66..00000000000 --- a/Event/LinkerEvent/include/Linker/LinkedFromKey.h +++ /dev/null @@ -1,27 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* 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. * -\*****************************************************************************/ -#ifndef LINKER_LINKEDFROMKEY_H -#define LINKER_LINKEDFROMKEY_H 1 - -// Include files -#include "Linker/LinkedFrom.h" - -/** @class LinkedFromKey LinkedFromKey.h Linker/LinkedFromKey.h - * Simple helper class to handle LinkedFrom with no source, i.e. key linker - * - * @author Olivier Callot - * @date 2008-03-14 - */ - -template <class TARGET, class KEY = int> -using LinkedFromKey = LinkedFrom<ContainedObject, TARGET, KEY>; - -#endif // LINKER_LINKEDFROMKEY_H diff --git a/Event/LinkerEvent/include/Linker/LinkerEntry.h b/Event/LinkerEvent/include/Linker/LinkerEntry.h deleted file mode 100644 index 0514c2c3afd..00000000000 --- a/Event/LinkerEvent/include/Linker/LinkerEntry.h +++ /dev/null @@ -1,54 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* 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. * -\*****************************************************************************/ -#ifndef LINKER_LINKERENTRY_H -#define LINKER_LINKERENTRY_H 1 - -/** @class LinkerEntry LinkerEntry.h Linker/LinkerEntry.h - * Describe an entry of a relation, expanded to pointer - * - * @author Olivier Callot - * @date 2005-01-19 - */ -template <class SOURCE, class TARGET> -class LinkerEntry final { -public: - /** constructor, with the needed information - * @param src source of the relation - * @param tgt target of the relation - * @param weight weight of the relation - */ - LinkerEntry( const SOURCE* src, const TARGET* tgt, double weight ) { - m_src = src; - m_target = tgt; - m_weight = weight; - }; - - /** accessor to the source - * @return the source information - */ - const SOURCE* from() const { return m_src; } - - /** accessor to the target - * @return the target information - */ - const TARGET* to() const { return m_target; } - - /** accessor to the weight - * @return the weight information - */ - double weight() const { return m_weight; } - -private: - const SOURCE* m_src; - const TARGET* m_target; - double m_weight; -}; -#endif // LINKER_LINKERENTRY_H diff --git a/Event/LinkerEvent/include/Linker/LinkerRange.h b/Event/LinkerEvent/include/Linker/LinkerRange.h deleted file mode 100644 index 228467e2300..00000000000 --- a/Event/LinkerEvent/include/Linker/LinkerRange.h +++ /dev/null @@ -1,81 +0,0 @@ -/*****************************************************************************\ -* (c) Copyright 2000-2018 CERN for the benefit of the LHCb Collaboration * -* * -* This software is distributed under the terms of the GNU General Public * -* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". * -* * -* 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. * -\*****************************************************************************/ -#ifndef LINKER_LINKERRANGE_H -#define LINKER_LINKERRANGE_H 1 - -// Include files -#include "Linker/LinkerEntry.h" -#include <vector> - -/** @class LinkerRange LinkerRange.h Linker/LinkerRange.h - * Holds a range, a collection of LinkerEntry - * - * @author Olivier Callot - * @date 2005-01-19 - */ - -template <class SOURCE, class TARGET> -class LinkerRange final { -public: - typedef typename std::vector<LinkerEntry<SOURCE, TARGET>>::const_iterator iterator; - - /** Add a LinkerEntry inside the range - * @param src pointer to the SOURCE of the entry - * @param tgt pointer to the TARGET of the entry - * @param weight Weight of the relation - */ - void addEntry( const SOURCE* src, const TARGET* tgt, double weight ) { emplace_back( src, tgt, weight ); } - - template <typename... Args> - void emplace_back( Args&&... args ) { - m_entries.emplace_back( std::forward<Args>( args )... ); - } - - void push_back( const LinkerEntry<SOURCE, TARGET>& le ) { m_entries.push_back( le ); } - - void push_back( LinkerEntry<SOURCE, TARGET>&& le ) { m_entries.push_back( std::move( le ) ); } - - /** returns an iterator to the beginning of the table of entries = range - * @return iterator - */ - iterator begin() const { return m_entries.begin(); } - - /** returns an iterator to the end of the table of entries = range - * @return iterator - */ - iterator end() const { return m_entries.end(); } - - /** returns the size of the range, the number of entries - * @return size - */ - int size() const { return m_entries.size(); } - - /** returns true if the range is empty - * @return is range empty ? - */ - bool empty() const { return m_entries.empty(); } - - /** clear the range, remove all entries - */ - void clear() { m_entries.clear(); } - - /** returns a reference to the first element - */ - const LinkerEntry<SOURCE, TARGET>& front() const { return m_entries.front(); } - - /** returns a reference to the last element - */ - const LinkerEntry<SOURCE, TARGET>& back() const { return m_entries.back(); } - -private: - std::vector<LinkerEntry<SOURCE, TARGET>> m_entries; -}; -#endif // LINKER_LINKERRANGE_H diff --git a/Event/LinkerEvent/include/Linker/LinkerTable.h b/Event/LinkerEvent/include/Linker/LinkerTable.h index f4bb0d7dccd..fcb59745b31 100644 --- a/Event/LinkerEvent/include/Linker/LinkerTable.h +++ b/Event/LinkerEvent/include/Linker/LinkerTable.h @@ -15,7 +15,6 @@ #include "Event/LinksByKey.h" #include "GaudiKernel/LinkManager.h" #include "GaudiKernel/ObjectContainerBase.h" -#include "Linker/LinkerRange.h" /** @class LinkerTable LinkerTable.h Linker/LinkerTable.h * This is a table, the interface to build LinkerRange. @@ -25,45 +24,132 @@ */ template <class SOURCE, class TARGET> class LinkerTable final { -public: - typedef LinkerRange<SOURCE, TARGET> Range; - typedef typename LinkerRange<SOURCE, TARGET>::iterator iterator; + class Range final { + struct AlwaysTrue { + template <typename... Args> + [[nodiscard]] constexpr bool operator()( Args&&... ) const noexcept { + return true; + } + }; - /** retrieve all relations in the table - * @return Range with all relations - */ - Range relations() const { - Range range; - if ( !m_links ) return range; - for ( auto iter = m_links->keyIndex().begin(); m_links->keyIndex().end() != iter; iter++ ) { + /** return the pointer to the TARGET object of the specified reference + * @param curReference reference entry to the object in the LinksByKeys + * @return pointer to the TARGET object + */ + static const TARGET* currentTarget( LHCb::LinksByKey const* links, LHCb::LinkReference const& curReference ) { + if ( !links ) return nullptr; + int myLinkID = curReference.linkID(); + const LinkManager::Link* link = links->linkMgr()->link( myLinkID ); + const ObjectContainerBase* parent = dynamic_cast<const ObjectContainerBase*>( link->object() ); + return parent ? static_cast<const TARGET*>( parent->containedObject( curReference.objectKey() ) ) : nullptr; + } + + /** return the pointer to the SOURCE object of the specified reference + * @param key key of the object. Its link is in the curReference argument + * @param curReference reference entry to the object in the LinksByKeys + * @return pointer to the SOURCE object + */ + static const SOURCE* currentSource( LHCb::LinksByKey const* links, int key, LHCb::LinkReference curReference ) { + if ( !links ) return nullptr; + int myLinkID = curReference.srcLinkID(); + if ( myLinkID < 0 ) return nullptr; + const LinkManager::Link* link = links->linkMgr()->link( myLinkID ); + const ObjectContainerBase* parent = dynamic_cast<const ObjectContainerBase*>( link->object() ); + return parent ? static_cast<const SOURCE*>( parent->containedObject( key ) ) : nullptr; + } + + class LinkerEntry final { + const SOURCE* m_src; + const TARGET* m_target; + double m_weight; + + public: + /** constructor, with the needed information + * @param src source of the relation + * @param tgt target of the relation + * @param weight weight of the relation + */ + LinkerEntry( const SOURCE* src, const TARGET* tgt, double weight ) { + m_src = src; + m_target = tgt; + m_weight = weight; + }; + + /** accessor to the source + * @return the source + */ + const SOURCE* from() const { return m_src; } + + /** accessor to the target + * @return the target + */ + const TARGET* to() const { return m_target; } + + /** accessor to the weight + * @return the weight + */ + double weight() const { return m_weight; } + }; + + std::vector<LinkerEntry> m_entries; + + public: + Range( const LHCb::LinksByKey* links ) { + if ( !links ) return; + for ( auto const [source, index] : links->keyIndex() ) { + LHCb::LinkReference curReference; + curReference.setNextIndex( index ); + while ( 0 <= curReference.nextIndex() ) { + curReference = links->linkReference()[curReference.nextIndex()]; + const SOURCE* src = currentSource( links, source, curReference ); + if ( src ) { // ignore int links + m_entries.emplace_back( src, currentTarget( links, curReference ), curReference.weight() ); + } + } + } + } + + template <typename Predicate = AlwaysTrue> + Range( const LHCb::LinksByKey* links, const SOURCE* reqSrc, Predicate predicate = {} ) { + if ( !links || !reqSrc ) return; LHCb::LinkReference curReference; - curReference.setNextIndex( ( *iter ).second ); - while ( 0 <= curReference.nextIndex() ) { - curReference = m_links->linkReference()[curReference.nextIndex()]; - const SOURCE* src = currentSource( iter->first, curReference ); - if ( src ) { // ignore int links - range.addEntry( src, currentTarget( curReference ), curReference.weight() ); + bool status = links->firstReference( reqSrc->index(), reqSrc->parent(), curReference ); + while ( status ) { + if ( predicate( curReference ) ) { + m_entries.emplace_back( reqSrc, currentTarget( links, curReference ), curReference.weight() ); } + status = links->nextReference( curReference ); } } - return range; + + auto begin() const { return m_entries.begin(); } + auto end() const { return m_entries.end(); } + int size() const { return m_entries.size(); } + bool empty() const { return m_entries.empty(); } + const LinkerEntry& front() const { return m_entries.front(); } + const LinkerEntry& back() const { return m_entries.back(); } }; +public: + LinkerTable( const LHCb::LinksByKey* links ) : m_links{links} { + if ( links ) { + links->requireSourceID( SOURCE::classID() ); + links->requireTargetID( TARGET::classID() ); + } + } + + explicit operator bool() const { return m_links != nullptr; } + + /** retrieve all relations in the table + * @return Range with all relations + */ + Range relations() const { return Range{m_links}; }; + /** Returns all the relations in the table for a given object. * @param reqSrc Object for which the relations is wanted @return Range of relations */ - Range relations( const SOURCE* reqSrc ) const { - Range range; - if ( !m_links || !reqSrc ) return range; - LHCb::LinkReference curReference; - bool status = m_links->firstReference( reqSrc->index(), reqSrc->parent(), curReference ); - while ( status ) { - range.addEntry( reqSrc, currentTarget( curReference ), curReference.weight() ); - status = m_links->nextReference( curReference ); - } - return range; - }; + Range relations( const SOURCE* reqSrc ) const { return Range{m_links, reqSrc}; }; /** Returns the relations with selected weight in the table for a given object. * @param reqSrc Object for which the relations is wanted @@ -72,52 +158,9 @@ public: * @return Range of selected relations */ Range relations( const SOURCE* reqSrc, double cut, bool order ) const { - Range range; - if ( !m_links ) return range; - if ( !reqSrc ) return range; - LHCb::LinkReference curReference; - bool status = m_links->firstReference( reqSrc->index(), reqSrc->parent(), curReference ); - while ( status ) { - double weight = curReference.weight(); - if ( ( order && weight >= cut ) || ( !order && weight <= cut ) ) { - TARGET* tgt = currentTarget( curReference ); - range.addEntry( reqSrc, tgt, weight ); - } - status = m_links->nextReference( curReference ); - } - return range; - }; - - /** load the LinksByKeys object - * @param links pointer to the LinksByKey object - */ - void load( const LHCb::LinksByKey* links ) { m_links = links; } - -protected: - /** return the pointer to the TARGET object of the specified reference - * @param curReference reference entry to the object in the LinksByKeys - * @return pointer to the TARGET object - */ - const TARGET* currentTarget( LHCb::LinkReference& curReference ) const { - if ( !m_links ) return nullptr; - int myLinkID = curReference.linkID(); - const LinkManager::Link* link = m_links->linkMgr()->link( myLinkID ); - const ObjectContainerBase* parent = dynamic_cast<const ObjectContainerBase*>( link->object() ); - return parent ? static_cast<const TARGET*>( parent->containedObject( curReference.objectKey() ) ) : nullptr; - } - - /** return the pointer to the SOURCE object of the specified reference - * @param key key of the object. Its link is in the curReference argument - * @param curReference reference entry to the object in the LinksByKeys - * @return pointer to the SOURCE object - */ - const SOURCE* currentSource( int key, LHCb::LinkReference curReference ) const { - if ( !m_links ) return nullptr; - int myLinkID = curReference.srcLinkID(); - if ( 0 > myLinkID ) return nullptr; - const LinkManager::Link* link = m_links->linkMgr()->link( myLinkID ); - const ObjectContainerBase* parent = dynamic_cast<const ObjectContainerBase*>( link->object() ); - return parent ? static_cast<const SOURCE*>( parent->containedObject( key ) ) : nullptr; + return Range{m_links, reqSrc, [cut, order]( const LHCb::LinkReference& r ) { + return order ? ( r.weight() >= cut ) : ( r.weight() <= cut ); + }}; } private: diff --git a/Event/LinkerEvent/include/Linker/LinkerTool.h b/Event/LinkerEvent/include/Linker/LinkerTool.h index 4342b2865e9..9bbb4d97beb 100644 --- a/Event/LinkerEvent/include/Linker/LinkerTool.h +++ b/Event/LinkerEvent/include/Linker/LinkerTool.h @@ -10,21 +10,11 @@ \*****************************************************************************/ #ifndef LINKER_LINKERTOOL_H #define LINKER_LINKERTOOL_H 1 - -// STL -#include <sstream> - -// Include files -#include "GaudiKernel/GaudiException.h" +#include "Event/LinksByKey.h" #include "GaudiKernel/IDataProviderSvc.h" -#include "GaudiKernel/LinkManager.h" -#include "GaudiKernel/ObjectContainerBase.h" +#include "GaudiKernel/SmartDataPtr.h" #include "GaudiKernel/SmartIF.h" - -#include "Event/LinksByKey.h" - #include "Linker/LinkerTable.h" -#include "Linker/LinkerWithKey.h" /** @class LinkerTool LinkerTool.h Linker/LinkerTool.h * Mimic the relation tool as much as possible @@ -36,95 +26,50 @@ template <class SOURCE, class TARGET> class LinkerTool final { public: - typedef LinkerTable<SOURCE, TARGET> DirectType; - typedef LinkerTable<TARGET, SOURCE> InverseType; - typedef typename DirectType::Range Range; - typedef typename DirectType::iterator iterator; + using DirectType = LinkerTable<SOURCE, TARGET>; + using InverseType = LinkerTable<TARGET, SOURCE>; /** Standard constructor * @param svc event service * @param containerName name of the container of links. */ - LinkerTool( IDataProviderSvc* svc, std::string containerName ) { - m_evtSvc = svc; - std::string name = "Link/" + containerName; - if ( "/Event/" == containerName.substr( 0, 7 ) ) { name = "Link/" + containerName.substr( 7 ); } - m_location = name; - m_invLocation = name + "Inv"; - }; + LinkerTool( IDataProviderSvc* svc, std::string containerName ) + : m_evtSvc{svc} + , m_location{LHCb::LinksByKey::linkerName( containerName )} + , m_invLocation{LHCb::LinksByKey::inverseLinkerName( containerName )} {} /** retrieve the direct relation * @return The direct table of relation. */ - - DirectType* direct() { + DirectType direct() const { SmartDataPtr<LHCb::LinksByKey> links( m_evtSvc.get(), m_location ); - if ( links ) { - links->resolveLinks( m_evtSvc.get() ); - - if ( links->sourceClassID() != SOURCE::classID() ) { - std::ostringstream message; - message << "Incompatible SOURCE type for location " << m_location - << " : Template classID is : " << SOURCE::classID() << " expected " << links->sourceClassID(); - throw GaudiException( message.str(), "LinkerTool", StatusCode::FAILURE ); - } - if ( links->targetClassID() != TARGET::classID() ) { - std::ostringstream message; - message << "Incompatible TARGET type for location " << m_location << " : Template classID is " - << TARGET::classID() << " expected " << links->targetClassID(); - throw GaudiException( message.str(), "LinkerTool", StatusCode::FAILURE ); - } - } - - const LHCb::LinksByKey* linkPtr = links; - m_table.load( linkPtr ); - return linkPtr ? &m_table : nullptr; + if ( links ) links->resolveLinks( m_evtSvc.get() ); + return {links}; } /** retrieve the inverse relation, build it if not yet done * @return The inverse table of relation. */ - InverseType* inverse() { + InverseType inverse() const { SmartDataPtr<LHCb::LinksByKey> links( m_evtSvc.get(), m_invLocation ); - LHCb::LinksByKey* linkPtr = links; - if ( 0 == linkPtr ) { + if ( !links ) { //== Invert the table... - const DirectType* tmp = direct(); - if ( 0 != tmp ) { - // Create, with name shortened to remove the "Link/" prefix - LinkerWithKey<SOURCE, TARGET> makeLink( m_evtSvc.get(), 0, m_invLocation.substr( 5 ) ); - Range rd = tmp->relations(); - for ( iterator it = rd.begin(); rd.end() != it; ++it ) { makeLink.link( it->to(), it->from(), it->weight() ); } - SmartDataPtr<LHCb::LinksByKey> newLinks( m_evtSvc.get(), m_invLocation ); - linkPtr = newLinks; + if ( const auto tmp = direct(); tmp ) { + links = new LHCb::LinksByKey{std::in_place_type<TARGET>, std::in_place_type<SOURCE>, + LHCb::LinksByKey::Order::decreasingWeight}; + StatusCode sc = m_evtSvc->registerObject( m_invLocation, links ); + if ( !sc ) { throw GaudiException( "Failed to register " + m_invLocation, "LinkerTool::inverse", sc ); } + for ( auto const& r : tmp.relations() ) links->link( r.to(), r.from(), r.weight() ); } } - if ( linkPtr ) linkPtr->resolveLinks( m_evtSvc.get() ); - m_invTable.load( linkPtr ); - if ( !linkPtr ) return nullptr; - - //== TARGET and SOURCE are exchanged for the inverse table - if ( linkPtr->targetClassID() != SOURCE::classID() ) { - throw GaudiException( "Incompatible SOURCE type for location " + m_location + " : Template classID is " + - std::to_string( SOURCE::classID() ) + " expected " + - std::to_string( links->targetClassID() ), - "LinkerTool", StatusCode::FAILURE ); - } - if ( linkPtr->sourceClassID() != TARGET::classID() ) { - throw GaudiException( "Incompatible TARGET type for location " + m_location + " : Template classID is " + - std::to_string( TARGET::classID() ) + " expected " + - std::to_string( links->sourceClassID() ), - "LinkerTool", StatusCode::FAILURE ); - } - return &m_invTable; + if ( links ) links->resolveLinks( m_evtSvc.get() ); + return {links}; } private: SmartIF<IDataProviderSvc> m_evtSvc; std::string m_location; std::string m_invLocation; - DirectType m_table; - InverseType m_invTable; }; #endif // LINKER_LINKERTOOL_H diff --git a/Event/LinkerEvent/include/Linker/LinkerWithKey.h b/Event/LinkerEvent/include/Linker/LinkerWithKey.h index cd3a891d365..1a9be3b4ae0 100644 --- a/Event/LinkerEvent/include/Linker/LinkerWithKey.h +++ b/Event/LinkerEvent/include/Linker/LinkerWithKey.h @@ -8,15 +8,11 @@ * granted to it by virtue of its status as an Intergovernmental Organization * * or submit itself to any jurisdiction. * \*****************************************************************************/ -#ifndef LINKER_LINKERWITHKEY_H -#define LINKER_LINKERWITHKEY_H 1 - -// Include files +#pragma once #include "Event/LinksByKey.h" #include "GaudiKernel/ContainedObject.h" +#include "GaudiKernel/GaudiException.h" #include "GaudiKernel/IDataProviderSvc.h" -#include "GaudiKernel/IMessageSvc.h" -#include "GaudiKernel/MsgStream.h" #include "GaudiKernel/SmartDataPtr.h" /** @class LinkerWithKey LinkerWithKey.h Linker/LinkerWithKey.h @@ -25,64 +21,35 @@ * @author Olivier Callot * @date 2004-01-06 */ -template <class TARGET, class SOURCE = ContainedObject> -class LinkerWithKey final { -public: - /// Standard constructor - LinkerWithKey( IDataProviderSvc* evtSvc, IMessageSvc* msgSvc, std::string containerName ) : m_links( nullptr ) { - if ( !containerName.empty() ) { - std::string name = "Link/" + containerName; - if ( "/Event/" == containerName.substr( 0, 7 ) ) { name = "Link/" + containerName.substr( 7 ); } - //== If it exists, just append to it. +template <class TARGET, class SOURCE = ContainedObject> +struct LinkerWithKey final { - SmartDataPtr<LHCb::LinksByKey> links( evtSvc, name ); - if ( links ) { - m_links = links; - } else { - m_links = new LHCb::LinksByKey(); - StatusCode sc = evtSvc->registerObject( name, m_links ); - if ( !sc && msgSvc ) { - MsgStream msg( msgSvc, "LinkerWithKey::" + containerName ); - msg << MSG::ERROR << "*** Link container " << name << " cannot be registered, Status " << sc << endmsg; - } + static LHCb::LinksByKey* create( IDataProviderSvc* evtSvc, std::string containerName, + LHCb::LinksByKey::Order order ) { + LHCb::LinksByKey* lbk = nullptr; + if ( containerName.empty() ) { + throw GaudiException{"Empty containerName", "LinkerWithKey::create", StatusCode::FAILURE}; + } + std::string name = LHCb::LinksByKey::linkerName( containerName ); + + //== If it exists, just append to it. + SmartDataPtr<LHCb::LinksByKey> links( evtSvc, name ); + if ( links ) { + lbk = links; + lbk->requireSourceID( SOURCE::classID() ); + lbk->requireTargetID( TARGET::classID() ); + if ( lbk->order() != order ) { + throw GaudiException( "Invalid LinkerWithKey: inconsistent prior ordering;", "LinkerWithKey::LinkerWithKey", + StatusCode::FAILURE ); } - - m_links->setTargetClassID( TARGET::classID() ); - m_links->setSourceClassID( SOURCE::classID() ); + } else { + lbk = new LHCb::LinksByKey{std::in_place_type<SOURCE>, std::in_place_type<TARGET>, + LHCb::LinksByKey::Order::decreasingWeight}; + StatusCode sc = evtSvc->registerObject( name, lbk ); + if ( !sc ) { throw GaudiException( "Failed to register " + name, "LinkerWithKey::LinkerWithKey", sc ); } } - }; - void reset() { m_links->reset(); } - - void link( const SOURCE* source, const TARGET* dest, double weight = 1. ) { - if ( !source ) return; - if ( !dest ) return; - if ( !m_links ) return; - int srcIndex = source->index(); - int srcLinkID = m_links->linkID( source->parent() ); - int destIndex = dest->index(); - int destLinkID = m_links->linkID( dest->parent() ); - - m_links->addReference( srcIndex, srcLinkID, destIndex, destLinkID, weight ); - } - - void link( int key, const TARGET* dest, double weight = 1. ) { - if ( !dest ) return; - if ( !m_links ) return; - int destIndex = dest->index(); - int destLinkID = m_links->linkID( dest->parent() ); - m_links->addReference( key, -1, destIndex, destLinkID, weight ); - } - - void setIncreasingWeight() { - if ( m_links ) m_links->setIncreasing(); - } - void setDecreasingWeight() { - if ( m_links ) m_links->setDecreasing(); - } - -private: - LHCb::LinksByKey* m_links; + return lbk; + }; }; -#endif // LINKER_LINKERWITHKEYNEW_H diff --git a/Event/LinkerEvent/src/LinksByKey.cpp b/Event/LinkerEvent/src/LinksByKey.cpp index 7a6d273e82d..110e2729ece 100644 --- a/Event/LinkerEvent/src/LinksByKey.cpp +++ b/Event/LinkerEvent/src/LinksByKey.cpp @@ -47,6 +47,8 @@ void LHCb::LinksByKey::addReference( int srcKey, int srcLinkID, int destKey, int int indx; if ( !findIndex( srcKey, indx ) ) { + // TODO: use lower_bound to find right place, then use that with insert... + // instead of doing this manually m_keyIndex.emplace_back( 0, 0 ); int iL = m_keyIndex.size() - 1; while ( iL > indx ) { @@ -223,11 +225,11 @@ int LHCb::LinksByKey::nextSource( LHCb::LinkReference& //========================================================================= // Returns the ID in the link table of the given object //========================================================================= -int LHCb::LinksByKey::linkID( const DataObject* obj ) const { +int LHCb::LinksByKey::linkID( const DataObject* obj ) { int id; LinkManager::Link const* link = linkMgr()->link( obj ); if ( !link ) { - id = const_cast<LinksByKey*>( this )->linkMgr()->addLink( obj->registry()->identifier(), obj ); + id = linkMgr()->addLink( obj->registry()->identifier(), obj ); } else { id = link->ID(); } -- GitLab