Commit 3413cfce authored by Gerhard Raven's avatar Gerhard Raven
Browse files

Add support for EventContext as input to Gaudi::Functional algorithms

- one can now specify `const EventContext&` as the first (input)
  argument to a Gaudi::Functional algorithm
- the implementations will skip the `EventContext` when generating
  the input handles for the input, and when calling `operator()`,
  it will prefix the arguments with the result of
  `Gaudi::Hive::currentContext()`.
parent f98d6e2e
......@@ -15,16 +15,17 @@ namespace Gaudi
class Consumer;
template <typename... In, typename Traits_>
class Consumer<void( const In&... ), Traits_> : public details::DataHandleMixin<void, std::tuple<In...>, Traits_>
class Consumer<void( const In&... ), Traits_>
: public details::DataHandleMixin<void, details::filter_evtcontext<In...>, Traits_>
{
public:
using details::DataHandleMixin<void, std::tuple<In...>, Traits_>::DataHandleMixin;
using details::DataHandleMixin<void, details::filter_evtcontext<In...>, Traits_>::DataHandleMixin;
// derived classes are NOT allowed to implement execute ...
StatusCode execute() override final
{
try {
Gaudi::apply( [&]( const auto&... i ) { ( *this )( details::deref( i.get() )... ); }, this->m_inputs );
details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs );
} catch ( GaudiException& e ) {
( e.code() ? this->warning() : this->error() ) << e.message() << endmsg;
return e.code();
......
......@@ -26,9 +26,7 @@ namespace Gaudi
StatusCode execute() override final
{
try {
this->setFilterPassed( Gaudi::apply(
[&]( auto&... handles ) { return details::as_const( *this )( details::deref( handles.get() )... ); },
this->m_inputs ) );
this->setFilterPassed( details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs ) );
return StatusCode::SUCCESS;
} catch ( GaudiException& e ) {
( e.code() ? this->warning() : this->error() ) << e.message() << endmsg;
......
......@@ -9,9 +9,10 @@
// TODO: fwd declare instead?
#include "GaudiAlg/GaudiAlgorithm.h"
#include "GaudiKernel/Algorithm.h"
#include "GaudiKernel/AnyDataHandle.h"
#include "GaudiKernel/DataObjectHandle.h"
#include "GaudiKernel/GaudiException.h"
#include "GaudiKernel/ThreadLocalContext.h"
#include "GaudiKernel/apply.h"
#include "GaudiKernel/detected.h"
// Boost
......@@ -112,19 +113,32 @@ namespace Gaudi
template <typename T>
void as_const( T&& t ) = delete;
template <class...>
struct disjunction : std::false_type {
};
template <class B1>
struct disjunction<B1> : B1 {
};
template <class B1, class... Bn>
struct disjunction<B1, Bn...> : std::conditional_t<bool( B1::value ), B1, disjunction<Bn...>> {
};
#else
using std::as_const;
using std::disjunction;
#endif
/////////////////////////////////////////
template <typename Out1, typename Out2, typename = std::enable_if_t<std::is_constructible<Out1, Out2>::value>>
template <typename Out1, typename Out2, typename = std::enable_if_t<std::is_constructible<Out1, Out2>::value &&
std::is_base_of<DataObject, Out1>::value>>
Out1* put( DataObjectHandle<Out1>& out_handle, Out2&& out )
{
return out_handle.put( std::make_unique<Out1>( std::forward<Out2>( out ) ) );
}
template <typename Out1, typename Out2, typename = std::enable_if_t<std::is_constructible<Out1, Out2>::value>>
void put( AnyDataHandle<Out1>& out_handle, Out2&& out )
void put( DataObjectHandle<AnyDataWrapper<Out1>>& out_handle, Out2&& out )
{
out_handle.put( std::forward<Out2>( out ) );
}
......@@ -352,6 +366,43 @@ namespace Gaudi
}
///////////////////////
// given a pack, return a corresponding tuple
template <typename... In>
struct filter_evtcontext_t {
using type = std::tuple<In...>;
static_assert( !details::disjunction<std::is_same<EventContext, In>...>::value,
"EventContext can only appear as first argument" );
template <typename Algorithm, typename Handles>
static auto apply( const Algorithm& algo, Handles& handles )
{
return Gaudi::apply( [&]( const auto&... handle ) { return algo( details::deref( handle.get() )... ); },
handles );
}
};
// except when it starts with EventContext, then drop it
template <typename... In>
struct filter_evtcontext_t<EventContext, In...> {
using type = std::tuple<In...>;
static_assert( !details::disjunction<std::is_same<EventContext, In>...>::value,
"EventContext can only appear as first argument" );
template <typename Algorithm, typename Handles>
static auto apply( const Algorithm& algo, Handles& handles )
{
return Gaudi::apply(
[&]( const auto&... handle ) {
return algo( Gaudi::Hive::currentContext(), details::deref( handle.get() )... );
},
handles );
}
};
template <typename... In>
using filter_evtcontext = typename filter_evtcontext_t<In...>::type;
template <typename OutputSpec, typename InputSpec, typename Traits_>
class DataHandleMixin;
......@@ -424,6 +475,23 @@ namespace Gaudi
std::tuple<details::OutputHandle_t<Traits_, Out>...> m_outputs;
};
template <typename Traits_>
class DataHandleMixin<void, std::tuple<>, Traits_> : public BaseClass_t<Traits_>
{
static_assert( std::is_base_of<Algorithm, BaseClass_t<Traits_>>::value,
"BaseClass must inherit from Algorithm" );
public:
DataHandleMixin( const std::string& name, ISvcLocator* pSvcLocator ) : BaseClass_t<Traits_>( name, pSvcLocator )
{
// make sure this algorithm is seen as reentrant by Gaudi
this->setProperty( "Cardinality", 0 );
}
protected:
std::tuple<> m_inputs;
};
template <typename... In, typename Traits_>
class DataHandleMixin<void, std::tuple<In...>, Traits_> : public BaseClass_t<Traits_>
{
......
......@@ -8,7 +8,6 @@
// TODO: fwd declare instead?
#include "GaudiAlg/GaudiAlgorithm.h"
#include "GaudiAlg/GaudiHistoAlg.h"
#include "GaudiKernel/AnyDataHandle.h"
#include "GaudiKernel/DataObjectHandle.h"
#include "GaudiKernel/SerializeSTL.h"
......@@ -92,9 +91,6 @@ namespace Gaudi
// this uses the defaults -- and it itself is the default ;-)
using useDefaults = use_<>;
// example: use AnyDataHandle as input and output, and the default BaseClass
using useAnyDataHandle = use_<InputHandle_t<AnyDataHandle>, OutputHandle_t<AnyDataHandle>>;
// this example uses GaudiHistoAlg as baseclass, and the default handle types for
// input and output
using useGaudiHistoAlg = use_<BaseClass_t<GaudiHistoAlg>>;
......
......@@ -54,8 +54,7 @@ namespace Gaudi
try {
// TODO:FIXME: how does operator() know the number and order of expected outputs?
using details::as_const;
auto out = Gaudi::apply(
[&]( auto&... ihandle ) { return as_const( *this )( as_const( *ihandle.get() )... ); }, this->m_inputs );
auto out = details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs );
if ( out.size() != m_outputs.size() ) {
throw GaudiException( "Error during transform: expected " + std::to_string( m_outputs.size() ) +
" containers, got " + std::to_string( out.size() ) + " instead",
......
......@@ -34,12 +34,8 @@ namespace Gaudi
StatusCode execute() override final
{
try {
Gaudi::apply(
[&]( const auto&... i ) {
details::put( std::get<0>( this->m_outputs ),
details::as_const( *this )( details::deref( i.get() )... ) );
},
this->m_inputs );
details::put( std::get<0>( this->m_outputs ),
details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs ) );
return StatusCode::SUCCESS;
} catch ( GaudiException& e ) {
( e.code() ? this->warning() : this->error() ) << e.message() << endmsg;
......@@ -86,11 +82,7 @@ namespace Gaudi
( details::put( ohandle, std::forward<decltype( data )>( data ) ), ... );
#endif
},
Gaudi::apply(
[this]( auto&... ihandle ) {
return details::as_const( *this )( details::deref( ihandle.get() )... );
},
this->m_inputs ) );
details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs ) );
#if defined( __clang__ ) && ( __clang_major__ < 6 )
#pragma clang diagnostic pop
......@@ -138,11 +130,7 @@ namespace Gaudi
( details::put( ohandle, std::forward<decltype( data )>( data ) ), ... );
#endif
},
Gaudi::apply(
[&]( auto&... ihandle ) {
return details::as_const( *this )( details::deref( ihandle.get() )... );
},
this->m_inputs ) );
details::filter_evtcontext_t<In...>::apply( *this, this->m_inputs ) );
},
this->m_outputs );
return StatusCode::SUCCESS;
......
......@@ -8,6 +8,8 @@ from Configurables import Gaudi__Examples__FloatDataConsumer as FloatDataConsume
from Configurables import Gaudi__Examples__IntDataConsumer as IntDataConsumer
from Configurables import Gaudi__Examples__IntToFloatData as IntToFloatData
from Configurables import Gaudi__Examples__IntIntToFloatFloatData as IntIntToFloatFloatData
from Configurables import Gaudi__Examples__ContextConsumer as ContextConsumer
from Configurables import Gaudi__Examples__ContextIntConsumer as ContextIntConsumer
# Application setup
app = ApplicationMgr()
......@@ -17,7 +19,11 @@ OtherIntDataProducer.OutputLocation = "/Event/MyOtherInt"
app.TopAlg = [IntDataProducer("IntDataProducer"), OtherIntDataProducer,
IntDataConsumer("IntDataConsumer"), IntToFloatData(
"IntToFloatData"),
IntIntToFloatFloatData("IntIntToFloatFloatData"), FloatDataConsumer("FloatDataConsumer")]
IntIntToFloatFloatData("IntIntToFloatFloatData"), FloatDataConsumer(
"FloatDataConsumer"),
ContextConsumer(),
ContextIntConsumer()
]
# - Events
app.EvtMax = 2
app.EvtSel = "NONE"
......
......@@ -98,5 +98,32 @@ namespace Gaudi
};
DECLARE_COMPONENT( FloatDataConsumer )
struct ContextConsumer final : Gaudi::Functional::Consumer<void( const EventContext& )> {
using Gaudi::Functional::Consumer<void( const EventContext& )>::Consumer;
void operator()( const EventContext& ctx ) const override
{
info() << "executing ContextConsumer, got " << ctx << endmsg;
}
};
DECLARE_COMPONENT( ContextConsumer )
struct ContextIntConsumer final : Gaudi::Functional::Consumer<void( const EventContext&, const int& )> {
ContextIntConsumer( const std::string& name, ISvcLocator* svcLoc )
: Consumer( name, svcLoc, KeyValue( "InputLocation", "/Event/MyInt" ) )
{
}
void operator()( const EventContext& ctx, const int& i ) const override
{
info() << "executing ContextIntConsumer, got context = " << ctx << ", int = " << i << endmsg;
}
};
DECLARE_COMPONENT( ContextIntConsumer )
}
}
......@@ -20,6 +20,8 @@ IntIntToFloatFl... INFO Number of inputs : 2, number of outputs : 2
IntIntToFloatFl... INFO Converting 7 from /Event/MyInt and 7 from /Event/MyOtherInt
IntIntToFloatFl... INFO Storing results into /Event/MyMultiFloat1 and /Event/MyMultiFloat2
FloatDataConsumer INFO executing FloatDataConsumer: 7
Gaudi::Examples... INFO executing ContextConsumer, got INVALID
Gaudi::Examples... INFO executing ContextIntConsumer, got context = INVALID, int = 7
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
......@@ -28,6 +30,8 @@ IntIntToFloatFl... INFO Number of inputs : 2, number of outputs : 2
IntIntToFloatFl... INFO Converting 7 from /Event/MyInt and 7 from /Event/MyOtherInt
IntIntToFloatFl... INFO Storing results into /Event/MyMultiFloat1 and /Event/MyMultiFloat2
FloatDataConsumer INFO executing FloatDataConsumer: 7
Gaudi::Examples... INFO executing ContextConsumer, got INVALID
Gaudi::Examples... INFO executing ContextIntConsumer, got context = INVALID, int = 7
ApplicationMgr INFO Application Manager Stopped successfully
EventLoopMgr INFO Histograms converted successfully according to request.
ApplicationMgr INFO Application Manager Finalized successfully
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment