Skip to content
Snippets Groups Projects
Commit 87c1c277 authored by Gerhard Raven's avatar Gerhard Raven Committed by Marco Clemencic
Browse files

next iteration on support for binding tools

parent be0cb48a
No related branches found
No related tags found
1 merge request!1270Support for binding tools to event and/or conditions data
......@@ -376,8 +376,8 @@ namespace Gaudi::Functional::details {
// check whether Traits::BaseClass is a valid type,
// if so, define BaseClass_t<Traits> as being Traits::BaseClass
// else define as being GaudiAlgorithm
template <typename Tr>
using BaseClass_t = Gaudi::cpp17::detected_or_t<GaudiAlgorithm, detail2::BaseClass_t, Tr>;
template <typename Tr, typename Base = GaudiAlgorithm>
using BaseClass_t = Gaudi::cpp17::detected_or_t<Base, detail2::BaseClass_t, Tr>;
// check whether Traits::{Input,Output}Handle<T> is a valid type,
// if so, define {Input,Output}Handle_t<Traits,T> as being Traits::{Input,Output}Handle<T>
......
......@@ -18,20 +18,20 @@ namespace Gaudi::Functional {
using add_base_t = std::conditional_t<Gaudi::cpp17::is_detected_v<detail2::BaseClass_t, Tr>, Tr,
Traits::use_<Tr, BaseClass_t<Base>>>;
template <typename Signature, typename Traits>
template <typename IFace, typename Signature, typename Traits>
struct ToolBinder;
template <typename IFace, typename... Args, typename Traits>
class ToolBinder<Gaudi::Interface::BoxedInterface<IFace>( Args const&... ), Traits>
: public extends<details::BaseClass_t<Traits>, Gaudi::Interface::IBinder<IFace>> {
class ToolBinder<IFace, Gaudi::Interface::Bind::Box( Args const&... ), Traits>
: public extends<details::BaseClass_t<Traits, AlgTool>, Gaudi::Interface::Bind::IBinder<IFace>> {
constexpr static std::size_t N = sizeof...( Args );
template <typename IArgs, std::size_t... I>
ToolBinder( std::string type, std::string name, const IInterface* parent, IArgs&& args,
std::index_sequence<I...> )
: extends<details::BaseClass_t<Traits>, Gaudi::Interface::IBinder<IFace>>{ std::move( type ),
std::move( name ), parent }
: extends<details::BaseClass_t<Traits>, Gaudi::Interface::Bind::IBinder<IFace>>{ std::move( type ),
std::move( name ), parent }
, m_handles{ std::tuple_cat( std::forward_as_tuple( this ), std::get<I>( args ) )... } {}
std::tuple<details::InputHandle_t<Traits, Args>...> m_handles;
......@@ -42,13 +42,13 @@ namespace Gaudi::Functional {
Gaudi::Functional::details::RepeatValues_<KeyValue, N> const& inputs )
: ToolBinder{ std::move( type ), std::move( name ), parent, inputs, std::make_index_sequence<N>{} } {}
virtual Gaudi::Interface::BoxedInterface<IFace> bind( const Args&... args ) const = 0;
virtual Gaudi::Interface::Bind::Box operator()( const Args&... args ) const = 0;
Gaudi::Interface::BoxedInterface<IFace> operator()( EventContext const& ctx ) const override final {
Gaudi::Interface::Bind::Box i_bind( EventContext const& ctx ) const final {
return std::apply(
[&]( auto const&... arg ) {
using namespace details;
return this->bind( get( arg, *this, ctx )... );
return std::invoke( *this, get( arg, *this, ctx )... );
},
m_handles );
}
......@@ -66,7 +66,7 @@ namespace Gaudi::Functional {
};
} // namespace details
template <typename Signature, typename Traits_ = Traits::use_<Traits::BaseClass_t<AlgTool>>>
using ToolBinder = details::ToolBinder<Signature, Traits_>;
template <typename IFace, typename Signature, typename Traits_ = Traits::use_<Traits::BaseClass_t<AlgTool>>>
using ToolBinder = details::ToolBinder<IFace, Signature, Traits_>;
} // namespace Gaudi::Functional
......@@ -14,6 +14,7 @@
from GaudiKernel.DataHandle import DataHandle
from Gaudi.Configuration import *
from Configurables import Gaudi__Examples__ToolConsumer as ToolConsumer
from Configurables import Gaudi__Examples__AlgToolConsumer as AlgToolConsumer
from Configurables import Gaudi__Examples__MyExampleTool as MyExampleTool
from Configurables import Gaudi__Examples__MyConsumerTool as MyConsumerTool
from Configurables import Gaudi__Examples__IntDataProducer as IntDataProducer
......@@ -83,6 +84,11 @@ app.TopAlg = [
IntDataConsumer("IntDataConsumer"),
BoundToolConsumer(
"BoundConsumer", MyTool=MyConsumerTool(MyInt="/Event/MyOtherInt")),
AlgToolConsumer(
"AlgBoundConsumer", MyTool=MyConsumerTool(MyInt="/Event/MyOtherInt")),
AlgToolConsumer(
"AlgUnBoundConsumer",
MyTool=MyExampleTool(Message="No binding required")),
IntToFloatData("IntToFloatData"),
IntIntToFloatFloatData("IntIntToFloatFloatData"),
FloatDataConsumer("FloatDataConsumer"),
......
......@@ -16,6 +16,7 @@
#include "GaudiAlg/Transformer.h"
#include "GaudiKernel/AlgTool.h"
#include "GaudiKernel/IAlgTool.h"
#include "GaudiKernel/IBinder.h"
#include "GaudiKernel/KeyedContainer.h"
#include "GaudiKernel/SharedObjectsContainer.h"
#include <cmath>
......@@ -34,56 +35,82 @@ namespace Gaudi::Examples {
void operator()() const override { always() << m_message.value() << endmsg; }
Gaudi::Property<std::string> m_message{ this, "Message", "Boring Default Message" };
};
DECLARE_COMPONENT( MyExampleTool )
struct MyConsumerTool final : Gaudi::Functional::ToolBinder<Gaudi::Interface::BoxedInterface<IMyTool>( const int& )> {
struct MyConsumerTool final : Gaudi::Functional::ToolBinder<IMyTool, Gaudi::Interface::Bind::Box( const int& )> {
MyConsumerTool( std::string type, std::string name, const IInterface* parent )
: ToolBinder{ std::move( type ), std::move( name ), parent, KeyValue{ "MyInt", "/Event/MyInt" } } {}
class BoundInstance final : public Gaudi::Interface::Stub<IMyTool> {
class BoundInstance final : public Gaudi::Interface::Bind::Stub<IMyTool> {
MyConsumerTool const* parent;
int i;
public:
BoundInstance( MyConsumerTool const* parent, const int& i ) : parent{ parent }, i{ i } {}
void operator()() const override {
parent->always() << "BoundInstance - got: " << i << " from " << parent->inputLocation() << endmsg;
parent->always() << "BoundInstance - got: " << i << " from " << parent->inputLocation<int>() << endmsg;
}
};
Gaudi::Interface::BoxedInterface<IMyTool> bind( const int& i ) const override {
return { std::in_place_type<BoundInstance>, this, i };
Gaudi::Interface::Bind::Box operator()( const int& i ) const override {
return { std::in_place_type<IMyTool>, std::in_place_type<BoundInstance>, this, i };
};
};
DECLARE_COMPONENT( MyConsumerTool )
using BaseClass_t = Gaudi::Functional::Traits::BaseClass_t<Gaudi::Algorithm>;
struct ToolConsumer final : Gaudi::Functional::Consumer<void( IMyTool const& ), BaseClass_t> {
struct ToolConsumer final : Gaudi::Functional::Consumer<void( EventContext const&, IMyTool const& ), BaseClass_t> {
ToolConsumer( const std::string& name, ISvcLocator* svcLoc )
: Consumer( name, svcLoc, KeyValue{ "MyTool", "MyExampleTool" } ) {}
void operator()( IMyTool const& tool ) const override { tool(); }
void operator()( EventContext const& ctx, IMyTool const& tool ) const override {
always() << "calling tool directly:" << endmsg;
tool();
always() << "calling boxed tool:" << endmsg;
auto box = Gaudi::Interface::Bind::makeBox<IMyTool>( &tool, ctx );
IMyTool const* ptr = box.get<IMyTool>();
if ( !ptr ) fatal() << "oops..." << endmsg;
( *ptr )();
}
};
DECLARE_COMPONENT( ToolConsumer )
struct BoundToolConsumer final
: Gaudi::Functional::Consumer<void( EventContext const&, Gaudi::Interface::IBinder<IMyTool> const& ),
: Gaudi::Functional::Consumer<void( EventContext const&, Gaudi::Interface::Bind::IBinder<IMyTool> const& ),
BaseClass_t> {
BoundToolConsumer( const std::string& name, ISvcLocator* svcLoc )
: Consumer( name, svcLoc, KeyValue{ "MyTool", "MyConsumerTool" } ) {}
void operator()( EventContext const& ctx, Gaudi::Interface::IBinder<IMyTool> const& tool ) const override {
auto box = tool( ctx );
IMyTool const& t = box;
t();
void operator()( EventContext const& ctx, Gaudi::Interface::Bind::IBinder<IMyTool> const& tool ) const override {
auto box = Gaudi::Interface::Bind::makeBox<IMyTool>( &tool, ctx );
IMyTool const* ptr = box.get<IMyTool>();
if ( !ptr ) fatal() << "oops..." << endmsg;
( *ptr )();
}
};
DECLARE_COMPONENT( BoundToolConsumer )
struct AlgToolConsumer final
: Gaudi::Functional::Consumer<void( EventContext const&, IAlgTool const& ), BaseClass_t> {
AlgToolConsumer( const std::string& name, ISvcLocator* svcLoc )
: Consumer( name, svcLoc, KeyValue{ "MyTool", "MyConsumerTool" } ) {}
void operator()( EventContext const& ctx, IAlgTool const& tool ) const override {
always() << "got generic IAlgTool, try to box it and get IMyTool" << endmsg;
auto box = Gaudi::Interface::Bind::makeBox<IMyTool>( &tool, ctx );
if ( IMyTool const* ptr = box.get<IMyTool>(); ptr != nullptr ) {
always() << "got IMyTool -- calling it" << endmsg;
( *ptr )();
} else {
always() << "could not get IMyTool interface... sorry" << endmsg;
}
}
};
DECLARE_COMPONENT( AlgToolConsumer )
struct CountingConsumer final : Gaudi::Functional::Consumer<void(), BaseClass_t> {
using Gaudi::Functional::Consumer<void(), BaseClass_t>::Consumer;
mutable Gaudi::Accumulators::MsgCounter<MSG::ERROR> m_err{ this, "This is not an error...", 3 };
......
......@@ -47,18 +47,27 @@
ApplicationMgr SUCCESS
====================================================================================================================================
Welcome to ApplicationMgr (GaudiCoreSvc v36r2)
running on stbc-i1.nikhef.nl on Tue Oct 26 11:57:51 2021
running on stbc-i1.nikhef.nl on Thu Oct 28 11:07:42 2021
====================================================================================================================================
ApplicationMgr INFO Application Manager Configured successfully
EventLoopMgr WARNING Unable to locate service "EventSelector"
EventLoopMgr WARNING No events will be processed from external input.
ApplicationMgr INFO Application Manager Initialized successfully
ApplicationMgr INFO Application Manager Started successfully
MyToolConsumer SUCCESS calling tool directly:
MyToolConsumer....SUCCESS Hello World!!!
MyToolConsumer SUCCESS calling boxed tool:
MyToolConsumer....SUCCESS Hello World!!!
IntDataProducer INFO executing IntDataProducer, storing 7 into /Event/MyInt
OtherIntDataPro... INFO executing IntDataProducer, storing 7 into /Event/MyOtherInt
IntDataConsumer INFO executing IntDataConsumer, consuming 7 from /Event/MyInt
BoundConsumer.G...SUCCESS BoundInstance - got: 7 from /Event/MyOtherInt
AlgBoundConsumer SUCCESS got generic IAlgTool, try to box it and get IMyTool
AlgBoundConsumer SUCCESS got IMyTool -- calling it
AlgBoundConsume...SUCCESS BoundInstance - got: 7 from /Event/MyOtherInt
AlgUnBoundConsumerSUCCESS got generic IAlgTool, try to box it and get IMyTool
AlgUnBoundConsumerSUCCESS got IMyTool -- calling it
AlgUnBoundConsu...SUCCESS No binding required
IntToFloatData INFO Converting: 7 from /Event/MyInt and storing it into /Event/MyFloat
IntIntToFloatFl... INFO Number of inputs : 2, number of outputs : 2
IntIntToFloatFl... INFO Converting 7 from /Event/MyInt and 7 from /Event/MyOtherInt
......@@ -111,11 +120,20 @@ IntVectorsMerger INFO Consuming vector [3, 3, 3, 3]
IntVectorsMergi... INFO sum of input sizes: 8
IntVectorsMergi... INFO Consuming vector [3, 3, 3, 3]
IntVectorsMergi... INFO Consuming vector [3, 3, 3, 3]
MyToolConsumer SUCCESS calling tool directly:
MyToolConsumer....SUCCESS Hello World!!!
MyToolConsumer SUCCESS calling boxed tool:
MyToolConsumer....SUCCESS Hello World!!!
IntDataProducer INFO executing IntDataProducer, storing 7 into /Event/MyInt
OtherIntDataPro... INFO executing IntDataProducer, storing 7 into /Event/MyOtherInt
IntDataConsumer INFO executing IntDataConsumer, consuming 7 from /Event/MyInt
BoundConsumer.G...SUCCESS BoundInstance - got: 7 from /Event/MyOtherInt
AlgBoundConsumer SUCCESS got generic IAlgTool, try to box it and get IMyTool
AlgBoundConsumer SUCCESS got IMyTool -- calling it
AlgBoundConsume...SUCCESS BoundInstance - got: 7 from /Event/MyOtherInt
AlgUnBoundConsumerSUCCESS got generic IAlgTool, try to box it and get IMyTool
AlgUnBoundConsumerSUCCESS got IMyTool -- calling it
AlgUnBoundConsu...SUCCESS No binding required
IntToFloatData INFO Converting: 7 from /Event/MyInt and storing it into /Event/MyFloat
IntIntToFloatFl... INFO Number of inputs : 2, number of outputs : 2
IntIntToFloatFl... INFO Converting 7 from /Event/MyInt and 7 from /Event/MyOtherInt
......
......@@ -8,24 +8,49 @@
* granted to it by virtue of its status as an Intergovernmental Organization *
* or submit itself to any jurisdiction. *
\*****************************************************************************/
#include "GaudiKernel/EventContext.h"
#pragma once
#include "GaudiKernel/IAlgTool.h"
#include "GaudiKernel/IInterface.h"
#include "GaudiKernel/extend_interfaces.h"
#include "GaudiKernel/bind.h"
#include <type_traits>
#include <utility>
namespace Gaudi::Interface {
namespace Gaudi::Interface::Bind {
template <typename IFace>
struct InterfaceStub : IFace {
long unsigned int addRef() override { return 0; }
long unsigned int release() override { return 0; }
StatusCode queryInterface( const InterfaceID&, void** ) override { return StatusCode::FAILURE; }
struct IBinder : extend_interfaces<IAlgTool> {
DeclareInterfaceID( IBinder, 1, 0 );
virtual Box i_bind( const EventContext& ctx ) const = 0;
};
/// Support binding of tools (FIXME: this could be moved into a ToolHandle (at which point some of the logic could be
/// cached...)
template <typename IFace>
Box makeBox( IAlgTool const* tool, const EventContext& ctx ) {
void* ptr = nullptr;
if ( auto sc = const_cast<IAlgTool*>( tool )->queryInterface( IFace::interfaceID(), &ptr ); sc.isSuccess() ) {
// TODO: what happens to the refCount?
return Gaudi::Interface::Bind::Box( std::in_place_type<IFace>, static_cast<IFace const*>( ptr ) );
} else if ( auto sc = const_cast<IAlgTool*>( tool )->queryInterface(
Gaudi::Interface::Bind::IBinder<IFace>::interfaceID(), &ptr );
sc.isSuccess() ) {
// TODO: what happens to the refCount?
return static_cast<Gaudi::Interface::Bind::IBinder<IFace> const*>( ptr )->i_bind( ctx );
} else {
return Gaudi::Interface::Bind::Box{};
}
}
template <typename IFace>
struct AlgToolStub : InterfaceStub<IFace> {
struct AlgToolStub : IFace {
using IFace::IFace;
AlgToolStub( const AlgToolStub& ) = delete;
AlgToolStub& operator=( const AlgToolStub& ) = delete;
AlgToolStub( AlgToolStub&& ) = delete;
AlgToolStub& operator=( AlgToolStub&& ) = delete;
const std::string& name() const override {
static std::string s{ "GoAway" };
static std::string s{ "<STUB>" };
return s;
}
const std::string& type() const override { return name(); }
......@@ -49,42 +74,6 @@ namespace Gaudi::Interface {
};
template <typename IFace>
struct Stub
: std::conditional_t<std::is_base_of_v<IAlgTool, IFace>, AlgToolStub<IFace>,
std::conditional_t<std::is_base_of_v<IInterface, IFace>, InterfaceStub<IFace>, IFace>> {};
// see https://godbolt.org/z/KPMYd1sbr
template <typename IFace>
class BoxedInterface final {
IFace const* m_ptr = nullptr;
std::aligned_storage_t<48> m_storage;
void ( *m_destruct )( void* ) = nullptr;
// static_assert( std::is_base_of_v<IAlgTool, IFace> );
public:
// in case no binding is required...
BoxedInterface( IFace const* ptr ) : m_ptr{ ptr } {}
// bind the arguments...
template <typename Ret, typename... Args, typename = std::enable_if_t<std::is_base_of_v<IFace, Ret>>>
BoxedInterface( std::in_place_type_t<Ret>, Args&&... args )
: m_ptr{ new ( &m_storage ) Ret{ std::forward<Args>( args )... } }
, m_destruct{ []( void* ptr ) { static_cast<Ret*>( ptr )->~Ret(); } } {
static_assert( sizeof( Ret ) <= sizeof( m_storage ) ); // TODO: add heap storage for large bindings...
}
~BoxedInterface() {
if ( m_destruct ) ( *m_destruct )( &m_storage );
}
BoxedInterface( const BoxedInterface& ) = delete;
BoxedInterface& operator=( const BoxedInterface& ) = delete;
BoxedInterface( BoxedInterface&& ) = delete;
BoxedInterface& operator=( BoxedInterface&& ) = delete;
operator const IFace&() const { return *m_ptr; }
// operator IFace& () && = delete;
};
template <typename IFace>
struct IBinder : extend_interfaces<IAlgTool> {
DeclareInterfaceID( IBinder<IFace>, 1, 0 );
virtual BoxedInterface<IFace> operator()( EventContext const& ) const = 0;
};
struct Stub : implements<AlgToolStub<IFace>> {};
} // namespace Gaudi::Interface
} // namespace Gaudi::Interface::Bind
......@@ -330,12 +330,10 @@ namespace Gaudi {
@author Pere Mato
*/
template <class I>
bool isValidInterface( I* i ) {
template <class IFace>
bool isValidInterface( IFace* i ) {
void* ii = nullptr;
;
StatusCode sc = i->queryInterface( I::interfaceID(), &ii );
return sc.isSuccess();
return i->queryInterface( IFace::interfaceID(), &ii ).isSuccess();
}
//#ifdef GAUDI_V20_COMPAT
......
/*****************************************************************************\
* (c) Copyright 2021 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. *
\*****************************************************************************/
#pragma once
class EventContext;
namespace Gaudi::Interface::Bind {
// see https://godbolt.org/z/KPMYd1sbr
class Box final {
unsigned long m_iid = -1;
const void* m_ptr = nullptr;
void ( *m_destruct )( void* ) = nullptr;
std::aligned_storage_t<64 - 2 * sizeof( void* ) - sizeof( long )> m_storage; // local storage for bound arguments...
public:
explicit Box() = default;
// identity binding: no actual binding is required...
template <typename IFace>
Box( std::in_place_type_t<IFace>, IFace const* ptr ) : m_iid{ IFace::interfaceID().id() }, m_ptr{ ptr } {
assert( m_ptr != nullptr );
}
// bind the arguments...
template <typename IFace, typename Ret, typename... Args,
typename = std::enable_if_t<std::is_base_of_v<IFace, Ret>>>
Box( std::in_place_type_t<IFace>, std::in_place_type_t<Ret>, Args&&... args ) : m_iid{ IFace::interfaceID().id() } {
if constexpr ( sizeof( Ret ) <= sizeof( m_storage ) ) {
m_ptr = new ( &m_storage ) Ret{ std::forward<Args>( args )... };
m_destruct = []( void* ptr ) { static_cast<Ret*>( ptr )->~Ret(); };
} else {
m_ptr = new Ret{ std::forward<Args>( args )... };
m_destruct = []( void* ptr ) { delete static_cast<Ret*>( ptr ); };
}
}
template <typename IFace, typename Bound, typename = std::enable_if_t<std::is_base_of_v<IFace, Bound>>>
Box( std::in_place_type_t<IFace>, Bound&& bound ) {
if constexpr ( sizeof( Bound ) <= sizeof( m_storage ) ) {
m_ptr = new ( &m_storage ) Bound{ std::forward<Bound>( bound ) };
m_destruct = []( void* ptr ) { static_cast<Bound*>( ptr )->~Bound(); };
} else {
m_ptr = new Bound{ std::forward<Bound>( bound ) };
m_destruct = []( void* ptr ) { delete static_cast<Bound*>( ptr ); };
}
}
~Box() {
if ( m_destruct ) ( *m_destruct )( &m_storage );
}
Box( const Box& ) = delete;
Box& operator=( const Box& ) = delete;
Box( Box&& ) = delete;
Box& operator=( Box&& ) = delete;
template <typename IFace>
const IFace* get() const {
return IFace::interfaceID().id() == m_iid ? static_cast<const IFace*>( m_ptr ) : nullptr;
}
template <typename IFace>
IFace* get() && = delete;
};
} // namespace Gaudi::Interface::Bind
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment