File indexing completed on 2025-09-16 08:55:24
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #pragma once
0012
0013 #include "details.h"
0014 #include "utilities.h"
0015 #include <Gaudi/Algorithm.h>
0016 #include <GaudiKernel/FunctionalFilterDecision.h>
0017 #include <functional>
0018 #include <string>
0019 #include <vector>
0020
0021 namespace Gaudi::Functional {
0022
0023 using details::vector_of_const_;
0024
0025 namespace details {
0026 template <typename F, size_t... Is>
0027 auto for_impl( F&& f, std::index_sequence<Is...> ) {
0028 if constexpr ( std::disjunction_v<std::is_void<std::invoke_result_t<F, std::integral_constant<int, Is>>>...> ) {
0029 ( std::invoke( f, std::integral_constant<int, Is>{} ), ... );
0030 } else {
0031 return std::array{ std::invoke( f, std::integral_constant<int, Is>{} )... };
0032 }
0033 }
0034
0035 template <auto N, typename F>
0036 decltype( auto ) for_( F&& f ) {
0037 return for_impl( std::forward<F>( f ), std::make_index_sequence<N>{} );
0038 }
0039
0040 template <typename Sig>
0041 constexpr bool is_void_fun_v = false;
0042 template <typename... Args>
0043 constexpr bool is_void_fun_v<void( Args... )> = true;
0044 template <typename Sig>
0045 concept is_void_fun = is_void_fun_v<Sig>;
0046
0047 template <typename Signature, typename Traits_, bool isLegacy>
0048 struct MergingTransformer;
0049
0050
0051 template <typename Out, typename In, typename Traits_>
0052 struct MergingTransformer<Out( const vector_of_const_<In>& ), Traits_, true>
0053 : DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_> {
0054 private:
0055 using base_class = DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_>;
0056
0057 public:
0058 using KeyValue = typename base_class::KeyValue;
0059 using KeyValues = typename base_class::KeyValues;
0060
0061 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs )
0062 : base_class( std::move( name ), locator )
0063 , m_inputLocations{ this, inputs.first, details::to_DataObjID( inputs.second ),
0064 [this]( Gaudi::Details::PropertyBase& ) {
0065 this->m_inputs =
0066 make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
0067 if ( std::is_pointer_v<In> ) {
0068
0069
0070 std::for_each( this->m_inputs.begin(), this->m_inputs.end(),
0071 []( auto& h ) { h.setOptional( true ); } );
0072 }
0073 },
0074 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } } {
0075 static_assert( std::is_void_v<Out> );
0076 }
0077
0078 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs, const KeyValue& output )
0079 : base_class( std::move( name ), locator, output )
0080 , m_inputLocations{ this, inputs.first, details::to_DataObjID( inputs.second ),
0081 [this]( Gaudi::Details::PropertyBase& ) {
0082 this->m_inputs =
0083 make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
0084 if ( std::is_pointer_v<In> ) {
0085
0086
0087 std::for_each( this->m_inputs.begin(), this->m_inputs.end(),
0088 []( auto& h ) { h.setOptional( true ); } );
0089 }
0090 },
0091 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } } {
0092 static_assert( !std::is_void_v<Out> );
0093 }
0094
0095
0096 const std::string& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n].key(); }
0097 unsigned int inputLocationSize() const { return m_inputLocations.value().size(); }
0098
0099
0100 StatusCode execute() override final {
0101 vector_of_const_<In> ins;
0102 ins.reserve( m_inputs.size() );
0103 std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ), details2::get_from_handle<In>{} );
0104 try {
0105 if constexpr ( std::is_void_v<Out> ) {
0106 std::as_const ( *this )( std::as_const( ins ) );
0107 } else {
0108 put( std::get<0>( this->m_outputs ), std::as_const( *this )( std::as_const( ins ) ) );
0109 }
0110 return FilterDecision::PASSED;
0111 } catch ( GaudiException& e ) {
0112 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0113 return e.code();
0114 }
0115 }
0116
0117 virtual Out operator()( const vector_of_const_<In>& inputs ) const = 0;
0118
0119 private:
0120
0121 template <typename T>
0122 using InputHandle_t = InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0123 std::vector<InputHandle_t<In>> m_inputs;
0124 Gaudi::Property<std::vector<DataObjID>> m_inputLocations;
0125
0126
0127 };
0128
0129 template <typename Out, typename... Ins, typename Traits_>
0130 struct MergingTransformer<Out( const vector_of_const_<Ins>&... ), Traits_, false>
0131 : DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_> {
0132
0133 using base_class = DataHandleMixin<std::tuple<Out>, std::tuple<>, Traits_>;
0134 using KeyValue = typename base_class::KeyValue;
0135 using KeyValues = typename base_class::KeyValues;
0136 using InKeys = details::RepeatValues_<KeyValues, sizeof...( Ins )>;
0137
0138 private:
0139 auto construct_properties( InKeys inputs ) {
0140 return details::for_<sizeof...( Ins )>( [&]( auto I ) {
0141 constexpr auto i = decltype( I )::value;
0142 auto& ins = std::get<i>( inputs );
0143 return Gaudi::Property<std::vector<DataObjID>>{
0144 this, ins.first, details::to_DataObjID( ins.second ),
0145 [this]( auto&& ) {
0146 auto& handles = std::get<i>( this->m_inputs );
0147 auto& ins = std::get<i>( this->m_inputLocations );
0148 using Handles = typename std::decay_t<decltype( handles )>;
0149 handles = make_vector_of_handles<Handles>( this, ins );
0150 if ( std::is_pointer_v<typename Handles::value_type> ) {
0151
0152
0153
0154 std::for_each( handles.begin(), handles.end(), []( auto& h ) { h.setOptional( true ); } );
0155 }
0156 },
0157 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } };
0158 } );
0159 }
0160
0161 public:
0162 MergingTransformer( std::string name, ISvcLocator* locator, InKeys inputs )
0163 : base_class( std::move( name ), locator ), m_inputLocations{ construct_properties( inputs ) } {
0164 static_assert( std::is_void_v<Out> );
0165 }
0166
0167 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs )
0168 : MergingTransformer{ std::move( name ), locator, InKeys{ inputs } } {
0169 static_assert( sizeof...( Ins ) == 1 );
0170 }
0171
0172 MergingTransformer( std::string name, ISvcLocator* locator, InKeys inputs, const KeyValue& output )
0173 : base_class( std::move( name ), locator, output ), m_inputLocations{ construct_properties( inputs ) } {
0174 static_assert( !std::is_void_v<Out> );
0175 }
0176
0177 MergingTransformer( std::string name, ISvcLocator* locator, const KeyValues& inputs, const KeyValue& output )
0178 : MergingTransformer{ std::move( name ), locator, InKeys{ inputs }, output } {
0179 static_assert( sizeof...( Ins ) == 1 );
0180 }
0181
0182
0183 const std::string& inputLocation( unsigned int i, unsigned int j ) const {
0184 return m_inputLocations.at( i ).value().at( j ).key();
0185 }
0186 const std::string& inputLocation( unsigned int i ) const {
0187 static_assert( sizeof...( Ins ) == 1 );
0188 return inputLocation( 0, i );
0189 }
0190 unsigned int inputLocationSize( int i = 0 ) const { return m_inputLocations.at( i ).value().size(); }
0191
0192
0193 StatusCode execute( const EventContext& ) const override final {
0194 std::tuple<vector_of_const_<Ins>...> inss;
0195 details::for_<sizeof...( Ins )>( [&]( auto I ) {
0196 constexpr size_t i = decltype( I )::value;
0197 auto& ins = std::get<i>( inss );
0198 auto& handles = std::get<i>( m_inputs );
0199 ins.reserve( handles.size() );
0200 std::transform( handles.begin(), handles.end(), std::back_inserter( ins ),
0201 details::details2::get_from_handle<typename std::decay_t<decltype( ins )>::value_type>{} );
0202 } );
0203 try {
0204 if constexpr ( std::is_void_v<Out> ) {
0205 std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); }, inss );
0206 } else {
0207 put( std::get<0>( this->m_outputs ),
0208 std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); },
0209 inss ) );
0210 }
0211 return FilterDecision::PASSED;
0212 } catch ( GaudiException& e ) {
0213 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0214 return e.code();
0215 }
0216 }
0217
0218 virtual Out operator()( const vector_of_const_<Ins>&... inputs ) const = 0;
0219
0220 private:
0221
0222 template <typename T>
0223 using InputHandle_t = InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0224 std::tuple<std::vector<InputHandle_t<Ins>>...> m_inputs;
0225 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations;
0226
0227
0228
0229 };
0230
0231 }
0232
0233 template <typename Signature, typename Traits_ = Traits::useDefaults>
0234 using MergingTransformer = details::MergingTransformer<Signature, Traits_, details::isLegacy<Traits_>>;
0235
0236
0237 template <details::is_void_fun Signature, typename Traits_ = Traits::useDefaults>
0238 using MergingConsumer = details::MergingTransformer<Signature, Traits_, details::isLegacy<Traits_>>;
0239
0240
0241 template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
0242 struct MergingMultiTransformer;
0243
0244 template <typename... Outs, typename... Ins, typename Traits_>
0245 struct MergingMultiTransformer<std::tuple<Outs...>( vector_of_const_<Ins> const&... ), Traits_>
0246 : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
0247
0248 private:
0249 using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
0250
0251 public:
0252 using KeyValue = typename base_class::KeyValue;
0253 using KeyValues = typename base_class::KeyValues;
0254 using InKeys = details::RepeatValues_<KeyValues, sizeof...( Ins )>;
0255 using OutKeys = details::RepeatValues_<KeyValue, sizeof...( Outs )>;
0256 static constexpr size_t n_args = sizeof...( Ins );
0257
0258 MergingMultiTransformer( std::string const& name, ISvcLocator* pSvcLocator, InKeys inputs, OutKeys outputs )
0259 : base_class{ name, pSvcLocator, std::move( outputs ) }
0260 , m_inputLocations{ details::for_<n_args>( [&]( auto I ) {
0261 constexpr auto i = decltype( I )::value;
0262 auto& ins = std::get<i>( inputs );
0263 return Gaudi::Property<std::vector<DataObjID>>{
0264 this, ins.first, details::to_DataObjID( ins.second ),
0265 [this]( auto&& ) {
0266 auto& handles = std::get<i>( this->m_inputs );
0267 auto& ins = std::get<i>( this->m_inputLocations );
0268 using In = typename std::decay_t<decltype( handles )>::value_type;
0269 handles = details::make_vector_of_handles<std::decay_t<decltype( handles )>>( this, ins );
0270 if ( std::is_pointer_v<In> ) {
0271
0272
0273 std::for_each( handles.begin(), handles.end(), []( auto& h ) { h.setOptional( true ); } );
0274 }
0275 },
0276 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } };
0277 } ) } {}
0278
0279 MergingMultiTransformer( std::string const& name, ISvcLocator* pSvcLocator, KeyValues inputs, OutKeys outputs )
0280 : MergingMultiTransformer{ name, pSvcLocator, InKeys{ std::move( inputs ) }, std::move( outputs ) } {
0281 static_assert( sizeof...( Ins ) == 1 );
0282 }
0283
0284
0285 std::string const& inputLocation( unsigned int i, unsigned int j ) const {
0286 return m_inputLocations.at( i ).value().at( j ).key();
0287 }
0288 std::string const& inputLocation( unsigned int j ) const {
0289 static_assert( n_args == 1 );
0290 return inputLocation( 0, j );
0291 }
0292 unsigned int inputLocationSize( int i = 0 ) const { return m_inputLocations.at( i ).value().size(); }
0293
0294
0295 StatusCode execute( EventContext const& ) const override final {
0296 std::tuple<vector_of_const_<Ins>...> inss;
0297 details::for_<sizeof...( Ins )>( [&]( auto I ) {
0298 constexpr size_t i = decltype( I )::value;
0299 auto& ins = std::get<i>( inss );
0300 auto& handles = std::get<i>( m_inputs );
0301 ins.reserve( handles.size() );
0302 std::transform( handles.begin(), handles.end(), std::back_inserter( ins ),
0303 details::details2::get_from_handle<typename std::decay_t<decltype( ins )>::value_type>{} );
0304 } );
0305 try {
0306 std::apply(
0307 [&]( auto&... outhandle ) {
0308 GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN
0309 std::apply(
0310 [&outhandle...]( auto&&... data ) {
0311 ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
0312 },
0313 std::apply( [&]( auto&&... ins ) { return std::as_const( *this )( std::as_const( ins )... ); },
0314 inss ) );
0315 GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END
0316 },
0317 this->m_outputs );
0318 return FilterDecision::PASSED;
0319 } catch ( GaudiException& e ) {
0320 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0321 return e.code();
0322 }
0323 }
0324
0325 virtual std::tuple<Outs...> operator()( const vector_of_const_<Ins>&... inputs ) const = 0;
0326
0327 private:
0328
0329 template <typename T>
0330 using InputHandle_t = details::InputHandle_t<Traits_, typename std::remove_pointer<T>::type>;
0331 std::tuple<std::vector<InputHandle_t<Ins>>...> m_inputs;
0332 std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations;
0333
0334
0335
0336 };
0337
0338
0339 template <typename Signature, typename Traits_ = Traits::BaseClass_t<Gaudi::Algorithm>>
0340 struct MergingMultiTransformerFilter;
0341
0342 template <typename... Outs, typename In, typename Traits_>
0343 struct MergingMultiTransformerFilter<std::tuple<Outs...>( vector_of_const_<In> const& ), Traits_>
0344 : details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_> {
0345
0346 private:
0347 using base_class = details::DataHandleMixin<std::tuple<Outs...>, std::tuple<>, Traits_>;
0348
0349 public:
0350 using KeyValue = typename base_class::KeyValue;
0351 using KeyValues = typename base_class::KeyValues;
0352 using OutKeys = details::RepeatValues_<KeyValue, sizeof...( Outs )>;
0353
0354 MergingMultiTransformerFilter( std::string const& name, ISvcLocator* locator, KeyValues const& inputs,
0355 OutKeys const& outputs );
0356
0357
0358 std::string const& inputLocation( unsigned int n ) const { return m_inputLocations.value()[n].key(); }
0359 unsigned int inputLocationSize() const { return m_inputLocations.value().size(); }
0360
0361
0362 StatusCode execute( EventContext const& ) const override final {
0363 vector_of_const_<In> ins;
0364 ins.reserve( m_inputs.size() );
0365 std::transform( m_inputs.begin(), m_inputs.end(), std::back_inserter( ins ),
0366 details::details2::get_from_handle<In>{} );
0367 try {
0368 return std::apply(
0369 [&]( auto&... outhandle ) {
0370 GF_SUPPRESS_SPURIOUS_CLANG_WARNING_BEGIN
0371 return std::apply(
0372 [&outhandle...]( bool passed, auto&&... data ) {
0373 ( details::put( outhandle, std::forward<decltype( data )>( data ) ), ... );
0374 return passed;
0375 },
0376 ( *this )( std::as_const( ins ) ) );
0377 GF_SUPPRESS_SPURIOUS_CLANG_WARNING_END
0378 },
0379 this->m_outputs )
0380 ? FilterDecision::PASSED
0381 : FilterDecision::FAILED;
0382 } catch ( GaudiException& e ) {
0383 if ( e.code().isFailure() ) this->error() << e.tag() << " : " << e.message() << endmsg;
0384 return e.code();
0385 }
0386 }
0387
0388 virtual std::tuple<bool, Outs...> operator()( const vector_of_const_<In>& inputs ) const = 0;
0389
0390 private:
0391
0392 template <typename T>
0393 using InputHandle_t = details::InputHandle_t<Traits_, typename std::remove_pointer<T>::type>;
0394 std::vector<InputHandle_t<In>> m_inputs;
0395 Gaudi::Property<std::vector<DataObjID>> m_inputLocations;
0396
0397
0398 };
0399
0400 template <typename... Outs, typename In, typename Traits_>
0401 MergingMultiTransformerFilter<std::tuple<Outs...>( const vector_of_const_<In>& ),
0402 Traits_>::MergingMultiTransformerFilter( std::string const& name,
0403 ISvcLocator* pSvcLocator,
0404 KeyValues const& inputs,
0405 OutKeys const& outputs )
0406 : base_class( name, pSvcLocator, outputs )
0407 , m_inputLocations{
0408 this, inputs.first, details::to_DataObjID( inputs.second ),
0409 [this]( Gaudi::Details::PropertyBase& ) {
0410 this->m_inputs = details::make_vector_of_handles<decltype( this->m_inputs )>( this, m_inputLocations );
0411 if ( std::is_pointer_v<In> ) {
0412
0413
0414 std::for_each( this->m_inputs.begin(), this->m_inputs.end(), []( auto& h ) { h.setOptional( true ); } );
0415 }
0416 },
0417 Gaudi::Details::Property::ImmediatelyInvokeHandler{ true } } {}
0418
0419 }