The Gaudi Framework  master (82fdf313)
Loading...
Searching...
No Matches
MergingTransformer.h
Go to the documentation of this file.
1/***********************************************************************************\
2* (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
3* *
4* This software is distributed under the terms of the Apache version 2 licence, *
5* copied verbatim in the file "LICENSE". *
6* *
7* In applying this licence, CERN does not waive the privileges and immunities *
8* granted to it by virtue of its status as an Intergovernmental Organization *
9* or submit itself to any jurisdiction. *
10\***********************************************************************************/
11#pragma once
12
13#include "details.h"
14#include "utilities.h"
15#include <Gaudi/Algorithm.h>
17#include <functional>
18#include <string>
19#include <vector>
20
21namespace Gaudi::Functional {
22
24
25 namespace details {
26 template <typename F, size_t... Is>
27 auto for_impl( F&& f, std::index_sequence<Is...> ) {
28 if constexpr ( std::disjunction_v<std::is_void<std::invoke_result_t<F, std::integral_constant<int, Is>>>...> ) {
29 ( std::invoke( f, std::integral_constant<int, Is>{} ), ... );
30 } else {
31 return std::array{ std::invoke( f, std::integral_constant<int, Is>{} )... };
32 }
33 }
34
35 template <auto N, typename F>
36 decltype( auto ) for_( F&& f ) {
37 return for_impl( std::forward<F>( f ), std::make_index_sequence<N>{} );
38 }
39
40 template <typename Sig>
41 constexpr bool is_void_fun_v = false;
42 template <typename... Args>
43 constexpr bool is_void_fun_v<void( Args... )> = true;
44 template <typename Sig>
46
47 template <typename Signature, typename Traits_, bool isLegacy>
49
51 template <typename Out, typename In, typename Traits_>
52 struct MergingTransformer<Out( const vector_of_const_<In>& ), Traits_, true>
53 : DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_> {
54 private:
55 using base_class = DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_>;
56
57 public:
58 using KeyValue = typename base_class::KeyValue;
59 using KeyValues = typename base_class::KeyValues;
60
61 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs )
62 : base_class( std::move( name ), locator )
63 , m_inputLocations{ this, inputs.first, details::to_DataObjID( inputs.second ),
64 [this]( Gaudi::Details::PropertyBase& ) {
65 this->m_inputs =
66 make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
67 if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
68 // optional flag... so do it
69 // explicitly here...
70 std::for_each( this->m_inputs.begin(), this->m_inputs.end(),
71 []( auto& h ) { h.setOptional( true ); } );
72 }
73 },
75 static_assert( std::is_void_v<Out> );
76 }
77
78 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs, const KeyValue& output )
79 : base_class( std::move( name ), locator, output )
80 , m_inputLocations{ this, inputs.first, details::to_DataObjID( inputs.second ),
81 [this]( Gaudi::Details::PropertyBase& ) {
82 this->m_inputs =
83 make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
84 if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
85 // optional flag... so do it
86 // explicitly here...
87 std::for_each( this->m_inputs.begin(), this->m_inputs.end(),
88 []( auto& h ) { h.setOptional( true ); } );
89 }
90 },
92 static_assert( !std::is_void_v<Out> );
93 }
94
95 // accessor to input Locations
96 const std::string& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n].key(); }
97 unsigned int inputLocationSize() const { return m_inputLocations.value().size(); }
98
99 // derived classes can NOT implement execute
100 StatusCode execute() override final {
102 ins.reserve( m_inputs.size() );
103 std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ), details2::get_from_handle<In>{} );
104 try {
105 if constexpr ( std::is_void_v<Out> ) {
106 std::as_const ( *this )( std::as_const( ins ) );
107 } else {
108 put( std::get<0>( this->m_outputs ), std::as_const( *this )( std::as_const( ins ) ) );
109 }
111 } catch ( GaudiException& e ) {
112 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
113 return e.code();
114 }
115 }
116
117 virtual Out operator()( const vector_of_const_<In>& inputs ) const = 0;
118
119 private:
120 // if In is a pointer, it signals optional (as opposed to mandatory) input
121 template <typename T>
123 std::vector<InputHandle_t<In>> m_inputs; // and make the handles properties instead...
124 Gaudi::Property<std::vector<DataObjID>> m_inputLocations; // TODO/FIXME: remove this duplication...
125 // TODO/FIXME: replace vector of DataObjID property + call-back with a
126 // vector<handle> property ... as soon as declareProperty can deal with that.
127 };
128
129 template <typename Out, typename... Ins, typename Traits_>
130 struct MergingTransformer<Out( const vector_of_const_<Ins>&... ), Traits_, false>
131 : DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_> {
132
133 using base_class = DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_>;
134 using KeyValue = typename base_class::KeyValue;
135 using KeyValues = typename base_class::KeyValues;
136 using InKeys = details::RepeatValues_<KeyValues, sizeof...( Ins )>;
137
138 private:
140 return details::for_<sizeof...( Ins )>( [&]( auto I ) {
141 constexpr auto i = decltype( I )::value;
142 auto& ins = std::get<i>( inputs );
144 this, ins.first, details::to_DataObjID( ins.second ),
145 [this]( auto&& ) {
146 auto& handles = std::get<i>( this->m_inputs );
147 auto& ins = std::get<i>( this->m_inputLocations );
148 using Handles = typename std::decay_t<decltype( handles )>;
149 handles = make_vector_of_handles<Handles>( this, ins );
150 if ( std::is_pointer_v<typename Handles::value_type> ) { // handle constructor does not (yet) allow to
151 // set
152 // optional flag... so do it
153 // explicitly here...
154 std::for_each( handles.begin(), handles.end(), []( auto& h ) { h.setOptional( true ); } );
155 }
156 },
158 } );
159 }
160
161 public:
162 MergingTransformer( std::string name, ISvcLocator* locator, InKeys inputs )
163 : base_class( std::move( name ), locator ), m_inputLocations{ construct_properties( inputs ) } {
164 static_assert( std::is_void_v<Out> );
165 }
166
167 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs )
168 : MergingTransformer{ std::move( name ), locator, InKeys{ inputs } } {
169 static_assert( sizeof...( Ins ) == 1 );
170 }
171
172 MergingTransformer( std::string name, ISvcLocator* locator, InKeys inputs, const KeyValue& output )
173 : base_class( std::move( name ), locator, output ), m_inputLocations{ construct_properties( inputs ) } {
174 static_assert( !std::is_void_v<Out> );
175 }
176
177 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs, const KeyValue& output )
178 : MergingTransformer{ std::move( name ), locator, InKeys{ inputs }, output } {
179 static_assert( sizeof...( Ins ) == 1 );
180 }
181
182 // accessor to input Locations
183 const std::string& inputLocation( unsigned int i, unsigned int j ) const {
184 return m_inputLocations.at( i ).value().at( j ).key();
185 }
186 const std::string& inputLocation( unsigned int i ) const {
187 static_assert( sizeof...( Ins ) == 1 );
188 return inputLocation( 0, i );
189 }
190 unsigned int inputLocationSize( int i = 0 ) const { return m_inputLocations.at( i ).value().size(); }
191
192 // derived classes can NOT implement execute
193 StatusCode execute( const EventContext& ) const override final {
194 std::tuple<vector_of_const_<Ins>...> inss;
195 details::for_<sizeof...( Ins )>( [&]( auto I ) {
196 constexpr size_t i = decltype( I )::value;
197 auto& ins = std::get<i>( inss );
198 auto& handles = std::get<i>( m_inputs );
199 ins.reserve( handles.size() );
200 std::transform( handles.begin(), handles.end(), std::back_inserter( ins ),
201 details::details2::get_from_handle<typename std::decay_t<decltype( ins )>::value_type>{} );
202 } );
203 try {
204 if constexpr ( std::is_void_v<Out> ) {
205 std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); }, inss );
206 } else {
207 put( std::get<0>( this->m_outputs ),
208 std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); },
209 inss ) );
210 }
212 } catch ( GaudiException& e ) {
213 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
214 return e.code();
215 }
216 }
217
218 virtual Out operator()( const vector_of_const_<Ins>&... inputs ) const = 0;
219
220 private:
221 // if In is a pointer, it signals optional (as opposed to mandatory) input
222 template <typename T>
224 std::tuple<std::vector<InputHandle_t<Ins>>...> m_inputs; // and make the handles properties instead...
225 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations; // TODO/FIXME: remove
226 // this duplication...
227 // TODO/FIXME: replace vector of string property + call-back with a
228 // vector<handle> property ... as soon as declareProperty can deal with that.
229 };
230
231 } // namespace details
232
233 template <typename Signature, typename Traits_ = Traits::useDefaults>
235
236 // more meaningful alias for cases where the return type in Signature is void
237 template <details::is_void_fun Signature, typename Traits_ = Traits::useDefaults>
239
240 // M vectors of the same -> N
241 template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
243
244 template <typename... Outs, typename... Ins, typename Traits_>
245 struct MergingMultiTransformer<std::tuple<Outs...>( vector_of_const_<Ins> const&... ), Traits_>
246 : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
247
248 private:
249 using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
250
251 public:
252 using KeyValue = typename base_class::KeyValue;
253 using KeyValues = typename base_class::KeyValues;
254 using InKeys = details::RepeatValues_<KeyValues, sizeof...( Ins )>;
255 using OutKeys = details::RepeatValues_<KeyValue, sizeof...( Outs )>;
256 static constexpr size_t n_args = sizeof...( Ins );
257
258 MergingMultiTransformer( std::string const& name, ISvcLocator* pSvcLocator, InKeys inputs, OutKeys outputs )
259 : base_class{ name, pSvcLocator, std::move( outputs ) }
260 , m_inputLocations{ details::for_<n_args>( [&]( auto I ) {
261 constexpr auto i = decltype( I )::value;
262 auto& ins = std::get<i>( inputs );
264 this, ins.first, details::to_DataObjID( ins.second ),
265 [this]( auto&& ) {
266 auto& handles = std::get<i>( this->m_inputs );
267 auto& ins = std::get<i>( this->m_inputLocations );
268 using In = typename std::decay_t<decltype( handles )>::value_type;
269 handles = details::make_vector_of_handles<std::decay_t<decltype( handles )>>( this, ins );
270 if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
271 // optional flag... so do it
272 // explicitly here...
273 std::for_each( handles.begin(), handles.end(), []( auto& h ) { h.setOptional( true ); } );
274 }
275 },
277 } ) } {}
278
279 MergingMultiTransformer( std::string const& name, ISvcLocator* pSvcLocator, KeyValues inputs, OutKeys outputs )
280 : MergingMultiTransformer{ name, pSvcLocator, InKeys{ std::move( inputs ) }, std::move( outputs ) } {
281 static_assert( sizeof...( Ins ) == 1 );
282 }
283
284 // accessor to input Locations
285 std::string const& inputLocation( unsigned int i, unsigned int j ) const {
286 return m_inputLocations.at( i ).value().at( j ).key();
287 }
288 std::string const& inputLocation( unsigned int j ) const {
289 static_assert( n_args == 1 );
290 return inputLocation( 0, j );
291 }
292 unsigned int inputLocationSize( int i = 0 ) const { return m_inputLocations.at( i ).value().size(); }
293
294 // derived classes can NOT implement execute
295 StatusCode execute( EventContext const& ) const override final {
296 std::tuple<vector_of_const_<Ins>...> inss;
297 details::for_<sizeof...( Ins )>( [&]( auto I ) {
298 constexpr size_t i = decltype( I )::value;
299 auto& ins = std::get<i>( inss );
300 auto& handles = std::get<i>( m_inputs );
301 ins.reserve( handles.size() );
302 std::transform( handles.begin(), handles.end(), std::back_inserter( ins ),
303 details::details2::get_from_handle<typename std::decay_t<decltype( ins )>::value_type>{} );
304 } );
305 try {
306 std::apply(
307 [&]( auto&... outhandle ) {
308 std::apply(
309 [&outhandle...]( auto&&... data ) {
310 ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
311 },
312 std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); },
313 inss ) );
314 },
315 this->m_outputs );
317 } catch ( GaudiException& e ) {
318 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
319 return e.code();
320 }
321 }
322
323 virtual std::tuple<Outs...> operator()( const vector_of_const_<Ins>&... inputs ) const = 0;
324
325 private:
326 // if In is a pointer, it signals optional (as opposed to mandatory) input
327 template <typename T>
329 std::tuple<std::vector<InputHandle_t<Ins>>...> m_inputs; // and make the handles properties instead...
330 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations; // TODO/FIXME: remove this
331 // duplication...
332 // TODO/FIXME: replace vector of string property + call-back with a
333 // vector<handle> property ... as soon as declareProperty can deal with that.
334 };
335
336 // Many of the same -> N with filter functionality
337 template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
339
340 template <typename... Outs, typename In, typename Traits_>
341 struct MergingMultiTransformerFilter<std::tuple<Outs...>( vector_of_const_<In> const& ), Traits_>
342 : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
343
344 private:
345 using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
346
347 public:
348 using KeyValue = typename base_class::KeyValue;
349 using KeyValues = typename base_class::KeyValues;
350 using OutKeys = details::RepeatValues_<KeyValue, sizeof...( Outs )>;
351
352 MergingMultiTransformerFilter( std::string const& name, ISvcLocator* locator, KeyValues const& inputs,
353 OutKeys const& outputs );
354
355 // accessor to input Locations
356 std::string const& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n].key(); }
357 unsigned int inputLocationSize() const { return m_inputLocations.value().size(); }
358
359 // derived classes can NOT implement execute
360 StatusCode execute( EventContext const& ) const override final {
362 ins.reserve( m_inputs.size() );
363 std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ),
365 try {
366 return std::apply(
367 [&]( auto&... outhandle ) {
368 return std::apply(
369 [&outhandle...]( bool passed, auto&&... data ) {
370 ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
371 return passed;
372 },
373 ( *this )( std::as_const( ins ) ) );
374 },
375 this->m_outputs )
378 } catch ( GaudiException& e ) {
379 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
380 return e.code();
381 }
382 }
383
384 virtual std::tuple<bool, Outs...> operator()( const vector_of_const_<In>& inputs ) const = 0;
385
386 private:
387 // if In is a pointer, it signals optional (as opposed to mandatory) input
388 template <typename T>
390 std::vector<InputHandle_t<In>> m_inputs; // and make the handles properties instead...
391 Gaudi::Property<std::vector<DataObjID>> m_inputLocations; // TODO/FIXME: remove this duplication...
392 // TODO/FIXME: replace vector of string property + call-back with a
393 // vector<handle> property ... as soon as declareProperty can deal with that.
394 };
395
396 template <typename... Outs, typename In, typename Traits_>
397 MergingMultiTransformerFilter<std::tuple<Outs...>( const vector_of_const_<In>& ),
398 Traits_>::MergingMultiTransformerFilter( std::string const& name,
399 ISvcLocator* pSvcLocator,
400 KeyValues const& inputs,
401 OutKeys const& outputs )
402 : base_class( name, pSvcLocator, outputs )
403 , m_inputLocations{
404 this, inputs.first, details::to_DataObjID( inputs.second ),
406 this->m_inputs = details::make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
407 if ( std::is_pointer_v<In> ) { // handle constructor does not (yet) allow to set
408 // optional flag... so do it
409 // explicitly here...
410 std::for_each( this->m_inputs.begin(), this->m_inputs.end(), []( auto& h ) { h.setOptional( true ); } );
411 }
412 },
414
415} // namespace Gaudi::Functional
MsgStream & endmsg(MsgStream &s)
MsgStream Modifier: endmsg. Calls the output method of the MsgStream.
Definition MsgStream.h:198
This class represents an entry point to all the event specific data.
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
Implementation of property with value of concrete type.
Definition PropertyFwd.h:27
Define general base for Gaudi exception.
virtual const std::string & message() const
error message to be printed
virtual const StatusCode & code() const
StatusCode for Exception.
virtual const std::string & tag() const
name tag for the exception, or exception type
The ISvcLocator is the interface implemented by the Service Factory in the Application Manager to loc...
Definition ISvcLocator.h:42
PropertyBase base class allowing PropertyBase* collections to be "homogeneous".
This class is used for returning status codes from appropriate routines.
Definition StatusCode.h:64
bool isFailure() const
Definition StatusCode.h:129
Gaudi::tagged_bool< class ImmediatelyInvokeHandler_tag > ImmediatelyInvokeHandler
Definition Property.h:23
std::vector< DataObjID > to_DataObjID(const std::vector< std::string > &in)
Definition details.h:106
decltype(auto) for_(F &&f)
typename detail2::InputHandle< T, Tr, detail2::DefaultInputHandle >::type InputHandle_t
Definition details.h:458
auto put(const DataObjectHandle< Out1 > &out_handle, Out2 &&out)
Definition details.h:162
Handles make_vector_of_handles(IDataHandleHolder *owner, const std::vector< DataObjID > &init)
Definition details.h:467
decltype(get_values_helper< Value >(std::make_index_sequence< N >())) RepeatValues_
Definition details.h:158
auto for_impl(F &&f, std::index_sequence< Is... >)
details::MergingTransformer< Signature, Traits_, details::isLegacy< Traits_ > > MergingTransformer
details::MergingTransformer< Signature, Traits_, details::isLegacy< Traits_ > > MergingConsumer
This file provides a Grammar for the type Gaudi::Accumulators::Axis It allows to use that type from p...
Definition __init__.py:1
STL namespace.
virtual std::tuple< bool, Outs... > operator()(const vector_of_const_< In > &inputs) const =0
MergingMultiTransformerFilter(std::string const &name, ISvcLocator *locator, KeyValues const &inputs, OutKeys const &outputs)
MergingMultiTransformer(std::string const &name, ISvcLocator *pSvcLocator, KeyValues inputs, OutKeys outputs)
virtual std::tuple< Outs... > operator()(const vector_of_const_< Ins > &... inputs) const =0
MergingMultiTransformer(std::string const &name, ISvcLocator *pSvcLocator, InKeys inputs, OutKeys outputs)
std::array< Gaudi::Property< std::vector< DataObjID > >, sizeof...(Ins)> m_inputLocations
MergingTransformer(std::string name, ISvcLocator *locator, InKeys inputs, const KeyValue &output)
MergingTransformer(std::string name, ISvcLocator *locator, const KeyValues &inputs, const KeyValue &output)
MergingTransformer(std::string name, ISvcLocator *locator, const KeyValues &inputs, const KeyValue &output)