Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-09-16 08:55:24

0001 /***********************************************************************************\
0002 * (c) Copyright 1998-2025 CERN for the benefit of the LHCb and ATLAS collaborations *
0003 *                                                                                   *
0004 * This software is distributed under the terms of the Apache version 2 licence,     *
0005 * copied verbatim in the file "LICENSE".                                            *
0006 *                                                                                   *
0007 * In applying this licence, CERN does not waive the privileges and immunities       *
0008 * granted to it by virtue of its status as an Intergovernmental Organization        *
0009 * or submit itself to any jurisdiction.                                             *
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     ////// Many of the same -> 1 or 0
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> ) { // handle constructor does not (yet) allow to set
0068                                                                // optional flag... so do it
0069                                                                // explicitly here...
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> ) { // handle constructor does not (yet) allow to set
0085                                                                // optional flag... so do it
0086                                                                // explicitly here...
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       // accessor to input Locations
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       // derived classes can NOT implement execute
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       // if In is a pointer, it signals optional (as opposed to mandatory) input
0121       template <typename T>
0122       using InputHandle_t = InputHandle_t<Traits_, std::remove_pointer_t<T>>;
0123       std::vector<InputHandle_t<In>>          m_inputs;         //   and make the handles properties instead...
0124       Gaudi::Property<std::vector<DataObjID>> m_inputLocations; // TODO/FIXME: remove this duplication...
0125       // TODO/FIXME: replace vector of DataObjID property + call-back with a
0126       //             vector<handle> property ... as soon as declareProperty can deal with that.
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> ) { // handle constructor does not (yet) allow to
0151                                                                          // set
0152                                                                          // optional flag... so do it
0153                                                                          // explicitly here...
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       // accessor to input Locations
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       // derived classes can NOT implement execute
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       // if In is a pointer, it signals optional (as opposed to mandatory) input
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; //   and make the handles properties instead...
0225       std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations; // TODO/FIXME: remove
0226                                                                                               // this duplication...
0227       // TODO/FIXME: replace vector of string property + call-back with a
0228       //             vector<handle> property ... as soon as declareProperty can deal with that.
0229     };
0230 
0231   } // namespace details
0232 
0233   template <typename Signature, typename Traits_ = Traits::useDefaults>
0234   using MergingTransformer = details::MergingTransformer<Signature, Traits_, details::isLegacy<Traits_>>;
0235 
0236   // more meaningful alias for cases where the return type in Signature is void
0237   template <details::is_void_fun Signature, typename Traits_ = Traits::useDefaults>
0238   using MergingConsumer = details::MergingTransformer<Signature, Traits_, details::isLegacy<Traits_>>;
0239 
0240   // M vectors of the same -> N
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> ) { // handle constructor does not (yet) allow to set
0271                                                // optional flag... so do it
0272                                                // explicitly here...
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     // accessor to input Locations
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     // derived classes can NOT implement execute
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     // if In is a pointer, it signals optional (as opposed to mandatory) input
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; //   and make the handles properties instead...
0332     std::array<Gaudi::Property<std::vector<DataObjID>>, sizeof...( Ins )> m_inputLocations; // TODO/FIXME: remove this
0333                                                                                             // duplication...
0334     // TODO/FIXME: replace vector of string property + call-back with a
0335     //             vector<handle> property ... as soon as declareProperty can deal with that.
0336   };
0337 
0338   // Many of the same -> N with filter functionality
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     // accessor to input Locations
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     // derived classes can NOT implement execute
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     // if In is a pointer, it signals optional (as opposed to mandatory) input
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;         //   and make the handles properties instead...
0395     Gaudi::Property<std::vector<DataObjID>> m_inputLocations; // TODO/FIXME: remove this duplication...
0396     // TODO/FIXME: replace vector of string property + call-back with a
0397     //             vector<handle> property ... as soon as declareProperty can deal with that.
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> ) { // handle constructor does not (yet) allow to set
0412                                              // optional flag... so do it
0413                                              // explicitly here...
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 } // namespace Gaudi::Functional